Tuesday, 14 July 2026

Oracle Apex - Script to Send the Table/Query Extract via email

0 comments

 Wrap the export/email logic into a procedure

CREATE OR REPLACE PROCEDURE xxsea_send_downtime_extract_email IS

    v_context   apex_exec.t_context;

    v_export    apex_data_export.t_export;

    v_mail_id   NUMBER;

BEGIN

    -- 1. Open a query context against your source table

    v_context := apex_exec.open_query_context (

                     p_location  => apex_exec.c_location_local_db,

                     p_sql_query => 'SELECT * FROM XXAL_DOWNTIME_FORM_HISTORY ORDER BY 1 DESC'

                 );


    -- 2. Export that context as CSV

    v_export := apex_data_export.export (

                    p_context   => v_context,

                    p_format    => apex_data_export.c_format_xlsx,

                    p_file_name => 'Downtime_Incident_Table_Extract'

                );


    apex_exec.close (v_context);


    -- 3. Send the email shell and capture the returned mail_id

    v_mail_id := apex_mail.send (

                     p_to   => 'aalam@abc.com',

                     p_from => 'apexadmin@abc.com',

                     p_body => 'Please find the attached downtime incident data extract.',

                     p_subj => 'Automated Downtime Incident Data Extract'

                 );


    -- 4. Attach the exported CSV using that mail_id

    apex_mail.add_attachment (

        p_mail_id    => v_mail_id,

        p_attachment => v_export.content_blob,

        p_filename   => v_export.file_name,

        p_mime_type  => v_export.mime_type

    );


    -- 5. Push the mail queue immediately (optional)

    apex_mail.push_queue;


EXCEPTION

    WHEN OTHERS THEN

        IF v_context IS NOT NULL THEN

            apex_exec.close(v_context);

        END IF;

        RAISE;

END xxsea_send_downtime_extract_email;

/


Important - set the APEX session context inside the job

APEX_DATA_EXPORT and APEX_MAIL need an APEX session/workspace context to resolve correctly. A DBMS_SCHEDULER job runs as a raw DB session with no APEX context by default, so you need to establish one inside the job action. Wrap the call like this:


CREATE OR REPLACE PROCEDURE xxsea_run_downtime_extract_job IS

    l_security_group_id NUMBER;

BEGIN

    -- point at the correct workspace before calling APEX APIs

    l_security_group_id := apex_util.find_security_group_id(p_workspace => 'SEAMAN');

    apex_util.set_security_group_id(p_security_group_id => l_security_group_id);


    -- APEX_EXEC / APEX_DATA_EXPORT require an actual session context, not just SG_ID

    apex_session.create_session (

        p_app_id   => 104,      -- any valid app ID in the SEAMAN workspace

        p_page_id  => 0,

        p_username => 'AALAM'         -- a valid APEX app/workspace user

    );

    xxsea_send_downtime_extract_email;

EXCEPTION WHEN OTHERS THEN 

           RAISE;

END xxsea_run_downtime_extract_job;

/


Create the scheduler job

BEGIN

    DBMS_SCHEDULER.CREATE_JOB (

        job_name        => 'JOB_DOWNTIME_EXTRACT_EMAIL',

        job_type        => 'PLSQL_BLOCK',

        job_action      => 'BEGIN xxsea_run_downtime_extract_job; END;',

        start_date      => SYSTIMESTAMP,

        repeat_interval => 'FREQ=DAILY; BYHOUR=7; BYMINUTE=0',  -- daily at 7:00 AM

        enabled         => TRUE,

        comments        => 'Sends daily downtime incident extract via email'

    );

END;

/


Verify the job is registered and check its run history

-- Confirm it's scheduled

SELECT job_name, enabled, state, next_run_date

FROM user_scheduler_jobs

WHERE job_name = 'JOB_DOWNTIME_EXTRACT_EMAIL';


-- Check whether it actually ran and if it errored

SELECT log_date, status, additional_info

FROM user_scheduler_job_run_details

WHERE job_name = 'JOB_DOWNTIME_EXTRACT_EMAIL'

ORDER BY log_date DESC;


Test it manually before waiting for the schedule

BEGIN

    DBMS_SCHEDULER.RUN_JOB('JOB_DOWNTIME_EXTRACT_EMAIL');

END;

/


To disable/drop it later

BEGIN

    DBMS_SCHEDULER.DISABLE('JOB_DOWNTIME_EXTRACT_EMAIL');

    -- or to remove entirely:

    -- DBMS_SCHEDULER.DROP_JOB('JOB_DOWNTIME_EXTRACT_EMAIL');

END;

/

Monday, 13 July 2026

Oracle APEX - Add a user to a group (without removing existing groups)

0 comments
CREATE OR REPLACE PROCEDURE add_user_to_apex_group (
    p_workspace_name IN VARCHAR2,   -- e.g. 'MY_WORKSPACE'
    p_user_name           IN VARCHAR2,   -- e.g. 'AALAM'
    p_group_name        IN VARCHAR2    -- e.g. 'MANAGERS'
) IS
    l_security_group_id   NUMBER;
    l_existing_groups      VARCHAR2(32767);
    l_group_table             apex_t_varchar2 := apex_t_varchar2();
BEGIN
    -- 1. Point APEX at the correct workspace (needed outside an APEX session)
    l_security_group_id := apex_util.find_security_group_id(p_workspace => p_workspace_name);
    apex_util.set_security_group_id(p_security_group_id => l_security_group_id);

    -- 2. Create the group if it doesn't already exist
    BEGIN
        IF apex_util.get_group_id(p_group_name => p_group_name) IS NULL THEN
            apex_util.create_user_group(p_group_name => p_group_name);
        END IF;
    EXCEPTION
        WHEN OTHERS THEN
            IF apex_util.get_group_id(p_group_name => p_group_name) IS NULL THEN
                apex_util.create_user_group(p_group_name => p_group_name);
            END IF;
    END;

    -- 3. Get the groups this user already belongs to (comma-space separated string)
    l_existing_groups := apex_util.get_groups_user_belongs_to(p_username => p_user_name);

    -- 4. Build the combined group list (existing + new), avoiding duplicates
    IF l_existing_groups IS NOT NULL THEN
        FOR i IN 1 .. REGEXP_COUNT(l_existing_groups, ',') + 1 LOOP
            l_group_table.EXTEND;
            l_group_table(l_group_table.COUNT) := TRIM(REGEXP_SUBSTR(l_existing_groups, '[^,]+', 1, i));
        END LOOP;
    END IF;

    -- only add the new group if it isn't already in the list
    IF NOT p_group_name MEMBER OF l_group_table THEN
        l_group_table.EXTEND;
        l_group_table(l_group_table.COUNT) := p_group_name;
    END IF;

    -- 5. Apply the full group list back to the user
    apex_util.set_group_user_grants (
        p_user_name           => p_user_name,
        p_granted_group_names => l_group_table
    );

    COMMIT;
END add_user_to_apex_group;
/

DECLARE
CURSOR C1 IS
select user_name from APEX_WORKSPACE_APEX_USERS;
BEGIN
FOR i IN C1
LOOP
    add_user_to_apex_group (
        p_workspace_name => 'SEAMAN',
        p_user_name      => i.user_name,
        p_group_name     => 'PLM'
    );
END LOOP;
END;
/

Monday, 18 May 2026

Wip Completion (intellinum/Telnet) Query to Fetch Work Order, Lot and LPN Numbers Details

0 comments

 SELECT

    we.wip_entity_name,

    wlc.organization_id,

    wlc.wip_entity_id,

    wlc.inventory_item_id,

    msik.concatenated_segments item,

    mmt.transaction_id,

    mmt.transaction_quantity,

    mmt.transaction_date,

    lpn.attribute4 lot_number,

    lpn.license_plate_number

FROM

    wip_lpn_completions       wlc,

    wip_entities              we,

    mtl_material_transactions mmt,

    mtl_transaction_lot_numbers lot,

    wms_license_plate_numbers lpn,

    mtl_system_items_kfv      msik

WHERE

        we.wip_entity_id = wlc.wip_entity_id

    AND we.organization_id = wlc.organization_id

    AND mmt.completion_transaction_id = wlc.completion_transaction_id

    AND lot.transaction_id = mmt.transaction_id

    AND lpn.lpn_id = wlc.lpn_id

    AND msik.inventory_item_id = wlc.inventory_item_id

    AND msik.organization_id = wlc.organization_id

--    AND we.wip_entity_name = '129465'--'129502'

    AND we.organization_id IN (91, 93)

    AND msik.item_type = 'FG'

ORDER BY

    mmt.transaction_date DESC;