 
/*********************************************\
*   ABSSOLUTE Oracle Objects                  *
*                                             *
*   Objects:           PACKAGES               *
*   Database version:  09.09.00               *
*   Date:              15-APR-2026            *
\*********************************************/
 
set define off 
 
create or replace package abslogwrite is

  -- Author  : PVD
  -- Created : 14-07-2008
  -- Updated : 21-10-2008 new log structure
  -- 20/03/2023: ABS-129857 Improve logging mechanism

  -- Purpose : Write ABSSolute logging into database

  procedure abslog_write(fp_logtype      in abslog.logtype%type,
                         fp_logsource    in abslog.logsource%type,
                         fp_plantid      in abslog.plant_id%type,
                         fp_priority     in abslog.priority%type,
                         fp_message      in abslog.message%type,
                         fp_systemuserid in abslog.systemuser_id%type default null);

  function abslogprocessjob_write(fp_plantid        in abslogprocessjob.plant_id%type,
                                  fp_starttimestamp in abslogprocessjob.starttimestamp%type,
                                  fp_workstationid  in abslogprocessjob.workstation_id%type,
                                  fp_dialogid       in abslogprocessjob.dialog_id%type,
                                  fp_plantprocessid in abslogprocessjob.plantprocess_id%type,
                                  fp_systemuserid   in abslog.systemuser_id%type default null)
    return number;

  procedure abslogprocessjob_update(fp_abslogprocessjobid in abslogprocessjob.abslogprocessjob_id%type,
                                    fp_endtimestamp       in abslogprocessjob.endtimestamp%type default null,
                                    fp_systemuserid       in abslogprocessjob.systemuser_id%type default null);

  function abslogprocessjobpart_write(fp_abslogprocessjobid in abslogprocessjobpart.abslogprocessjob_id%type,
                                      fp_processname        in abslogprocessjobpart.processname%type,
                                      fp_systemuserid       in abslogprocessjob.systemuser_id%type default null)
    return number;

  procedure abslogprocessjobline_write(fp_abslogprocessjobpartid in abslogprocessjobline.abslogprocessjobpart_id%type,
                                       fp_priority               in abslog.priority%type,
                                       fp_message                in abslog.message%type,
                                       fp_systemuserid           in abslog.systemuser_id%type default null);

  PROCEDURE extralog_info(p_source VARCHAR2, p_info IN VARCHAR_ARRAY);

end abslogwrite;
/
create or replace package body abslogwrite is
  gv_systemuserid systemuser.systemuser_id%type;

  procedure abslog_write(fp_logtype      in abslog.logtype%type,
                         fp_logsource    in abslog.logsource%type,
                         fp_plantid      in abslog.plant_id%type,
                         fp_priority     in abslog.priority%type,
                         fp_message      in abslog.message%type,
                         fp_systemuserid in abslog.systemuser_id%type default null) is
    pragma autonomous_transaction;
    lv_message abslog.message%type;
  begin
    select to_char(systimestamp, 'dd-mm-yyyy hh24.mi.ss.ff3') || ' ' into lv_message from dual;
    insert into abslog
      (abslog_id, logtype, logsource, plant_id, priority, timestamp, systemuser_id, message)
    values
      (seq_abslog.nextval, fp_logtype, fp_logsource, fp_plantid, fp_priority, sysdate,
       nvl(fp_systemuserid, gv_systemuserid), substr(lv_message||' '||fp_message, 1, 2000));
    commit;
  exception
    when others then
      begin
        rollback;
        dbms_output.put_line('Error during abslogwrite.abslog_write: ' || sqlerrm);
        raise;
      end;
  end abslog_write;

  function abslogprocessjob_write(fp_plantid        in abslogprocessjob.plant_id%type,
                                  fp_starttimestamp in abslogprocessjob.starttimestamp%type,
                                  fp_workstationid  in abslogprocessjob.workstation_id%type,
                                  fp_dialogid       in abslogprocessjob.dialog_id%type,
                                  fp_plantprocessid in abslogprocessjob.plantprocess_id%type,
                                  fp_systemuserid   in abslog.systemuser_id%type default null)
    return number is
    pragma autonomous_transaction;
    lv_abslogprocessjobid abslogprocessjob.abslogprocessjob_id%type;
  begin
    insert into abslogprocessjob
      (abslogprocessjob_id, plant_id, starttimestamp, endtimestamp, workstation_id, dialog_id,
       plantprocess_id, systemuser_id, timestamp)
    values
      (seq_abslogprocessjob.nextval, fp_plantid, nvl(fp_starttimestamp, sysdate), null,
       fp_workstationid, fp_dialogid, fp_plantprocessid, nvl(fp_systemuserid, gv_systemuserid),
       sysdate)
    returning abslogprocessjob_id into lv_abslogprocessjobid;
    commit;
    return lv_abslogprocessjobid;
  exception
    when others then
      begin
        rollback;
        dbms_output.put_line('Error during abslogwrite.abslogprocessjob_write: ' || sqlerrm);
        raise;
      end;
  end abslogprocessjob_write;

  procedure abslogprocessjob_update(fp_abslogprocessjobid in abslogprocessjob.abslogprocessjob_id%type,
                                    fp_endtimestamp       in abslogprocessjob.endtimestamp%type default null,
                                    fp_systemuserid       in abslogprocessjob.systemuser_id%type default null) is
    pragma autonomous_transaction;
  begin
    update abslogprocessjob
    set    endtimestamp = nvl(fp_endtimestamp, sysdate),
           systemuser_id = nvl(fp_systemuserid, gv_systemuserid),
           timestamp = nvl(fp_endtimestamp, sysdate)
    where  abslogprocessjob_id = fp_abslogprocessjobid;
    commit;
  exception
    when others then
      begin
        rollback;
        dbms_output.put_line('Error during abslogwrite.abslogprocessjob_update: ' || sqlerrm);
        raise;
      end;
  end abslogprocessjob_update;

  function abslogprocessjobpart_write(fp_abslogprocessjobid in abslogprocessjobpart.abslogprocessjob_id%type,
                                      fp_processname        in abslogprocessjobpart.processname%type,
                                      fp_systemuserid       in abslogprocessjob.systemuser_id%type default null)
    return number is
    pragma autonomous_transaction;
    lv_abslogprocesspartid abslogprocessjobpart.abslogprocessjobpart_id%type;
  begin
    insert into abslogprocessjobpart
      (abslogprocessjobpart_id, abslogprocessjob_id, processname, systemuser_id, timestamp)
    values
      (seq_abslogprocessjobpart.nextval, fp_abslogprocessjobid, fp_processname,
       nvl(fp_systemuserid, gv_systemuserid), sysdate)
    returning abslogprocessjobpart_id into lv_abslogprocesspartid;
    commit;
    return lv_abslogprocesspartid;
  exception
    when others then
      begin
        rollback;
        dbms_output.put_line('Error during abslogwrite.abslogprocessjobpart_write: ' || sqlerrm);
        raise;
      end;
  end abslogprocessjobpart_write;

  procedure abslogprocessjobline_write(fp_abslogprocessjobpartid in abslogprocessjobline.abslogprocessjobpart_id%type,
                                       fp_priority               in abslog.priority%type,
                                       fp_message                in abslog.message%type,
                                       fp_systemuserid           in abslog.systemuser_id%type default null) is
    pragma autonomous_transaction;
    lv_message abslog.message%type;
  begin
    select to_char(systimestamp, 'dd-mm-yyyy hh24.mi.ss.ff3') || ' ' into lv_message from dual;
    insert into abslogprocessjobline
      (abslogprocessjobline_id, abslogprocessjobpart_id, priority, timestamp, message,
       systemuser_id)
    values
      (seq_abslogprocessjobline.nextval, fp_abslogprocessjobpartid, fp_priority, sysdate,
       substr(lv_message||' '||fp_message, 1, 2000), nvl(fp_systemuserid, gv_systemuserid));
    commit;
  exception
    when others then
      begin
        rollback;
        dbms_output.put_line('Error during abslogwrite.abslogprocessjobline_write: ' || sqlerrm);
        raise;
      end;
  end abslogprocessjobline_write;

  PROCEDURE extralog_info(p_source VARCHAR2, p_info IN VARCHAR_ARRAY) IS
    pragma autonomous_transaction;
    lv_module                    VARCHAR2(100);
    lv_action                    VARCHAR2(100);
    lv_client_identifier         VARCHAR2(100);
    lv_client_info               VARCHAR2(500);
    lv_slash                     VARCHAR2(1) := '';
    lv_abslog_message            VARCHAR2(1000) := '[';
    lv_newline                   VARCHAR2(2) := chr(13)||chr(10);
  BEGIN
    FOR idx IN 1..p_info.count
    LOOP
      IF (p_info(idx) = lv_newline) THEN
        lv_abslog_message := lv_abslog_message||' ]'||lv_newline||'[';
        lv_slash := '';
        CONTINUE;
      END IF;
      lv_abslog_message := lv_abslog_message||' '||lv_slash||p_info(idx);
      lv_slash := '/';
    END LOOP;
    lv_abslog_message := lv_abslog_message||' ]';

    DBMS_APPLICATION_INFO.read_module(module_name => lv_module, action_name => lv_action);
    select SYS_CONTEXT('USERENV', 'CLIENT_IDENTIFIER') into lv_client_identifier from DUAL;
    DBMS_APPLICATION_INFO.read_client_info(client_info => lv_client_info);
    lv_abslog_message := lv_abslog_message||lv_newline||'[ '||lv_module||' /'||lv_action||' /'||lv_client_identifier||' /'||lv_client_info||' ]';

    abslogwrite.abslog_write(1, p_source, null, 5, lv_abslog_message);
  EXCEPTION
    when OTHERS then
      begin
        rollback;
        dbms_output.put_line('Error during abslogwrite.extralog_info: ' || sqlerrm);
        raise;
      end;
  END;

begin
  -- Initialization
  begin
    select sy.systemuser_id into gv_systemuserid from systemuser sy where sy.username = 'SYSADM';
  exception
    when no_data_found then
      begin
        select sy.systemuser_id
        into   gv_systemuserid
        from   systemuser sy
        where  sy.username = 'ABSADM';
      exception
        when no_data_found then
          begin
            select min(sy.systemuser_id) into gv_systemuserid from systemuser sy;
          end;
      end;
  end;
exception
  when others then
    begin
      dbms_output.put_line('Error during abslogwrite initialization: ' || sqlerrm);
      raise;
    end;
end abslogwrite;
/
create or replace package e2_lst is

  -- Author  : Bog
  -- Created : 27-02-2007

  v_errmessage varchar2(200);
  n_errcode    number;

  procedure e2_change_contact_person(fpnPlpc_id productlistpercustomer.productlistpercustomer_id%type,
                                     fpncontact_person_number contactperson.contactpersonnumber%type,
                                     fpscontact_person_name contactperson.name%type,
                                     fpscontact_person_phone_number contactperson.phone%type,
                                     fpscontact_person_email contactperson.email%type,
                                     fpscontact_person_function contactpersonfunction.code%type,
                                     fpnstatuscode out number,
                                     fpsstatustext out varchar2,
                                     fpnperson_id out contactperson.contactperson_id%type);

  procedure e2_change_route(fpncustomer_number customer.customernumber%type,
                            fpsroutenumber varchar2,
                            fpnstop_number stop.stopnumber%type,
                            fpdfirst_visit_date date,
                            fpnfrequency_in_weeks number,
                            fpsroute_stop_change_type varchar2,
                            fpsaction_text routestop.routelistinstructions%type,
                            fpnstatuscode out number,
                            fpsstatustext out varchar2);

  procedure raise_error(error_number number);

  function check_agreement_exist(plpc_id productlistpercustomer.productlistpercustomer_id%type)
  return boolean;

  function get_userid return systemuser.systemuser_id%type;

--  function get_finishing_meth_type return number;
end e2_lst;

/
create or replace package body e2_lst is

  procedure e2_change_contact_person(fpnPlpc_id productlistpercustomer.productlistpercustomer_id%type,
                                     fpncontact_person_number contactperson.contactpersonnumber%type,
                                     fpscontact_person_name contactperson.name%type,
                                     fpscontact_person_phone_number contactperson.phone%type,
                                     fpscontact_person_email contactperson.email%type,
                                     fpscontact_person_function contactpersonfunction.code%type,
                                     fpnstatuscode out number,
                                     fpsstatustext out varchar2,
                                     fpnperson_id out contactperson.contactperson_id%type) is
    lvnpersonexist  number;
    lvnfunctionid contactpersonfunction.contactpersonfunction_id%type;

    systemuserid systemuser.systemuser_id%type;
    customerid customer.customer_id%type;
    contactpersonid contactperson.contactperson_id%type;

    type Tcsr is ref cursor;
    Vcsr Tcsr;
  begin
    if not check_agreement_exist(fpnPlpc_id) then
      raise_error(-20000);
    end if;

    systemuserid := get_userid();

    -- get customerid
    select plpc.customer_id
    into customerid
    from productlistpercustomer plpc
    where plpc.productlistpercustomer_id = fpnPlpc_id;

    -- get the function id
    begin
      select f.contactpersonfunction_id
      into   lvnfunctionid
      from   contactpersonfunction f
      where  f.code = fpscontact_person_function;
    exception
      when no_data_found then
        raise_error(-20001);
    end;

    select count(*)
    into   lvnpersonexist
    from   contactperson p, productlistpercustomer plpc
    where  p.contactpersonnumber = fpncontact_person_number
      and plpc.customer_id = p.customer_id
      and plpc.productlistpercustomer_id = fpnPlpc_id;

    if lvnpersonexist = 0 then
      -- insert into contactperson table
      insert into contactperson cp
        (CUSTOMER_ID, CONTACTPERSON_ID, CONTACTPERSONNUMBER, NAME,
         PHONE, MOBILEPHONE,
         EMAIL, INVOICECONTACTPERSON, FAX,
         CONTACTPERSONFUNCTION_ID, SYSTEMUSER_ID, TIMESTAMP, SUPPLIER_ID)
      values
        (customerid, seq_contactperson.nextval, fpncontact_person_number, substr(fpscontact_person_name, 0, 40),
         substr(fpscontact_person_phone_number, 0 , 15), null,
         substr(fpscontact_person_email, 0, 40), 'Y', null,
         lvnfunctionid, systemuserid, sysdate, null);
    else
      begin
        open Vcsr for select p.contactperson_id
          from   contactperson p, productlistpercustomer plpc
          where  p.contactpersonnumber = fpncontact_person_number
            and plpc.customer_id = p.customer_id
            and plpc.productlistpercustomer_id = fpnPlpc_id;
        fetch Vcsr into contactpersonid;
        close Vcsr;

        update contactperson cp
          set CONTACTPERSONNUMBER = fpncontact_person_number,
            NAME = substr(fpscontact_person_name, 0, 40),
            PHONE = substr(fpscontact_person_phone_number, 0 , 15),
            EMAIL = substr(fpscontact_person_email, 0, 40),
            CONTACTPERSONFUNCTION_ID = lvnfunctionid,
            SYSTEMUSER_ID = systemuserid,
            TIMESTAMP = sysdate
        where cp.contactperson_id = contactpersonid;
        end;
    end if;

    commit;
    fpnstatuscode := 0;
    fpnperson_id := contactpersonid;
    return;

  exception
    when others then
      fpsstatustext := sqlerrm(sqlcode);
      fpnstatuscode := sqlcode;
      dbms_output.put_line('Error in procedure e2_change_contact_person; ' ||
                           fpsstatustext);
      rollback;
  end;
  -- END  Procedure e2_change_contact_person

  --Procedure e2_change_route
  procedure e2_change_route(fpncustomer_number customer.customernumber%type,
                            fpsroutenumber varchar2,
                            fpnstop_number stop.stopnumber%type,
                            fpdfirst_visit_date date,
                            fpnfrequency_in_weeks number,
                            fpsroute_stop_change_type varchar2,
                            fpsaction_text routestop.routelistinstructions%type,
                            fpnstatuscode out number,
                            fpsstatustext out varchar2) is
    lvncustomerid           number;

    routestopid stop.routestop_id%type;
    type Tcsr is ref cursor;
    Vcsr Tcsr;
    systemuserid systemuser.systemuser_id%type;
  begin
  null;
    -- checkings........
    if fpsroute_stop_change_type <> 'C' then raise_error(-20004); end if;

    begin
      select c.customer_id
      into   lvncustomerid
      from   customer c
      where  c.customernumber = fpncustomer_number;
    exception
      when no_data_found then
        raise_error(-20002);
    end;

    begin
      open Vcsr for
        select rs.routestop_id
        into routestopid
        from route r, routestop rs
        where r.route_id = rs.route_id
          and rs.stopnumber = fpnstop_number
          and rs.customer_id = lvncustomerid
          and r.routenumber = fpsroutenumber;
        fetch Vcsr into routestopid;
--    exception
--      when no_data_found then raise_error(-20005);
      if routestopid is null then raise_error(-20005); end if;
    end;

    systemuserid := get_userid();

    update routestop rs
    set rs.routelistinstructions = fpsaction_text,
      rs.systemuser_id = systemuserid,
      rs.timestamp = sysdate
    where rs.routestop_id in
      (select s.routestop_id
       from route r, routestop s
       where r.route_id = s.route_id
         and s.stopnumber = fpnstop_number
         and r.routenumber = fpsroutenumber
         and s.customer_id = lvncustomerid);

    update stop s
    set s.routelistinstructions = fpsaction_text,
      s.systemuser_id = systemuserid,
      s.timestamp = sysdate
    where s.routestop_id in
      (select s.routestop_id
       from route r, routestop s
       where r.route_id = s.route_id
         and s.stopnumber = fpnstop_number
         and r.routenumber = fpsroutenumber
         and s.customer_id = lvncustomerid);

    commit;
    fpnstatuscode := 0;
    return;
  exception
    when others then
      fpsstatustext := sqlerrm(sqlcode);
      fpnstatuscode := sqlcode;
      dbms_output.put_line('Error in procedure e2_change_route; ' ||
                           fpsstatustext);
      if fpnstatuscode > -20500 then
        rollback;
      else
        fpnstatuscode := 0; --do nothing with only warning.
        commit;
      end if;

  end;
  -- END  Procedure e2_change_route

  -- Procedure Raise_error
  procedure raise_error(error_number number) is
  begin
    -- -20000 .. -20999
    if error_number = -20000 then
      raise_application_error(error_number, 'Invalid product list per customer');
   elsif error_number = -20001 then
      raise_application_error(error_number, 'Invalid function code');
   elsif error_number = -20002 then
      raise_application_error(error_number, 'Invalid customer number');
   elsif error_number = -20003 then
      raise_application_error(error_number, 'Invalid route number');
   elsif error_number = -20004 then
      raise_application_error(error_number, 'Only C action is implemented');
   elsif error_number = -20005 then
      raise_application_error(error_number, 'Invalid route or stop number');

    end if;
  end;
  -- END Procedure Raise_error

  function check_agreement_exist(plpc_id productlistpercustomer.productlistpercustomer_id%type) return boolean is
    dummy_number number;
  begin

    select plpc.productlistpercustomer_id
    into dummy_number
    from productlistpercustomer plpc
    where plpc.productlistpercustomer_id = plpc_id;

    return true;
  exception
    when no_data_found then
      return false;
  end;

  function get_userid return systemuser.systemuser_id%type is
    systemuserid systemuser.systemuser_id%type;
  begin
    begin
      select s.systemuser_id
      into systemuserid
      from systemuser s
      where s.username = 'E2';
    exception
      when no_data_found then
        select min(s.systemuser_id) into systemuserid from systemuser s order by s.username asc;
    end;
    return systemuserid;
  end;

end e2_lst;

/
create or replace package guaranteedminimumdelivery is
  /*****************************************************************************************************************\
  * Package Guaranteed Minimum Delivery                                                                             *
  * Version 1.03                                                                                                    *
  *                                                                                                                 *
  * Release notes                                                                                                   *
  * 29-Nov-2018  ABS-71603 Create SQL Procedure to fill 'FILLDELIVERYLOADTABLES'                                    *
  * 04-Feb-2019  ABS-71608 (New) Modules Guaranteed Delivery Minimum + Temporary Assignment of Pool Garments        *
  * 23-Apr-2019  ABS-82716 Guaranteed Minimum Delivery - Add sorting criteria 'Delivery Point' and 'Bank'           *
  * 06-Sep-2019  ABS-88556 Different sequence sortstring                                                            *
  *                                                                                                                 *
  * Description:                                                                                                    *
  * Consists of 2 procedures                                                                                        *
  * - CreateDeliveryLoad creates deliveryload/detail                                                                *
  * - InitializeDeliveryLoad change status 1 to 2 and count personalizedavailableqty                                *
  \*****************************************************************************************************************/

  --CreateDeliveryLoad, creates deliveryload/detail
  procedure createdeliveryload(fp_plantid            in plant.plant_id%type,
                               fp_abslogprocessjobid in abslogprocessjob.abslogprocessjob_id%type default null,
                               fp_systemuserid       in systemuser.systemuser_id%type default 0);

  --InitializeDeliveryLoad, change deliveryload from status 1 to 2 and count personalizedavailableqty
  procedure initializedeliveryload(fp_deliveryloadid in deliveryload.deliveryload_id%type,
                                   fp_systemuserid   in systemuser.systemuser_id%type default 0);
end guaranteedminimumdelivery;
/
create or replace package body guaranteedminimumdelivery is

  procedure createdeliveryload(fp_plantid            in plant.plant_id%type,
                               fp_abslogprocessjobid in abslogprocessjob.abslogprocessjob_id%type default null,
                               fp_systemuserid       in systemuser.systemuser_id%type default 0) is
    gv_userexception exception;
    gv_abslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
    gv_message                abslog.message%type;
    gv_plantcode              plant.code%type;
    gv_process_desc           process.description%type;
    gv_guaranteedmindeldays   number;
    gv_maxbatchsize           number;
    gv_sizeall                sizedefinition.sizedefinition_id%type;
    gv_deliverydate           date;
    gv_deliveryday            number;
    gv_total_rowcount         number;
    gv_no_output_anymore      number := 0;

    ---internal procedure(s)
    procedure write_log(fp_message     in varchar2,
                        fp_priority    in number,
                        fp_partmessage in varchar2 default null) is
      procedure write_output is
      begin
        if gv_no_output_anymore = 0 then
          begin
            --write_output
            dbms_output.put_line(fp_message);
          end;
        end if;
      exception
        when others then
          begin
            gv_no_output_anymore := 1;
          end;
      end write_output;
    begin
      if fp_abslogprocessjobid is null then
        begin
          abslogwrite.abslog_write(5, 'createdeliveryload', fp_plantid, fp_priority, fp_message,
                                   fp_systemuserid);
        end;
      else
        begin
          --write_log abslogprocessjob
          if (gv_abslogprocessjobpartid is null or fp_partmessage is not null) then
            begin
              gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(fp_abslogprocessjobid,
                                                                                  coalesce(fp_partmessage,
                                                                                            'createdeliveryload'),
                                                                                  fp_systemuserid);
            end;
          end if;
          abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, fp_priority, fp_message,
                                                 fp_systemuserid);
        end;
      end if;
      write_output;
    exception
      when others then
        begin
          --write_log abslog
          abslogwrite.abslog_write(5, 'createdeliveryload', fp_plantid, fp_priority, fp_message,
                                   fp_systemuserid);
          write_output;
        end;
    end write_log;

    procedure intitialize is
    begin
      --intitialize
      gv_message                := 'intitialize';
      gv_abslogprocessjobpartid := null;
      gv_total_rowcount         := 0;
      --check parameter fp_plantid
      if fp_plantid is null then
        begin
          gv_message := 'Parameter fp_plantid cannot be left blank!';
          raise gv_userexception;
        end;
      else
        begin
          gv_message := 'Parameter fp_plantid ' || to_char(fp_plantid);
          select pt.code into gv_plantcode from plant pt where pt.plant_id = fp_plantid;
        end;
      end if;
      --check parameter fp_abslogprocessjobid
      if fp_abslogprocessjobid is not null then
        begin
          --select abslogprocessjob
          gv_message := 'fp_abslogprocessjobid ' || to_char(fp_abslogprocessjobid) ||
                        ' for plant code ' || gv_plantcode;
          select ps.description
          into   gv_process_desc
          from   abslogprocessjob ajl
          join   plantprocess pp
          on     pp.plantprocess_id = ajl.plantprocess_id
          join   process ps
          on     ps.process_id = pp.process_id
          where  ajl.abslogprocessjob_id = fp_abslogprocessjobid
          and    ajl.plant_id = fp_plantid;
        end;
      end if;
      --check parameter fp_systemuserid
      if fp_systemuserid is null then
        begin
          gv_message := 'Parameter fp_systemuserid cannot be left blank!';
          raise gv_userexception;
        end;
      end if;
      --get size star/all
      gv_message := 'get size star (*)';
      select s.sizedefinition_id into gv_sizeall from sizedefinition s where s.code = '*';
    end intitialize;

    procedure get_systemsettings is
    begin
      --GUARANTEEDMINDELDAYS
      gv_message := 'system setting GUARANTEEDMINDELDAYS for plant ' || gv_plantcode;
      select nvl(to_number(max(coalesce(st.value, st.factorydefault, '0'))), 0)
      into   gv_guaranteedmindeldays
      from   systemsetting st
      where  st.name = 'GUARANTEEDMINDELDAYS'
      and    st.plant_id = fp_plantid;
      --MAXMANUALSORTBATCHSIZE
      gv_message := 'system setting MAXMANUALSORTBATCHSIZE for plant ' || gv_plantcode;
      select nvl(to_number(max(coalesce(st.value, st.factorydefault, '0'))), 99)
      into   gv_maxbatchsize
      from   systemsetting st
      where  st.name = 'MAXMANUALSORTBATCHSIZE'
      and    st.plant_id = fp_plantid;
    end get_systemsettings;

    procedure create_load is
      lv_deliveryloadid    deliveryload.deliveryload_id%type;
      lv_sequencenumber    deliveryload.sequencenumber%type;
      lv_dld_count         number;
      lv_plantdepartmentid plantdepartment.plantdepartment_id%type;
      lv_cust_count        number;
    begin
      --create_load
      gv_message      := 'create_load, get deliveryday/date';
      gv_deliverydate := trunc(sysdate) + gv_guaranteedmindeldays;
      gv_deliveryday  := getabsdaynumber(gv_deliverydate);
      --Process Customer C, CustomerDeliveryDay CDD, CustomerExtraInfo CEI
      gv_message := 'create_load xc';
      for xc in (select c.customer_id, max(c.customernumber) customernumber, max(c.name) customername
                 from   customer c
                 join   customerdeliveryday cdd
                 on     cdd.customer_id = c.customer_id
                 join   customerextrainfo cei
                 on     cei.customer_id = c.customer_id
                 where  cdd.day_id = gv_deliveryday
                 and    c.dateactive <= gv_deliverydate
                 and    c.dateinactive > gv_deliverydate
                 and    cei.guaranteedminimumdelivery = 'Y'
                 and    exists (select 1
                         from   customeractivities ca
                         join   businessunit bu
                         on     bu.businessunit_id = ca.processbusinessunit_id
                         where  ca.customer_id = c.customer_id
                         and    bu.plant_id = fp_plantid)
                 group  by c.customer_id
                 order  by 2) loop
        begin
          --Process ProductListPerCustomer PLPC etc
          write_log('Customer: ' || xc.customernumber || '  Name ' || xc.customername, 1);
          lv_cust_count := 0;
          gv_message    := 'create_load xl';
          --Process Wearer W, WearerEmployment WE, etc
          gv_message := 'create_load xw';
          for xw in (select wi.wearerinventory_id, we.distributionpoint_id, lc.deliverypoint_id,
                            lc.bank, wi.changesperweek, delp.code deliverypointcode,
                            (select max(bu.businessunit_id)
                              from   product p
                              join   productgroup pg
                              on     pg.productgroup_id = p.productgroup_id
                              join   customeractivities ca
                              on     ca.activity_id = pg.activity_id
                              join   businessunit bu
                              on     bu.businessunit_id = ca.processbusinessunit_id
                              where  ca.customer_id = w.customer_id
                              and    p.product_id = wi.product_id
                              and    bu.plant_id = fp_plantid) businessunit_id
                     from   wearer w
                     join   weareremployment we
                     on     we.wearer_id = w.wearer_id
                     join   wearerinventory wi
                     on     wi.weareremployment_id = we.weareremployment_id
                     join   locker lc
                     on     lc.locker_id = we.locker_id
                     join   deliverypoint delp
                     on     delp.deliverypoint_id = lc.deliverypoint_id
                     join   distributionpoint dp
                     on     dp.distributionpoint_id = we.distributionpoint_id
                     where  w.customer_id = xc.customer_id
                     and    w.dateactive <= gv_deliverydate
                     and    w.dateinactive > gv_deliverydate
                     and    not exists (select 1
                             from   deliveryday dd
                             where  dd.department_id = dp.department_id
                             and    dd.day_id = gv_deliveryday)
                     and    wi.dateactive <= gv_deliverydate
                     and    wi.dateinactive > gv_deliverydate
                     and    wi.maxinventory > 0
                     and    exists
                      (select 1
                             from   productlistpercustomer plpc
                             join   productdeliveryday pdd
                             on     pdd.productlistpercustomer_id = plpc.productlistpercustomer_id
                             where  plpc.customer_id = xc.customer_id
                             and    plpc.product_id = wi.product_id
                             and    plpc.dateactive <= gv_deliverydate
                             and    plpc.dateinactive > gv_deliverydate
                             and    pdd.day_id = gv_deliveryday)
                     and    exists (select bu.businessunit_id
                             from   product p
                             join   productgroup pg
                             on     pg.productgroup_id = p.productgroup_id
                             join   customeractivities ca
                             on     ca.activity_id = pg.activity_id
                             join   businessunit bu
                             on     bu.businessunit_id = ca.processbusinessunit_id
                             where  ca.customer_id = w.customer_id
                             and    p.product_id = wi.product_id
                             and    bu.plant_id = fp_plantid)
                     order  by lc.deliverypoint_id, lc.bank, lc.locker) loop
            begin
              --reset values
              lv_sequencenumber := null;
              lv_dld_count      := 0;
              --First check if there is a DeliveryLoad which contains already
              --a detail line for the same bank.
              --If there is then the current wearer inventory can be added to this one.
              gv_message := 'check if deliveryload, exists for bank ' || nvl(xw.bank, ' ');
              for zz in (select dl.deliveryload_id, dl.sequencenumber
                         from   deliveryload dl
                         join   deliveryloaddetail dld
                         on     dld.deliveryload_id = dl.deliveryload_id
                         join   businessunit bu
                         on     bu.businessunit_id = dl.businessunit_id
                         where  bu.plant_id = fp_plantid
                         and    dl.deliverypoint_id = xw.deliverypoint_id
                         and    dl.deliverydate = gv_deliverydate
                         and    dld.sortstring = nvl(xw.bank, ' ')
                         order  by dl.sequencenumber desc) loop
                begin
                  lv_deliveryloadid := zz.deliveryload_id;
                  lv_sequencenumber := zz.sequencenumber;
                  lv_dld_count      := 0; --it is there, no new count needed
                  --first record found exit loop
                  exit;
                end;
              end loop;
              if lv_sequencenumber is null then
                begin
                  --check if deliveryload, exists
                  gv_message := 'check if deliveryload, exists';
                  select dl.deliveryload_id, dl.sequencenumber,
                         nvl((select count(distinct dld.sortstring)
                              from   deliveryloaddetail dld
                              where  dld.deliveryload_id = dl.deliveryload_id), 0) dld_count
                  into   lv_deliveryloadid, lv_sequencenumber, lv_dld_count
                  from   deliveryload dl
                  join   businessunit bu
                  on     bu.businessunit_id = dl.businessunit_id
                  where  bu.plant_id = fp_plantid
                  and    dl.deliverypoint_id = xw.deliverypoint_id
                  and    dl.deliverydate = gv_deliverydate
                  and    dl.sequencenumber =
                         (select max(dlx.sequencenumber) sequencenumber
                           from   deliveryload dlx
                           where  dlx.businessunit_id = dl.businessunit_id
                           and    dlx.deliverypoint_id = dl.deliverypoint_id
                           and    dlx.deliverydate = dl.deliverydate);
                  --more then we can have in the batch, create new one
                  if lv_dld_count >= gv_maxbatchsize then
                    begin
                      lv_sequencenumber := lv_sequencenumber + 1;
                      raise no_data_found;
                    end;
                  end if;
                exception
                  when no_data_found then
                    begin
                      --insert into deliveryload
                      gv_message := 'insert into deliveryload';
                      --get new count
                      lv_dld_count      := nvl(lv_dld_count, 0) + 1;
                      lv_sequencenumber := nvl(lv_sequencenumber, 1);
                      --get plantdepartment_id
                      select max(std.plantdepartment_id)
                      into   lv_plantdepartmentid
                      from   standarddelivery std
                      where  std.distributionpoint_id = xw.distributionpoint_id;
                      --insert into deliveryload
                      insert into deliveryload
                        (deliveryload_id, businessunit_id, deliverypoint_id, deliverydate,
                         sequencenumber, plantdepartment_id, code, status, creationtimestamp,
                         initializationtimestamp, initializationsystemuser_id, outscanstarttimestamp,
                         outscanstartsystemuser_id, systemuser_id, timestamp)
                      values
                        (seq_deliveryload.nextval, xw.businessunit_id, xw.deliverypoint_id,
                         gv_deliverydate, lv_sequencenumber, lv_plantdepartmentid,
                         to_char(gv_deliverydate, 'YYYYIWDY') ||
                          lpad(to_char(lv_sequencenumber), 2, '0') ||
                          lpad(to_char(xc.customernumber), 12, '0') ||
                          lpad(xw.deliverypointcode, 6, ' '), 1, sysdate, null, null, null, null,
                         fp_systemuserid, sysdate)
                      returning deliveryload_id into lv_deliveryloadid;
                    end;
                end;
              end if;
              begin
                --insert into deliveryloaddetail
                gv_message := 'insert into deliveryloaddetail';
                insert into deliveryloaddetail
                  (deliveryloaddetail_id, deliveryload_id, wearerinventory_id, sortstring,
                   todeliverquantity, personalizedavailableqty, sortposition, systemuser_id,
                   timestamp)
                values
                  (seq_deliveryloaddetail.nextval, lv_deliveryloadid, xw.wearerinventory_id,
                   nvl(xw.bank, ' '), xw.changesperweek, 0, 0, fp_systemuserid, sysdate);
                --count rows
                gv_total_rowcount := gv_total_rowcount + 1;
                lv_cust_count     := lv_cust_count + 1;
              exception
                when dup_val_on_index then
                  null; --no problem was already there
              end;
            end;
          end loop; --xw
          write_log('Number of rows created  ' || lv_cust_count, 1);
        end;
      end loop; --xc
    end create_load;

    procedure finalize is
    begin
      --finalize
      commit;
      if gv_total_rowcount > 0 then
        begin
          write_log('Total of deliveryloaddetail ' || gv_total_rowcount || ' created', 1);
        end;
      else
        begin
          write_log('No rows created', 1);
        end;
      end if;
    end finalize;
  begin
    --intitialize
    intitialize;
    --get systemsettings
    get_systemsettings;
    --create_load
    create_load;
    --finalize
    finalize;
  exception
    --exception handling global
    when gv_userexception then
      begin
        rollback;
        write_log(gv_message, 3);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('Error No Data Found ' || gv_message, 3);
      end;
    when others then
      begin
        rollback;
        write_log('Error Others ' || gv_message || ' ' || sqlerrm, 3);
      end;
  end createdeliveryload;

  procedure initializedeliveryload(fp_deliveryloadid in deliveryload.deliveryload_id%type,
                                   fp_systemuserid   in systemuser.systemuser_id%type default 0) is
    gv_userexception exception;
    gv_plantid          plant.plant_id%type;
    gv_message          abslog.message%type;
    gv_rec_deliveryload deliveryload%rowtype;
    gv_repairflagid     automaticflag.flag_id%type; --AutomaticFlag_ID = 3
    gv_rewashflagid     automaticflag.flag_id%type; --AutomaticFlag_ID = 19

    ---internal procedure(s)
    procedure write_log(fp_message in varchar2, fp_priority in number) is
      procedure write_output is
      begin
        --write_output
        dbms_output.put_line(fp_message);
      exception
        when others then
          null; --no problem if output cannot be written
      end write_output;
    begin
      --write_log abslog
      abslogwrite.abslog_write(5, 'initializedeliveryload', gv_plantid, fp_priority, fp_message,
                               fp_systemuserid);
      write_output;
    end write_log;

    procedure intitialize is
    begin
      --intitialize
      gv_message := 'intitialize';
      --check parameter fp_deliveryloadid
      if fp_deliveryloadid is null then
        begin
          gv_message := 'Parameter fp_deliveryloadid cannot be left blank!';
          raise gv_userexception;
        end;
      else
        begin
          gv_message := 'Parameter fp_deliveryloadid ' || to_char(fp_deliveryloadid);
          select dll.*
          into   gv_rec_deliveryload
          from   deliveryload dll
          where  dll.deliveryload_id = fp_deliveryloadid;
          if gv_rec_deliveryload.status >= 2 then
            begin
              gv_message := 'Parameter fp_deliveryloadid ' || to_char(fp_deliveryloadid) ||
                            ' already initialized';
              raise gv_userexception;
            end;
          end if;
        end;
      end if;
      --check parameter fp_systemuserid
      if fp_systemuserid is null then
        begin
          gv_message := 'Parameter fp_systemuserid cannot be left blank!';
          raise gv_userexception;
        end;
      end if;
      --get gv_repairflagid
      gv_message := 'get repair flag for event = Repair requested by repair pointer';
      select nvl(max(af.flag_id), 0)
      into   gv_repairflagid
      from   automaticflag af
      where  af.event = 'Repair requested by repair pointer';
      --get gv_rewashflagid
      gv_message := 'get Rewash flag for event = Rewash';
      select nvl(max(af.flag_id), 0)
      into   gv_rewashflagid
      from   automaticflag af
      where  af.event = 'Rewash';
    end intitialize;

    procedure initial_load is
      lv_sortstring   deliveryloaddetail.sortstring%type := ' ';
      lv_sortposition deliveryloaddetail.sortposition%type := 0;
      lv_available    number;

      procedure get_available_qty(fp_wearerinventoryid in wearerinventory.wearerinventory_id%type) is
      begin
        --get_available_qty
        gv_message := 'get_available_qty for wearerinventory_id ' || to_char(fp_wearerinventoryid);
        select count(distinct ui.uniqueitem_id)
        into   lv_available
        from   uniqueitem ui
        join   uniqueitemnonpool uinp
        on     uinp.uniqueitem_id = ui.uniqueitem_id
        join   stay
        on     stay.stay_id = ui.stay_id
        where  uinp.wearerinventory_id = fp_wearerinventoryid
        and    stay.stay_id = ui.stay_id
        and    stay.staynr in (30, 33, 40)
        and    not exists
         (select 1
                from   uniqueitemflag uif
                join   flag
                on     flag.flag_id = uif.flag_id
                where  uif.uniqueitem_id = ui.uniqueitem_id
                and    uif.startdate <= trunc(sysdate)
                and    ((flag.prohibitdelivery = 'Y') or (uif.flag_id = gv_repairflagid) or
                      (uif.flag_id = gv_rewashflagid)));
      end get_available_qty;
    begin
      --initial_load
      gv_message := 'initial_load';
      for xd in (select dld.sortstring, dld.wearerinventory_id
                 from   deliveryloaddetail dld
                 where  dld.deliveryload_id = fp_deliveryloadid
                 group  by dld.sortstring, dld.wearerinventory_id
                 order  by dld.sortstring, dld.wearerinventory_id) loop
        begin
          if (xd.sortstring <> lv_sortstring) then
            begin
              lv_sortposition := lv_sortposition + 1;
              lv_sortstring   := xd.sortstring;
            end;
          end if;
          --get_available_qty
          get_available_qty(xd.wearerinventory_id);
          --Update DeliveryLoadDetail
          gv_message := 'update deliveryloaddetail dld to Initialized';
          update deliveryloaddetail dld
          set    dld.sortposition = lv_sortposition, dld.personalizedavailableqty = lv_available,
                 dld.systemuser_id = fp_systemuserid, dld.timestamp = sysdate
          where  dld.deliveryload_id = fp_deliveryloadid
          and    dld.wearerinventory_id = xd.wearerinventory_id;
        end;
      end loop; --x
      --Update DeliveryLoad
      gv_message := '';
      update deliveryload dl
      set    dl.status = 2, dl.systemuser_id = fp_systemuserid, dl.timestamp = sysdate,
             dl.initializationsystemuser_id = fp_systemuserid, dl.initializationtimestamp = sysdate
      where  dl.deliveryload_id = fp_deliveryloadid;
    end initial_load;

    procedure finalize is
    begin
      --finalize
      commit;
      write_log('Ready', 1);
    end finalize;
  begin
    --intitialize
    intitialize;
    --initial_load
    initial_load;
    --finalize
    finalize;
  exception
    --exception handling global
    when gv_userexception then
      begin
        rollback;
        write_log(gv_message, 3);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('Error No Data Found ' || gv_message, 3);
      end;
    when others then
      begin
        rollback;
        write_log('Error Others ' || gv_message || ' ' || sqlerrm, 3);
      end;
  end initializedeliveryload;

end guaranteedminimumdelivery;
/
create or replace package importpayments is
  /**************************************************************************************************\
  * -- Author  : ABS                                                                                 *
  * -- Version : 2.16                                                                                *
  * -- Created : 24-6-2010                                                                           *
  * -- Updated : 11-4-2010 for order 20011240 automatic write of differences in reconsiliation file  *
  *              27-6-2012 latest version made with WBO/PVD                                          *
  *              02-7-2014 updated version from AUJ                                                  *
  *              17-7-2015 updated for remit batch id on artransaction                               *
  *              01-8-2017 ABS-38514 Clean Financial Interface with Sage and ABSSolute               *
  *              17-09-2019 Fix problem with length artransaction.remitidentification                *
  *              19-06-2020 Fix problem for multiple remitbatches                                    *
  *              02-09-2021 ABS-124024 /ABS-9519 add trigger functionality into package              *
  * -- Purpose : This package contains a number of database procedures and functions for             *
  *    processing payments for ABSsolute and automatically apply these payments.                     *
  *    These procedures are used from the ABSsolute client itself,                                   *
  *    but they can also be used in scripts that can be scheduled via the script scheduler.          *
  \**************************************************************************************************/

  -- Internal public functions not be called directly! but only from a differenct plsql block.
  function create_remitbatch(fp_businessunitid   in businessunit.businessunit_id%type,
                             fp_businessunitcode out businessunit.code%type,
                             fp_batchdate        in remitbatch.batchdate%type,
                             fp_alwayscreate     in number default 0)
    return remitbatch.remitbatch_id%type;

  function update_remitbatch(fp_remitbatchid in remitbatch.remitbatch_id%type) return number;

  function create_artransaction(fp_rec_paymenttransaction in paymenttransaction%rowtype,
                                fp_remark                 in artransaction.remark%type,
                                fp_remitbatchid           in remitbatch.remitbatch_id%type,
                                fp_origin                 in artransaction.origin%type default 7,
                                fp_debitcredit            in artransaction.debitcredit%type default 'C',
                                fp_artransactiontypeid    in artransactiontype.artransactiontype_id%type default null,
                                fp_invoicenumber          in artransaction.invoicenumber%type default 0)
    return artransaction.artransaction_id%type;

  -- Public procedure declarations
  procedure processpaymenttransaction(fp_paymenttransaction_id  in paymenttransaction.paymenttransaction_id%type,
                                      fp_remitbatchid           in remitbatch.remitbatch_id%type,
                                      fp_abslogprocessjobpartid in abslogprocessjobpart.abslogprocessjobpart_id%type,
                                      fp_remark                 in artransaction.remark%type,
                                      fp_systemuserid           in systemuser.systemuser_id%type,
                                      fp_manual                 in number default 1,
                                      fp_internal               in boolean default false,
                                      fp_invoicenumber          in invoiceheader.invoicenumber%type default 0,
                                      fp_allpaid                in boolean default false,
                                      fp_artransactionid_o      in artransaction.artransaction_id%type default null);

  procedure processopencredit(fp_paymenttransaction_id  in paymenttransaction.paymenttransaction_id%type,
                              fp_remitbatchid           in remitbatch.remitbatch_id%type,
                              fp_abslogprocessjobpartid in abslogprocessjobpart.abslogprocessjobpart_id%type,
                              fp_remark                 in artransaction.remark%type,
                              fp_systemuserid           in systemuser.systemuser_id%type,
                              fp_manual                 in number default 1,
                              fp_internal               in boolean default false);

  procedure processallpayments(fp_plantid in plant.plant_id%type);

  function create_paymenttransaction(fp_rec_paymenttransaction in out paymenttransaction%rowtype) return boolean;
  function create_paymenttransactdetail(fp_rec_paymenttransaction in paymenttransaction%rowtype)return boolean;
end importpayments;
/
create or replace package body importpayments is
  e_user_exception_error exception;
  gv_abslogprocessjobid     abslogprocessjob.abslogprocessjob_id%type;
  gv_abslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
  gv_processname            abslogprocessjobpart.processname%type;
  gv_plantid                plant.plant_id%type;
  gv_plantprocessid         plantprocess.plantprocess_id%type;
  gv_systemuserid           systemuser.systemuser_id%type;
  gv_dialogid               dialogs.dialog_id%type;
  gv_workstationid          workstation.workstation_id%type;
  gv_message                abslogprocessjobline.message%type;
  gv_remitbatchstatus_1     status.status_id%type;
  gv_remitbatchstatus_2     status.status_id%type;

  procedure initialize is
  begin
    --initialize
    gv_processname            := 'package importpayments';
    gv_message                := 'initialize';
    gv_abslogprocessjobid     := null;
    gv_abslogprocessjobpartid := null;
    gv_processname            := null;
    gv_plantid                := null;
    gv_plantprocessid         := null;
    gv_systemuserid           := 0;
    gv_dialogid               := null;
    gv_workstationid          := null;
    --get default values
    gv_message := 'initialize getting remitbatch status 1';
    select st.status_id
    into   gv_remitbatchstatus_1
    from   status st
    where  st.statustype = 'RB'
    and    st.code = '1';
    gv_message := 'initialize getting remitbatch status 1';
    select st.status_id
    into   gv_remitbatchstatus_2
    from   status st
    where  st.statustype = 'RB'
    and    st.code = '2';
  end initialize;

  procedure end_log is
  begin
    if gv_abslogprocessjobid is not null then
      --end_log
      abslogwrite.abslogprocessjob_update(gv_abslogprocessjobid, sysdate, gv_systemuserid);
    else
      --write_log
      abslogwrite.abslog_write(5, nvl(substr(gv_processname, 1, 30), 'importpayments'), null, 3,
                               gv_message || ' ' || sqlerrm, gv_systemuserid);
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(gv_message);
        dbms_output.put_line(sqlerrm);
      end;
  end end_log;

  procedure write_log(fp_priority abslogprocessjobline.priority%type default 1) is
  begin
    --write_log
    if gv_abslogprocessjobid is null and gv_abslogprocessjobpartid is null then
      gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(gv_plantid, sysdate,
                                                                  gv_workstationid, gv_dialogid,
                                                                  gv_plantprocessid, gv_systemuserid);
    end if;
    --write_log part
    if gv_abslogprocessjobpartid is null and gv_abslogprocessjobid is not null then
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gv_abslogprocessjobid,
                                                                          gv_processname,
                                                                          gv_systemuserid);
    end if;
    abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, fp_priority, gv_message,
                                           gv_systemuserid);
  exception
    when others then
      begin
        dbms_output.put_line(gv_message);
        dbms_output.put_line(sqlerrm);
      end;
  end write_log;

  function check_paymenttransaction(fp_paymenttransaction_id in paymenttransaction.paymenttransaction_id%type,
                                    fp_errorcheck            boolean default true)
    return paymenttransaction%rowtype is
    lv_rec_paymenttransaction     paymenttransaction%rowtype;
    lv_status                     paymenttransaction.status%type;
    lv_messagenumber              paymenttransaction.messagenumber%type;
    lv_paymenttransactiondetailid paymenttransactiondetail.paymenttransactiondetail_id%type;

    procedure update_paymenttransaction is
    begin
      update paymenttransaction t
      set    t.status = lv_status, t.messagenumber = lv_messagenumber,
             t.systemuser_id = gv_systemuserid, t.timestamp = sysdate
      where  t.paymenttransaction_id = fp_paymenttransaction_id;
    end update_paymenttransaction;

    procedure update_paymenttransactdetail is
    begin
      update paymenttransactiondetail td
      set    td.messagenumber = lv_messagenumber, td.systemuser_id = gv_systemuserid,
             td.timestamp = sysdate
      where  td.paymenttransactiondetail_id = lv_paymenttransactiondetailid;
    end update_paymenttransactdetail;
  begin
    --check_paymenttransaction - step 1
    gv_message := 'check_paymenttransaction - step 1 id ' || fp_paymenttransaction_id;
    select *
    into   lv_rec_paymenttransaction
    from   paymenttransaction t
    where  t.paymenttransaction_id = fp_paymenttransaction_id;
    --check paymenttransaction
    case
      when lv_rec_paymenttransaction.customer_link_id is null then
        begin
          gv_message       := 'Customer from payment transaction is unknown, transaction id ' ||
                              fp_paymenttransaction_id;
          lv_status        := 2;
          lv_messagenumber := 1;
          update_paymenttransaction;
          raise e_user_exception_error;
        end;
      when lv_rec_paymenttransaction.status = 2 and fp_errorcheck then
        begin
          gv_message := 'Payment transaction id ' || fp_paymenttransaction_id ||
                        ' contains error! (status 2)';
          raise e_user_exception_error;
        end;
      when lv_rec_paymenttransaction.status in (3, 4) then
        begin
          gv_message := 'Payment transaction id ' || fp_paymenttransaction_id ||
                        ' is already processed! (status 3 or 4)';
          raise e_user_exception_error;
        end;
      else
        null; -- all ok
    end case;
    --check paymenttransactiondetail lines
    for y in (select t.paymenttransactiondetail_id, t.detailreference, t.grossamount,
                     t.discountamount, t.invoicenumber,
                     (select h.billtocustomer_link_id
                       from   invoiceheader h
                       where  h.invoicenumber = t.invoicenumber
                       and    h.documenttype = 2) ih_billtocust_id,
                     (select ihe.paybycustomer_link_id
                       from   invoiceheaderextrainfo ihe, invoiceheader h
                       where  ihe.invoiceheader_id = h.invoiceheader_id
                       and    h.invoicenumber = t.invoicenumber
                       and    h.documenttype = 2) paybycustomer_link_id
              from   paymenttransactiondetail t
              where  t.paymenttransaction_id = fp_paymenttransaction_id
              and    t.artransaction_id is null) loop
      begin
        if y.ih_billtocust_id <> lv_rec_paymenttransaction.customer_link_id and
           y.paybycustomer_link_id <> lv_rec_paymenttransaction.customer_link_id then
          begin
            lv_messagenumber := 1;
            update_paymenttransactdetail;
            lv_status        := 2;
            lv_messagenumber := 3;
            update_paymenttransaction;
            gv_message := 'Details error: payment customer does not match with bill to customer or pay by customer';
            raise e_user_exception_error;
          end;
        end if;
        -- for each invoice number check artransactions
        for z in (select a.billtocustomer_link_id, a.invoiceheader_id,
                         (select he.paybycustomer_link_id
                           from   invoiceheader h, invoiceheaderextrainfo he
                           where  h.invoiceheader_id = a.invoiceheader_id
                           and    h.invoiceheader_id = he.invoiceheader_id) ih_paybycustomer_id,
                         (select cbi.paybycustomer_link_id
                           from   customerbillinginfo cbi
                           where  cbi.customer_id = a.billtocustomer_link_id) cb_paybycustomer_id
                  from   artransaction a
                  where  a.invoicenumber = y.invoicenumber
                  and    a.originaltransaction_id = a.artransaction_id
                  and    a.debitcredit = 'D') loop
          begin
            if (z.billtocustomer_link_id <> lv_rec_paymenttransaction.customer_link_id and
               z.ih_paybycustomer_id <> lv_rec_paymenttransaction.customer_link_id) or
               (z.cb_paybycustomer_id <> lv_rec_paymenttransaction.customer_link_id and
               z.invoiceheader_id is null) then
              begin
                lv_messagenumber := 1;
                update_paymenttransactdetail;
                lv_status        := 2;
                lv_messagenumber := 3;
                update_paymenttransaction;
                gv_message := 'Details error: payment customer does not match with bill to customer or pay by customer';
                raise e_user_exception_error;
              end;
            end if;
          end;
        end loop; --z
      end;
    end loop; --y
    return lv_rec_paymenttransaction;
  exception
    when no_data_found then
      begin
        gv_message := 'Payment transaction id ' || fp_paymenttransaction_id || ' does not exist!';
        raise e_user_exception_error;
      end;
  end check_paymenttransaction;

  function get_next_artransaction_id return artransaction.artransaction_id%type is
    lv_artransactionid artransaction.artransaction_id%type;
  begin
    select seq_artransaction.nextval into lv_artransactionid from dual;
    return lv_artransactionid;
  end get_next_artransaction_id;

  function get_artransactiontype_id(fp_type        in artransactiontype.typenumber%type,
                                    fp_debitcredit in artransactiontype.debitcredit%type)
    return artransactiontype.artransactiontype_id%type is
    lv_artransactiontype_id artransactiontype.artransactiontype_id%type;
  begin
    select t.artransactiontype_id
    into   lv_artransactiontype_id
    from   artransactiontype t
    where  t.typenumber = fp_type
    and    t.debitcredit = fp_debitcredit;
    return lv_artransactiontype_id;
  end get_artransactiontype_id;

  function create_artransaction(fp_rec_paymenttransaction in paymenttransaction%rowtype,
                                fp_remark                 in artransaction.remark%type,
                                fp_remitbatchid           in remitbatch.remitbatch_id%type,
                                fp_origin                 in artransaction.origin%type,
                                fp_debitcredit            in artransaction.debitcredit%type,
                                fp_artransactiontypeid    in artransactiontype.artransactiontype_id%type,
                                fp_invoicenumber          in artransaction.invoicenumber%type)
    return artransaction.artransaction_id%type is
    lv_rec_artransaction artransaction%rowtype;
  begin
    --create_artransaction - step 2
    gv_message := 'create_artransaction - step 2';
    --fill values
    lv_rec_artransaction.artransaction_id       := get_next_artransaction_id;
    lv_rec_artransaction.paymenttype            := fp_rec_paymenttransaction.paymenttype;
    lv_rec_artransaction.businessunit_id        := fp_rec_paymenttransaction.businessunit_id;
    lv_rec_artransaction.billtocustomer_link_id := fp_rec_paymenttransaction.customer_link_id;
    lv_rec_artransaction.deltocustomer_link_id  := null;
    lv_rec_artransaction.artransactiondate      := fp_rec_paymenttransaction.paymentdate;
    lv_rec_artransaction.debitcredit            := fp_debitcredit;
    lv_rec_artransaction.artransactiontype_id   := nvl(fp_artransactiontypeid,
                                                       get_artransactiontype_id(5, fp_debitcredit));
    lv_rec_artransaction.currency_id            := fp_rec_paymenttransaction.currency_id;
    lv_rec_artransaction.amount := case
                                     when fp_debitcredit = 'D' then
                                      -1 * fp_rec_paymenttransaction.amount
                                     else
                                      fp_rec_paymenttransaction.amount
                                   end;
    lv_rec_artransaction.route_id               := null;
    lv_rec_artransaction.remitidentification    := substr(trim(fp_rec_paymenttransaction.reference),1,16);
    lv_rec_artransaction.paymentreference       := fp_rec_paymenttransaction.reference;
    lv_rec_artransaction.invoicenumber          := fp_invoicenumber;
    lv_rec_artransaction.remark                 := fp_remark;
    lv_rec_artransaction.remitbatch_id          := fp_remitbatchid;
    lv_rec_artransaction.invoiceheader_id       := null;
    lv_rec_artransaction.originaltransaction_id := lv_rec_artransaction.artransaction_id;
    lv_rec_artransaction.parentartransaction_id := null;
    lv_rec_artransaction.arbalance_id           := null;
    lv_rec_artransaction.glexport_id            := null;
    lv_rec_artransaction.commissioncalculated   := 'N';
    lv_rec_artransaction.processbusinessunit_id := lv_rec_artransaction.businessunit_id;
    lv_rec_artransaction.client_link_id         := null;
    lv_rec_artransaction.systemuser_id          := gv_systemuserid;
    lv_rec_artransaction.timestamp              := sysdate;
    lv_rec_artransaction.origin                 := fp_origin;
    lv_rec_artransaction.exportstatus           := 0;
    lv_rec_artransaction.totalappliedamount     := 0;
    lv_rec_artransaction.isopen_yn              := 'Y';
    --insert
    insert into artransaction values lv_rec_artransaction;
    return lv_rec_artransaction.artransaction_id;
  end create_artransaction;

  procedure update_paymenttransactdetail(fp_paymenttransactdetailid in paymenttransactiondetail.paymenttransactiondetail_id%type,
                                         fp_messagenumber           paymenttransactiondetail.messagenumber%type) is
  begin
    --update paymenttransactiondetail.messagenumber
    update paymenttransactiondetail ptd
    set    ptd.messagenumber = fp_messagenumber, ptd.systemuser_id = gv_systemuserid,
           ptd.timestamp = sysdate
    where  ptd.paymenttransactiondetail_id = fp_paymenttransactdetailid;
  end update_paymenttransactdetail;

  procedure connect_artrans_topayment(fp_paymenttransaction_id in paymenttransaction.paymenttransaction_id%type,
                                      fp_artransaction_id      in artransaction.artransaction_id%type,
                                      fp_manual                in number default 1) is
    lv_status paymenttransaction.status%type;
  begin
    --connect_artrans_topayment - step 3
    gv_message := 'connect_artrans_topayment - step 3 fp_paymenttransaction_id ' ||
                  fp_paymenttransaction_id || ' fp_artransaction_id ' || fp_artransaction_id;
    case
      when fp_manual = 1 then
        lv_status := 4;
      else
        lv_status := 3;
    end case;
    --update artransaction
    update paymenttransaction t
    set    t.artransaction_id = fp_artransaction_id, t.status = lv_status,
           t.processingtimestamp = sysdate, t.processinguser_id = gv_systemuserid,
           t.systemuser_id = gv_systemuserid, t.timestamp = sysdate
    where  t.paymenttransaction_id = fp_paymenttransaction_id;
  end connect_artrans_topayment;

  procedure apply_paymentdetails(fp_rec_paymenttransaction in paymenttransaction%rowtype,
                                 fp_origin                 in artransaction.origin%type default 7,
                                 fp_allpaid                in boolean default false,
                                 fp_artransactionid_o      in artransaction.artransaction_id%type,
                                 fp_remitbatchid           in remitbatch.remitbatch_id%type) is
    lv_counter             number;
    lv_rec_artransaction   artransaction%rowtype;
    lv_invoiceheaderid     invoiceheader.invoiceheader_id%type;
    lv_paybycustomerid     invoiceheaderextrainfo.paybycustomer_link_id%type;
    lv_billtocustomerid    invoiceheader.billtocustomer_link_id%type;
    lv_paymenttermsduedate invoiceheaderextrainfo.paymenttermsduedate%type;

    procedure after_create_cashapplication(fp_new_amount             in cashapplication.amount%type,
                                           fp_debitartransaction_id  in cashapplication.debitartransaction_id%type,
                                           fp_creditartransaction_id in cashapplication.creditartransaction_id%type) is
    begin
      --after_create_cashapplication
      --previously was "trigger after_create_cashapplication after insert on cashapplication"
      update artransaction d
      set    d.totalappliedamount = d.totalappliedamount + fp_new_amount,
             d.isopen_yn = case
                             when d.totalappliedamount + fp_new_amount = d.amount then
                              'N'
                             else
                              'Y'
                           end, d.timestamp = sysdate, d.systemuser_id = gv_systemuserid
      where  d.artransaction_id = fp_debitartransaction_id;
      update artransaction c
      set    c.totalappliedamount = c.totalappliedamount + fp_new_amount,
             c.isopen_yn = case
                             when c.totalappliedamount + fp_new_amount = c.amount then
                              'N'
                             else
                              'Y'
                           end,
             c.originaltransaction_id = case
                                          when c.originaltransaction_id = c.artransaction_id and
                                               c.origin = 7 and c.artransactiontype_id = 21 then
                                           fp_debitartransaction_id
                                          else
                                           c.originaltransaction_id
                                        end, c.timestamp = sysdate,
             c.systemuser_id = gv_systemuserid
      where  c.artransaction_id = fp_creditartransaction_id;
    end after_create_cashapplication;

    procedure statement_apply(fp_rec_ptd in paymenttransactiondetail%rowtype) is
      lv_applyamount        paymenttransactiondetail.grossamount%type;
      lv_statementnumber    invoiceheader.invoicenumber%type;
      lv_count              number := 0;
      lv_m_applied          artransaction.isopen_yn%type;
      lv_invoiceamount      artransaction.amount%type;
      lv_2beapplieddiscount artransaction.amount%type;
    begin
      --statement_apply step 4 statement
      gv_message     := 'statement_apply';
      lv_applyamount := fp_rec_ptd.grossamount - fp_rec_ptd.discountamount;
      --get invoice artransaction
      begin
        --4.1 statement invoice amount linked to artransactions via statements
        select h.prebillamount
        into   lv_invoiceamount
        from   invoiceheader h
        where  h.invoiceheader_id = fp_rec_ptd.invoiceheader_id;
        --
        if not fp_allpaid and (lv_applyamount < lv_invoiceamount) then
          begin
            select h.invoicenumber
            into   lv_statementnumber
            from   invoiceheader h, artransaction a
            where  h.invoiceheader_id = a.invoiceheader_id
            and    a.artransaction_id = fp_rec_ptd.artransaction_id;
            gv_message := 'Payment is less then statement amount for statement ' ||
                          lv_statementnumber ||
                          '. Payment is processed as unapplied credit and must be applied manually';
            write_log(2);
          end;
        else
          begin
            if (fp_rec_ptd.grossamount <> lv_invoiceamount) then
              begin
                --update record, gross amount does not match
                update_paymenttransactdetail(fp_rec_ptd.paymenttransactiondetail_id, 12);
              end;
            end if; --4.2. process all statementlines
            lv_2beapplieddiscount := nvl(fp_rec_ptd.discountamount, 0);
            for x in (select a.*
                      from   statementline l, artransaction a
                      where  l.invoiceheader_id = fp_rec_ptd.invoiceheader_id
                      and    l.artransaction_id = a.artransaction_id
                      and    a.debitcredit = 'D'
                      union all
                      select a.*
                      from   artransaction a
                      where  a.invoiceheader_id = fp_rec_ptd.invoiceheader_id
                      and    a.debitcredit = 'D') loop
              begin
                --apply invoices and finance charges from statement
                update artransaction a
                set    a.remitbatch_id = nvl(a.remitbatch_id, fp_remitbatchid),
                       a.systemuser_id = gv_systemuserid, a.timestamp = sysdate
                where  a.artransaction_id = x.artransaction_id
                and    a.isopen_yn = 'Y';
                lv_m_applied := 'N';
                if (x.totalappliedamount <> 0) then
                  begin
                    lv_m_applied := 'Y';
                  end;
                end if;
                if ((x.amount - x.totalappliedamount > lv_2beapplieddiscount) or
                   (lv_2beapplieddiscount = 0) /*no discount*/
                   ) then
                  begin
                    insert into cashapplication
                      (cashapplication_id, debitartransaction_id, creditartransaction_id, applydate,
                       applytimestamp, applysystemuser_id, amount, unapplied_yn, unapplydate,
                       unapplytimestamp, unapplysystemuser_id, origin)
                    values
                      (seq_cashapplication.nextval, x.artransaction_id,
                       fp_rec_paymenttransaction.artransaction_id,
                       fp_rec_paymenttransaction.paymentdate, sysdate, gv_systemuserid,
                       x.amount - x.totalappliedamount - lv_2beapplieddiscount, 'N', null, null,
                       null, 5);
                    --after_create_cashapplication
                    after_create_cashapplication(x.amount - x.totalappliedamount -
                                                 lv_2beapplieddiscount, x.artransaction_id,
                                                 fp_rec_paymenttransaction.artransaction_id);
                    if lv_2beapplieddiscount > 0 and fp_artransactionid_o is not null then
                      insert into cashapplication
                        (cashapplication_id, debitartransaction_id, creditartransaction_id,
                         applydate, applytimestamp, applysystemuser_id, amount, unapplied_yn,
                         unapplydate, unapplytimestamp, unapplysystemuser_id, origin)
                      values
                        (seq_cashapplication.nextval, x.artransaction_id, fp_artransactionid_o,
                         fp_rec_paymenttransaction.paymentdate, sysdate, gv_systemuserid,
                         lv_2beapplieddiscount, 'N', null, null, null, 5);
                      --after_create_cashapplication
                      after_create_cashapplication(lv_2beapplieddiscount, x.artransaction_id,
                                                   fp_artransactionid_o);
                      lv_2beapplieddiscount := 0;
                    end if;
                  end;
                else
                  begin
                    /*only apply discount for this invoice*/
                    lv_2beapplieddiscount := lv_2beapplieddiscount -
                                             (x.amount - x.totalappliedamount);
                    insert into cashapplication
                      (cashapplication_id, debitartransaction_id, creditartransaction_id, applydate,
                       applytimestamp, applysystemuser_id, amount, unapplied_yn, unapplydate,
                       unapplytimestamp, unapplysystemuser_id, origin)
                    values
                      (seq_cashapplication.nextval, x.artransaction_id,
                       nvl(fp_artransactionid_o, fp_rec_paymenttransaction.artransaction_id),
                       fp_rec_paymenttransaction.paymentdate, sysdate, gv_systemuserid,
                       (x.amount - x.totalappliedamount), 'N', null, null, null, 5);
                    --after_create_cashapplication
                    after_create_cashapplication((x.amount - x.totalappliedamount),
                                                 x.artransaction_id,
                                                 nvl(fp_artransactionid_o,
                                                      fp_rec_paymenttransaction.artransaction_id));
                  end;
                end if;

                if (lv_m_applied = 'Y') then
                  begin
                    --update partly paid
                    update_paymenttransactdetail(fp_rec_ptd.paymenttransactiondetail_id, 11);
                  end;
                end if;
                --check if partly paid
                select count(1)
                into   lv_count
                from   artransaction a
                where  a.originaltransaction_id = x.artransaction_id
                and    a.totalappliedamount <> 0
                and    a.artransaction_id <> a.originaltransaction_id;
                if lv_count >= 1 then
                  begin
                    --update partly paid
                    update_paymenttransactdetail(fp_rec_ptd.paymenttransactiondetail_id, 11);
                  end;
                end if;
              end;
            end loop; --x
          end;
        end if;
      exception
        when no_data_found then
          null;
      end;
    end statement_apply;

    procedure invoice_apply(fp_rec_ptd in paymenttransactiondetail%rowtype) is
      lv_applyamount   paymenttransactiondetail.grossamount%type;
      lv_invoiceamount artransaction.amount%type;
      --       artransaction.closingamount%type;
      lv_rec_discount artransaction%rowtype;
      --lv_rec_opendiff        artransaction%rowtype;
      lv_creditsqueezeamount invoiceheader.creditsqueezeamount%type;
    begin
      --invoice_apply step 4 invoice
      gv_message     := 'invoice_apply';
      lv_applyamount := fp_rec_ptd.grossamount - fp_rec_ptd.discountamount;
      --get invoice artransaction
      begin
        select *
        into   lv_rec_artransaction
        from   artransaction aro
        where  aro.artransaction_id = fp_rec_ptd.artransaction_id
              -->20011971
        and    aro.isopen_yn = 'Y';
        --aro.closingtransaction_id is null;
        --get invoice amount
        lv_invoiceamount := lv_rec_artransaction.amount - lv_rec_artransaction.totalappliedamount;
        --<20011971
        begin
          --get credit squeeze amount
          select h.creditsqueezeamount
          into   lv_creditsqueezeamount
          from   invoiceheader h
          where  h.invoiceheader_id = lv_rec_artransaction.invoiceheader_id;
        exception
          when no_data_found then
            begin
              lv_creditsqueezeamount := 0;
            end;
        end;
      exception
        when no_data_found then
          begin
            lv_invoiceamount       := 0;
            lv_creditsqueezeamount := 0;
          end;
      end;
      if (lv_invoiceamount = 0) then
        begin
          --update record, invoice partly paid
          update_paymenttransactdetail(fp_rec_ptd.paymenttransactiondetail_id, 11);
        end;
      else
        begin
          if ((lv_creditsqueezeamount <> fp_rec_ptd.discountamount and
             lv_rec_artransaction.invoiceheader_id is not null) or
             (fp_rec_ptd.discountamount > 0 and
             lv_paymenttermsduedate <= fp_rec_paymenttransaction.paymentdate)) then
            begin
              --update record, discount amount does not match
              update_paymenttransactdetail(fp_rec_ptd.paymenttransactiondetail_id, 13);
            end;
          end if;
          --check amounts
          if (fp_rec_ptd.grossamount <> lv_invoiceamount) then
            begin
              --update record, gross amount does not match
              update_paymenttransactdetail(fp_rec_ptd.paymenttransactiondetail_id, 12);
            end;
          end if;
          --4.1 invoice apply
          --determine closing amount
          if lv_applyamount < lv_invoiceamount then
            --create cash application record
            insert into cashapplication
              (cashapplication_id, debitartransaction_id, creditartransaction_id, applydate,
               applytimestamp, applysystemuser_id, amount, unapplied_yn, unapplydate,
               unapplytimestamp, unapplysystemuser_id, origin)
            values
              (seq_cashapplication.nextval, lv_rec_artransaction.artransaction_id,
               fp_rec_paymenttransaction.artransaction_id,
               trunc(fp_rec_paymenttransaction.paymentdate), sysdate, gv_systemuserid,
               lv_applyamount, 'N', null, null, null, 5);
          else
            --create cash application record
            insert into cashapplication
              (cashapplication_id, debitartransaction_id, creditartransaction_id, applydate,
               applytimestamp, applysystemuser_id, amount, unapplied_yn, unapplydate,
               unapplytimestamp, unapplysystemuser_id, origin)
            values
              (seq_cashapplication.nextval, lv_rec_artransaction.artransaction_id,
               fp_rec_paymenttransaction.artransaction_id,
               trunc(fp_rec_paymenttransaction.paymentdate), sysdate, gv_systemuserid,
               lv_invoiceamount, 'N', null, null, null, 5);
          end if;
          --update closing amount
          if lv_applyamount < lv_invoiceamount then
            begin
              --debit transaction
              update artransaction a
              set    a.remitbatch_id = nvl(a.remitbatch_id, fp_remitbatchid),
                     a.systemuser_id = gv_systemuserid, a.timestamp = sysdate,
                     a.totalappliedamount = a.totalappliedamount + lv_applyamount
              where  a.originaltransaction_id = lv_rec_artransaction.artransaction_id
              and    a.isopen_yn = 'Y';
              --credit transaction
              update artransaction a
              set    a.systemuser_id = gv_systemuserid, a.timestamp = sysdate,
                     a.totalappliedamount = lv_applyamount, a.isopen_yn = 'N'
              where  a.originaltransaction_id = fp_rec_paymenttransaction.artransaction_id
              and    a.isopen_yn = 'Y';
            end;
          else
            begin
              --debit transaction
              update artransaction a
              set    a.remitbatch_id = nvl(a.remitbatch_id, fp_remitbatchid),
                     a.systemuser_id = gv_systemuserid, a.timestamp = sysdate,
                     a.totalappliedamount = a.totalappliedamount + lv_invoiceamount, a.isopen_yn = 'N'
              where  a.originaltransaction_id = lv_rec_artransaction.artransaction_id
              and    a.isopen_yn = 'Y';
              if lv_applyamount = lv_invoiceamount then
                begin
                  --credit transaction
                  update artransaction a
                  set    a.systemuser_id = gv_systemuserid, a.timestamp = sysdate,
                         a.totalappliedamount = lv_applyamount, a.isopen_yn = 'N'
                  where  a.originaltransaction_id = fp_rec_paymenttransaction.artransaction_id
                  and    a.isopen_yn = 'Y';
                end;
              else
                begin
                  --credit transaction
                  --there is still a part open of this unapplied credit
                  update artransaction a
                  set    a.systemuser_id = gv_systemuserid, a.timestamp = sysdate,
                         a.totalappliedamount = lv_invoiceamount
                  where  a.originaltransaction_id = fp_rec_paymenttransaction.artransaction_id
                  and    a.isopen_yn = 'Y';
                end;
              end if;
            end;
          end if;
          --4.2 invoice create discount
          if fp_rec_ptd.discountamount > 0 and
             lv_paymenttermsduedate <= fp_rec_paymenttransaction.paymentdate then
            begin
              --copy from original
              lv_rec_discount := lv_rec_artransaction;
              --update fields that are different
              lv_rec_discount.artransaction_id       := get_next_artransaction_id;
              lv_rec_discount.artransactiontype_id   := get_artransactiontype_id(4, 'C'); --credit discount
              lv_rec_discount.debitcredit            := 'C';
              lv_rec_discount.amount                 := fp_rec_ptd.discountamount;
              lv_rec_discount.remitbatch_id          := nvl(lv_rec_discount.remitbatch_id,
                                                            fp_remitbatchid);
              lv_rec_discount.originaltransaction_id := lv_rec_artransaction.artransaction_id;
              lv_rec_discount.origin                 := fp_origin;
              insert into artransaction values lv_rec_discount;
              --create cash application record
              insert into cashapplication
                (cashapplication_id, debitartransaction_id, creditartransaction_id, applydate,
                 applytimestamp, applysystemuser_id, amount, unapplied_yn, unapplydate,
                 unapplytimestamp, unapplysystemuser_id, origin)
              values
                (seq_cashapplication.nextval, lv_rec_artransaction.artransaction_id,
                 lv_rec_discount.artransaction_id, fp_rec_paymenttransaction.paymentdate, sysdate,
                 gv_systemuserid, lv_rec_discount.amount, 'N', null, null, null, 5);
            end;
          end if;
        end;
      end if;
    end invoice_apply;

  begin
    --apply_invoice - step 4
    gv_message := 'apply_paymentdetails - step 4 fp_paymenttransaction_id ' ||
                  fp_rec_paymenttransaction.paymenttransaction_id;
    for x in (select *
              from   paymenttransactiondetail ptd
              where  ptd.paymenttransaction_id = fp_rec_paymenttransaction.paymenttransaction_id
              order  by ptd.grossamount) loop
      begin
        --check if there is an invoiceheader for statment
        begin
          select h.invoiceheader_id, h.billtocustomer_link_id,
                 (select he.paybycustomer_link_id
                   from   invoiceheaderextrainfo he
                   where  he.invoiceheader_id = h.invoiceheader_id) paybycustomer_id,
                 (select he.paymenttermsduedate
                   from   invoiceheaderextrainfo he
                   where  he.invoiceheader_id = h.invoiceheader_id) paymenttermsduedate
          into   lv_invoiceheaderid, lv_billtocustomerid, lv_paybycustomerid, lv_paymenttermsduedate
          from   invoiceheader h
          where  h.invoicenumber = x.invoicenumber
          and    h.documenttype = 2
          and    x.artransaction_id is null;
          --update paymenttransactiondetail with invoiceheader_id
          if (fp_rec_paymenttransaction.customer_link_id = lv_billtocustomerid or
             fp_rec_paymenttransaction.customer_link_id = lv_paybycustomerid) then
            begin
              --update variable
              x.invoiceheader_id := lv_invoiceheaderid;
              --update record
              update paymenttransactiondetail ptd
              set    ptd.invoiceheader_id = lv_invoiceheaderid, ptd.systemuser_id = gv_systemuserid,
                     ptd.timestamp = sysdate
              where  ptd.paymenttransactiondetail_id = x.paymenttransactiondetail_id;
              --apply statement
              statement_apply(x);
            end;
          end if;
        exception
          when no_data_found then
            begin
              --process invoice
              select count(1), max(a.artransaction_id) artransaction_id
              into   lv_counter, lv_rec_artransaction.artransaction_id
              from   artransaction a
              where  a.invoicenumber = x.invoicenumber
              and    a.debitcredit = 'D' --otherwise it selects also credits and count will be >1
              and    a.originaltransaction_id = a.artransaction_id
              and    ((a.billtocustomer_link_id = fp_rec_paymenttransaction.customer_link_id) or
                    (fp_rec_paymenttransaction.customer_link_id =
                    (select he.paybycustomer_link_id
                        from   invoiceheader h, invoiceheaderextrainfo he
                        where  h.invoiceheader_id = he.invoiceheader_id
                        and    a.invoiceheader_id = h.invoiceheader_id)) or
                    (a.invoiceheader_id is null and
                    fp_rec_paymenttransaction.customer_link_id =
                    (select cb.paybycustomer_link_id
                        from   customerbillinginfo cb
                        where  cb.customer_id = a.billtocustomer_link_id)));
              if lv_counter = 1 then
                begin
                  select he.paymenttermsduedate
                  into   lv_paymenttermsduedate
                  from   invoiceheaderextrainfo he, invoiceheader h, artransaction a
                  where  he.invoiceheader_id = h.invoiceheader_id
                  and    h.invoiceheader_id = a.invoiceheader_id
                  and    a.invoicenumber = x.invoicenumber;
                  --update variable
                  x.artransaction_id := lv_rec_artransaction.artransaction_id;
                  --update record
                  update paymenttransactiondetail ptd
                  set    ptd.artransaction_id = lv_rec_artransaction.artransaction_id,
                         ptd.systemuser_id = gv_systemuserid, ptd.timestamp = sysdate
                  where  ptd.paymenttransactiondetail_id = x.paymenttransactiondetail_id;
                  --apply invoice
                  invoice_apply(x);
                end;
              else
                begin
                  --update record, not found or too many found
                  update_paymenttransactdetail(x.paymenttransactiondetail_id, 10);
                end;
              end if;
            end;
        end;
      end;
    end loop; --x  end step 4
  end apply_paymentdetails;

  function create_remitbatch(fp_businessunitid   in businessunit.businessunit_id%type,
                             fp_businessunitcode out businessunit.code%type,
                             fp_batchdate        in remitbatch.batchdate%type,
                             fp_alwayscreate     in number default 0)
    return remitbatch.remitbatch_id%type is
    lv_remitbatchid remitbatch.remitbatch_id%type;
    lv_batchnumber  remitbatch.batchnumber%type;

    procedure create_batch is
    begin
      --get batch number
      gv_message := gv_message || ' get sequence seq_remitbatch_' || fp_businessunitcode;
      execute immediate 'select seq_remitbatch_' || fp_businessunitcode || '.nextval from dual'
        into lv_batchnumber;
      --create remit batch
      select seq_remitbatch.nextval into lv_remitbatchid from dual;
      insert into remitbatch
        (remitbatch_id, businessunit_id, timestamp, systemuser_id, totalamount, batchnumber,
         batchdate, status_id)
      values
        (lv_remitbatchid, fp_businessunitid, sysdate, gv_systemuserid, 0, lv_batchnumber,
         fp_batchdate, gv_remitbatchstatus_1);
    end create_batch;
  begin
    --create_remitbatch
    gv_message := 'create_remitbatch';
    --get businessunit code
    select bu.code
    into   fp_businessunitcode
    from   businessunit bu
    where  bu.businessunit_id = fp_businessunitid;
    if fp_alwayscreate = 1 then
      create_batch;
    else
      begin
        --check if it already exists BUSINESSUNIT_ID, BATCHDATE, BATCHNUMBER, SYSTEMUSER_ID
        select rb.remitbatch_id
        into   lv_remitbatchid
        from   remitbatch rb
        where  rb.businessunit_id = fp_businessunitid
        and    rb.batchdate = fp_batchdate
        and    rb.status_id = gv_remitbatchstatus_1
        and    rb.systemuser_id = gv_systemuserid;
      exception
        when no_data_found then
          create_batch;
      end;
    end if;
    return lv_remitbatchid;
  end create_remitbatch;

  function update_remitbatch(fp_remitbatchid in remitbatch.remitbatch_id%type) return number is
    lv_amount number;
  begin
    --update_remitbatch
    gv_message := 'update_remitbatch';
    --get amount
    select nvl(sum(a.amount), 0)
    into   lv_amount
    from   artransaction a
    where  a.remitbatch_id = fp_remitbatchid
    and    a.originaltransaction_id = a.artransaction_id
    and    a.debitcredit = 'C';
    --update remitbatch
    update remitbatch rt
    set    rt.totalamount = lv_amount, rt.status_id = gv_remitbatchstatus_2,
           rt.systemuser_id = gv_systemuserid, rt.timestamp = sysdate
    where  rt.remitbatch_id = fp_remitbatchid;
    --return lv_amount
    return lv_amount;
  end update_remitbatch;

  procedure get_log_info(fp_rec_paymenttransaction in paymenttransaction%rowtype) is
    lv_customernumber customer.customernumber%type;
    lv_customername   customer.name%type;
    function get_message_text return varchar2 is
      /*  paymenttransaction.messagenumber values and text
      0 = OK / No error
      1 = Customer not found / defined
      2 = Customer number and MICR number don?t match
      3 = Details error
      4 = Sum of detail amounts is more than payment
      */
    begin
      --agreed we would export paymenttransaction.messagenumber's text
      case
        when fp_rec_paymenttransaction.messagenumber = 0 then
          return 'OK / No error';
        when fp_rec_paymenttransaction.messagenumber = 1 then
          return 'Customer not found / defined';
        when fp_rec_paymenttransaction.messagenumber = 2 then
          return 'Customer number and MICR number don not match';
        when fp_rec_paymenttransaction.messagenumber = 4 then
          return 'Sum of detail amounts is more than payment';
        else
          return 'Details error';
      end case;
    end get_message_text;
  begin
    --get customer info
    select c.customernumber, c.name
    into   lv_customernumber, lv_customername
    from   customer c
    where  c.customer_id = fp_rec_paymenttransaction.customer_link_id;
    --create message
    gv_message := lv_customernumber || ' ' || lv_customername || ' ' ||
                  to_char(fp_rec_paymenttransaction.paymentdate, 'YYYY-MM-DD') || ' ' ||
                  fp_rec_paymenttransaction.reference || ' ' || fp_rec_paymenttransaction.amount || ' ' ||
                  get_message_text;
  end get_log_info;

  procedure processpaymenttransaction(fp_paymenttransaction_id  in paymenttransaction.paymenttransaction_id%type,
                                      fp_remitbatchid           in remitbatch.remitbatch_id%type,
                                      fp_abslogprocessjobpartid in abslogprocessjobpart.abslogprocessjobpart_id%type,
                                      fp_remark                 in artransaction.remark%type,
                                      fp_systemuserid           in systemuser.systemuser_id%type,
                                      fp_manual                 in number default 1,
                                      fp_internal               in boolean default false,
                                      fp_invoicenumber          in invoiceheader.invoicenumber%type default 0,
                                      fp_allpaid                in boolean default false,
                                      fp_artransactionid_o      in artransaction.artransaction_id%type default null) is
    lv_rec_paymenttransaction paymenttransaction%rowtype;

    procedure check_parameters is
    begin
      if fp_paymenttransaction_id is null then
        begin
          gv_message := 'parameter fp_paymenttransaction_id cannot be left empty!';
          raise e_user_exception_error;
        end;
      end if;
      if fp_systemuserid is null then
        begin
          gv_message := 'parameter fp_systemuserid cannot be left empty!';
          raise e_user_exception_error;
        end;
      end if;
    end check_parameters;

  begin
    --processpaymenttransaction
    gv_message                := 'processpaymenttransaction';
    gv_processname            := 'importpayments.' || gv_message;
    gv_systemuserid           := fp_systemuserid;
    if (fp_abslogprocessjobpartid is not null) then
       gv_abslogprocessjobpartid := fp_abslogprocessjobpartid;
    end if;
    check_parameters;
    write_log(1);
    --steps 1 check_paymenttransaction
    lv_rec_paymenttransaction := check_paymenttransaction(fp_paymenttransaction_id);
    --step 2 create credit artransaction
    lv_rec_paymenttransaction.artransaction_id := create_artransaction(lv_rec_paymenttransaction,
                                                                       fp_remark, fp_remitbatchid, 7,
                                                                       'C', null, fp_invoicenumber);
    --step 3 connect artransaction to payment
    connect_artrans_topayment(fp_paymenttransaction_id, lv_rec_paymenttransaction.artransaction_id,
                              fp_manual);
    --step 4
    apply_paymentdetails(lv_rec_paymenttransaction, 7, fp_allpaid, fp_artransactionid_o,
                         fp_remitbatchid);
    --step 7 log message
    commit;
    get_log_info(lv_rec_paymenttransaction);
    write_log(1);
    if not fp_internal then
      end_log;
    end if;
  exception
    when e_user_exception_error then
      begin
        rollback;
        write_log(3);
        if fp_internal then
          raise;
        else
          end_log;
        end if;
      end;
    when no_data_found then
      begin
        rollback;
        gv_message := 'No data found ' || gv_message;
        write_log(3);
        if fp_internal then
          raise;
        else
          end_log;
        end if;
      end;
    when others then
      begin
        rollback;
        write_log(3);
        gv_message := sqlerrm;
        write_log(5);
        if fp_internal then
          raise;
        else
          end_log;
        end if;
      end;
  end processpaymenttransaction;

  procedure processopencredit(fp_paymenttransaction_id  in paymenttransaction.paymenttransaction_id%type,
                              fp_remitbatchid           in remitbatch.remitbatch_id%type,
                              fp_abslogprocessjobpartid in abslogprocessjobpart.abslogprocessjobpart_id%type,
                              fp_remark                 in artransaction.remark%type,
                              fp_systemuserid           in systemuser.systemuser_id%type,
                              fp_manual                 in number default 1,
                              fp_internal               in boolean default false) is
    lv_artransactionid        artransaction.artransaction_id%type;
    lv_rec_paymenttransaction paymenttransaction%rowtype;

    procedure check_parameters is
    begin
      if fp_paymenttransaction_id is null then
        begin
          gv_message := 'parameter fp_paymenttransaction_id cannot be left empty!';
          raise e_user_exception_error;
        end;
      end if;
      if fp_abslogprocessjobpartid is null then
        begin
          gv_message := 'parameter fp_abslogprocessjobpartid cannot be left empty!';
          raise e_user_exception_error;
        end;
      else
        begin
          gv_message := 'parameter fp_abslogprocessjobpartid ' || fp_abslogprocessjobpartid;
          select jp.abslogprocessjob_id
          into   gv_abslogprocessjobid
          from   abslogprocessjobpart jp
          where  jp.abslogprocessjobpart_id = fp_abslogprocessjobpartid;
        end;
      end if;
      if fp_systemuserid is null then
        begin
          gv_message := 'parameter fp_systemuserid cannot be left empty!';
          raise e_user_exception_error;
        end;
      end if;
    end check_parameters;

  begin
    --processunappliedcredit
    gv_message                := 'processopencredit';
    gv_processname            := 'importpayments.' || gv_message;
    gv_systemuserid           := fp_systemuserid;
    gv_abslogprocessjobpartid := fp_abslogprocessjobpartid;
    check_parameters;
    gv_message := 'processopencredit';
    write_log(1);
    --steps 1 check artransaction, do not check on status =2 that is allowed now
    lv_rec_paymenttransaction := check_paymenttransaction(fp_paymenttransaction_id, false);
    --step 2 create artransaction
    lv_artransactionid := create_artransaction(lv_rec_paymenttransaction, fp_remark, fp_remitbatchid,
                                               8, null, 0);
    --step 3 connect artransaction to payment
    connect_artrans_topayment(fp_paymenttransaction_id, lv_artransactionid, fp_manual);
    --step 4 log message
    commit;
    get_log_info(lv_rec_paymenttransaction);
    write_log(1);
    if not fp_internal then
      end_log;
    end if;
  exception
    when e_user_exception_error then
      begin
        rollback;
        write_log(3);
        if fp_internal then
          raise;
        else
          end_log;
        end if;
      end;
    when no_data_found then
      begin
        rollback;
        gv_message := 'No data found ' || gv_message;
        write_log(3);
        if fp_internal then
          raise;
        else
          end_log;
        end if;
      end;
    when others then
      begin
        rollback;
        write_log(3);
        gv_message := sqlerrm;
        write_log(5);
        if fp_internal then
          raise;
        else
          end_log;
        end if;
      end;
  end processopencredit;

  procedure processallpayments(fp_plantid in plant.plant_id%type) is
    lv_counter          number := 0;
    lv_remitbatchid     remitbatch.remitbatch_id%type;
    lv_businessunitcode businessunit.code%type;
    lv_remitamount      number;

    procedure check_parameters is
    begin
      if fp_plantid is null then
        begin
          gv_message := 'parameter fp_plantid cannot be left empty!';
          raise e_user_exception_error;
        end;
      end if;
    end check_parameters;
  begin
    --processallpayments
    gv_message     := 'processallpayments';
    gv_processname := 'importpayments.' || gv_message;
    gv_plantid     := fp_plantid;
    check_parameters;
    --step 1-2 create process log
    write_log(1);
    --step 3 process not processed payment transactions
    for x in (select pa.paymenttransaction_id, pa.businessunit_id, pa.paymentdate, pa.reference
              from   paymenttransaction pa
              where  pa.status in (0, 1)
              and    pa.businessunit_id in
                     (select bu.businessunit_id from businessunit bu where bu.plant_id = fp_plantid)
              order  by pa.businessunit_id, pa.batchnumber, pa.paymentdate) loop
      begin
        --step 3.1  create remitbatch
        lv_remitbatchid           := create_remitbatch(x.businessunit_id, lv_businessunitcode,
                                                       x.paymentdate);
        gv_processname            := 'importpayments.processallpayments ' || lv_businessunitcode;
        gv_abslogprocessjobpartid := null;
        write_log(1);
        --step 3.2 process payment transaction
        processpaymenttransaction(x.paymenttransaction_id, lv_remitbatchid,
                                  gv_abslogprocessjobpartid, null, gv_systemuserid, 0, true,
                                  x.reference);
        --step 3.3. update remitbatch
        lv_remitamount := update_remitbatch(lv_remitbatchid);
        --count number of records processed
        lv_counter := lv_counter + 1;
        --messages in log
        gv_message := 'Businessunit ' || lv_businessunitcode || ' total remit batch ' ||
                      lv_remitamount;
        write_log(1);
      end;
    end loop; --x
    --extra logging
    if lv_counter = 0 then
      begin
        gv_message := 'No payment transactions found/nothing processed';
        write_log(1);
      end;
    else
      begin
        gv_message := 'processed ' || lv_counter || ' paymenttransactions.';
        write_log(1);
      end;
    end if;
    --step 4 close log
    commit;
    end_log;
  exception
    when e_user_exception_error then
      begin
        rollback;
        write_log(3);
        end_log;
      end;
    when no_data_found then
      begin
        rollback;
        gv_message := 'No data found ' || gv_message;
        write_log(3);
        end_log;
      end;
    when others then
      begin
        rollback;
        write_log(3);
        gv_message := sqlerrm;
        write_log(5);
        end_log;
      end;
  end processallpayments;

  function get_cust_currency(fp_customerid in customer.customer_id%type) return number is
    lv_currencyid currency.currency_id%type;
  begin
    --get_cust_currency
    gv_message := ' get_cust_currency for customer id ' || fp_customerid;
    select c.currency_id into lv_currencyid from customer c where c.customer_id = fp_customerid;
    return lv_currencyid;
  end get_cust_currency;

  function create_paymenttransaction(fp_rec_paymenttransaction in out paymenttransaction%rowtype)
    return boolean is
  begin
    --create_paymenttransaction
    gv_message := 'create_paymenttransaction';
    --get paymenttransaction_id
    select seq_paymenttransaction.nextval
    into   fp_rec_paymenttransaction.paymenttransaction_id
    from   dual;
    --get other values
    fp_rec_paymenttransaction.importtimestamp     := sysdate;
    fp_rec_paymenttransaction.processingtimestamp := null;
    fp_rec_paymenttransaction.processinguser_id   := null;
    fp_rec_paymenttransaction.artransaction_id    := null;
    fp_rec_paymenttransaction.systemuser_id       := gv_systemuserid;
    fp_rec_paymenttransaction.timestamp           := sysdate;
    begin
      --get customer link id
      gv_message := 'get customer link id for invoice number, payment reference ' ||
                      fp_rec_paymenttransaction.reference;
      select a.billtocustomer_link_id, c.defaultbusinessunit_id
        into fp_rec_paymenttransaction.customer_link_id,
             fp_rec_paymenttransaction.businessunit_id
        from artransaction a, customer c
       where a.invoicenumber =
             to_number(fp_rec_paymenttransaction.reference)
         and a.billtocustomer_link_id = c.customer_id
         and rownum = 1
       order by a.artransaction_id desc;
       --fill status
      fp_rec_paymenttransaction.status        := 0;
      fp_rec_paymenttransaction.messagenumber := 0;
      fp_rec_paymenttransaction.currency_id   := get_cust_currency(fp_rec_paymenttransaction.customer_link_id);
    exception
      when others then
         begin
            --errors fill with error=status 2
            fp_rec_paymenttransaction.customer_link_id := null;
            fp_rec_paymenttransaction.businessunit_id  := null;
            fp_rec_paymenttransaction.status           := 2;
            fp_rec_paymenttransaction.messagenumber    := 1;
            fp_rec_paymenttransaction.currency_id      := null;
            --write log
            gv_message := 'Unknown payments, payment could not be linked to customer payment reference ' ||
                          fp_rec_paymenttransaction.reference;
            write_log(2);
         end;
    end;
    --create paymenttransaction
    gv_message := 'insert into paymenttransaction payment reference ' ||
                  fp_rec_paymenttransaction.reference;
    insert into paymenttransaction values fp_rec_paymenttransaction;
    return true;
  exception
    when others then
      begin
        gv_message := 'error during payment ' || fp_rec_paymenttransaction.reference || ' ' ||
                      sqlerrm;
        write_log(3);
        return false;
      end;
  end create_paymenttransaction;

  function create_paymenttransactdetail(fp_rec_paymenttransaction in paymenttransaction%rowtype)
    return boolean is
    lv_rec_paymenttransdetail paymenttransactiondetail%rowtype;
  begin
    --create_paymenttransactiondetail
    gv_message := 'create_paymenttransactdetail';
    --get paymenttransactiondetail id
    select seq_paymenttransactiondetail.nextval
    into   lv_rec_paymenttransdetail.paymenttransactiondetail_id
    from   dual;
    --fill invoicenumber
    gv_message                              := gv_message || ' fill invoice number ' ||
                                               fp_rec_paymenttransaction.reference;
    lv_rec_paymenttransdetail.invoicenumber := to_number(fp_rec_paymenttransaction.reference);
    gv_message                              := 'create_paymenttransactdetail';
    --fill other fields
    lv_rec_paymenttransdetail.paymenttransaction_id := fp_rec_paymenttransaction.paymenttransaction_id;
    lv_rec_paymenttransdetail.detailreference       := fp_rec_paymenttransaction.reference;
    lv_rec_paymenttransdetail.grossamount           := fp_rec_paymenttransaction.amount;
    lv_rec_paymenttransdetail.discountamount        := 0;
    lv_rec_paymenttransdetail.systemuser_id         := gv_systemuserid;
    lv_rec_paymenttransdetail.timestamp             := sysdate;
    lv_rec_paymenttransdetail.artransaction_id      := null;
    lv_rec_paymenttransdetail.messagenumber         := 0;
    lv_rec_paymenttransdetail.discountamount        := 0;
    --create record
    insert into paymenttransactiondetail values lv_rec_paymenttransdetail;
    return true;
  exception
    when others then
      begin
        gv_message := 'error during payment ' || fp_rec_paymenttransaction.reference || ' ' ||
                      sqlerrm;
        write_log(3);
        return false;
      end;
  end create_paymenttransactdetail;

begin
  initialize;
exception
  when e_user_exception_error then
    begin
      write_log(3);
      end_log;
    end;
  when no_data_found then
    begin
      gv_message := 'No data found ' || gv_message;
      write_log(3);
      end_log;
    end;
  when others then
    begin
      write_log(3);
      gv_message := sqlerrm;
      write_log(5);
      end_log;
    end;
end importpayments;
/
create or replace PACKAGE PACK_ABSSOLUTEVERSION is

  function GetShortDatabaseVersion return varchar2;
  PRAGMA RESTRICT_REFERENCES(GetShortDatabaseVersion, WNDS, WNPS);

  function GetCustomerCode return varchar2;
  PRAGMA RESTRICT_REFERENCES(GetCustomerCode, WNDS, WNPS);

end PACK_ABSSOLUTEVERSION;
/
create or replace PACKAGE BODY PACK_ABSSOLUTEVERSION is

  function GetShortDatabaseVersion return varchar2 is
    major varchar2(30);
    minor varchar2(30);
    micro varchar2(30);
  begin
    for vCursor in (select column_name
                      from user_tab_columns
                     where table_name like 'ABSSOLUTEDBVERSION'
                     order by column_id) loop
      if substr(vCursor.column_name, 0, 6) = 'MAJOR_' then
        major := substr(vCursor.column_name, 7);
      end if;
      if substr(vCursor.column_name, 0, 6) = 'MINOR_' then
        minor := substr(vCursor.column_name, 7);
      end if;
      if substr(vCursor.column_name, 0, 6) = 'MICRO_' then
        micro := substr(vCursor.column_name, 7);
      end if;
    end loop;

    if length(major) < 2 then
      major := '0' || major;
    end if;
    return major || '.' || minor || '.' || micro;

  end;

  function GetCustomerCode return varchar2 is
    result databasesettings.code%type;
  begin
    select code into result from databasesettings;
    return result;
  exception
    when others then
      return '?';
  end;

end PACK_ABSSOLUTEVERSION;
/
create or replace package PACK_ABS_DBM is

  -- Author  : CATALIN
  -- Created : 15/10/2002 2:37:27 PM
  -- Purpose : Database  management tools
  -- Version : 2.4
  -- Update  : 25/01/2009 Export views in right sequence
  --           ,,    ,,   Remove obsolete procedures
  --           ,,    ,,   Remove warnings
  -- 08/07/2022 ABS-127736 Prevent auto deployment of view erp_transaction_log
  -- 19/03/2024 ABS-161456 Check pack_startup - invalid at update to 9.07.00
  -- 09/08/2024 ABS-167958 PACK_ABSDBM increase variables length
  -- 12/09/2024 ABS-168938 PACK_ABSDBENCRYPTs appeared on 9.07.02 and higher Structure databases
  -- 25/09/2024 ABS-167958 PACK_ABSDBM increase variables length
  -- 20/12/2024 ABSN-170 [QF][TestCreateEmptyDBScript] Error in createdatabase-PlsqlDbObjects log file when creating the database with empty database script
  -- 23/01/2024 ABSN-170 [QF][TestCreateEmptyDBScript] Error in createdatabase-PlsqlDbObjects log file when creating the database with empty database script
  -- 27/01/2024 ABSN-170 [QF][TestCreateEmptyDBScript] Error in createdatabase-PlsqlDbObjects log file when creating the database with empty database script

 UTLDIR varchar2 (40) := 'e:\output'; -- please see ABS-92804 variable needs the name of an existing oracle directory
 CREATE_DROP_SCRIPT integer := 0;

 procedure export_conversion(fp_exportfile out clob);

 procedure CFvExportObjectsOfType (
               FPsFilename          VARCHAR2,
               FPsUserName          VARCHAR2,
               FPbDropScript        integer,
               FPsObjectsType       VARCHAR2,
               FPbAllObjects        boolean default true);

  procedure CFvExportViews (
               FPsFilename          VARCHAR2);

  procedure CFvExportTriggers (
               FPsFilename          VARCHAR2,
               FPsUserName          VARCHAR2,
               FPbDropScript        integer );

  procedure CFvExportAllObjects(FPsDirName varchar2 default UTLDIR, revNr varchar2);
  procedure CFvExportAllViews(FPsDirName varchar2 default UTLDIR);
  procedure CFvExport_ImportPackages(FPsDirName varchar2 default UTLDIR);

  -----------------------------------------------------------------------------
  function exportViewsToClob return clob;
  function exportTriggersToClob return clob;
  function exportProceduresToClob return clob;
  function exportFunctionsToClob return clob;
  function exportPackagesToClob return clob;
  function exportImportPackagesToClob return clob;

  -----------------------------------------------------------------------------

  procedure createPublicSynonyms;
  procedure grantToAbssoluteSelectTables;
  procedure grantToAbssoluteSelectViews;

  ----------------------------------------------------------------------------

  procedure displayUserVersion;

  ----------------------------------------------------------------------------

  procedure ExportCheckConstraints;

  ----------------------------------------------------------------------------

  procedure CreateMyConstraintsAndIndexes;

  ----------------------------------------------------------------------------

end PACK_ABS_DBM;
/
create or replace package body PACK_ABS_DBM is
gv_cr varchar2(2) := chr(13) || chr(10);
gv_content clob;

  procedure writeToClob(fp_text in varchar2) is
  begin
    gv_content := gv_content || fp_text;
  end writeToClob;

  procedure writeToClobWithNewLine(fp_text in varchar2) is
  begin
    gv_content := gv_content || fp_text || gv_cr;
  end writeToClobWithNewLine;

  procedure exportHeaderToClob(FPsObjectsType varchar2) is
  begin
    writeToClobWithNewLine(' ');
    writeToClobWithNewLine('/*********************************************\');
    writeToClobWithNewLine('*   ABSSOLUTE Oracle Objects                  *');
    writeToClobWithNewLine('*                                             *');
    writeToClobWithNewLine('*   Objects:           ' || rpad(FPsObjectsType, 23, ' ') || '*');
    writeToClobWithNewLine('*   Database version:  ' || rpad(pack_abssoluteversion.GetShortDatabaseVersion, 23, ' ') || '*');
    writeToClobWithNewLine('*   Date:              ' || rpad(to_char(sysdate, 'DD-MON-YYYY'), 23, ' ') || '*');
    writeToClobWithNewLine('\*********************************************/');
    writeToClobWithNewLine(' ');
    writeToClobWithNewLine('set define off ');
    writeToClobWithNewLine(' ');
  end exportHeaderToClob;

  procedure export_header(FPsObjectsType varchar2, FPSqlFile UTL_FILE.FILE_TYPE) is
  begin
    UTL_FILE.PUT_LINE(FPSqlFile, ' ');
    UTL_FILE.PUT_LINE(FPSqlFile, '/*********************************************\');
    UTL_FILE.PUT_LINE(FPSqlFile, '*   ABSSOLUTE Oracle Objects                  *');
    UTL_FILE.PUT_LINE(FPSqlFile, '*                                             *');
    UTL_FILE.PUT_LINE(FPSqlFile, '*   Objects:           ' || rpad(FPsObjectsType, 23, ' ') || '*');
    UTL_FILE.PUT_LINE(FPSqlFile,
                      '*   Database version:  ' ||
                       rpad(pack_abssoluteversion.GetShortDatabaseVersion, 23, ' ') || '*');
    UTL_FILE.PUT_LINE(FPSqlFile,
                      '*   Date:              ' || rpad(to_char(sysdate, 'DD-MON-YYYY'), 23, ' ') || '*');
    UTL_FILE.PUT_LINE(FPSqlFile, '\*********************************************/');
    UTL_FILE.PUT_LINE(FPSqlFile, ' ');
    UTL_FILE.PUT_LINE(FPSqlFile, 'set define off ');
    UTL_FILE.PUT_LINE(FPSqlFile, ' ');
  end export_header;

  procedure export_conversion(fp_exportfile out clob) is
    /*export_conversion version 1.0*/
    gv_cr varchar2(2) := chr(13) || chr(10);

    procedure write_export(fp_text in varchar2) is
    begin
      fp_exportfile := fp_exportfile || fp_text;
    end write_export;

    procedure write_header is
    begin
      --write_header
      write_export(gv_cr);
      write_export('/*********************************************\' || gv_cr);
      write_export('*   Objects:           CONVERSION PACKAGES    *' || gv_cr);
      write_export('*   Database version:  ' ||
                   rpad(pack_abssoluteversion.getshortdatabaseversion, 23, ' ') || '*' || gv_cr);
      write_export('*   Date:              ' || rpad(to_char(sysdate, 'DD-MON-YYYY'), 23, ' ') || '*' ||
                   gv_cr);
      write_export('\*********************************************/' || gv_cr);
      write_export('set define off' || gv_cr);
    end write_header;

    procedure write_footer is
    begin
      --write_footer
      write_export('set define on' || gv_cr || '/');
    end write_footer;
  begin
    write_header;
    for x in (select c.object_name, c.object_type
              from   user_objects c
              where  substr(c.object_name, 0, 11) = 'PACK_IMPORT'
              order  by c.object_name, c.object_type) loop
      begin
        write_export('create or replace ');
        for r_text in (select y.text
                       from   sys.all_source y
                       where  y.owner = upper(user)
                       and    y.name = upper(x.object_name)
                       and    y.type = upper(x.object_type)
                       order  by y.line) loop
          write_export(r_text.text);
        end loop;
        write_export(gv_cr || '/' || gv_cr);
      end;
    end loop; --x
    write_footer;
  end export_conversion;


 procedure CFvExport_ImportPackages(FPsDirName varchar2 default UTLDIR) is
    plsqlVersion            VARCHAR2(30):=pack_abssoluteversion.GetShortDatabaseVersion;
 begin
      UTLDIR := FPsDirName;
      CFvExportObjectsOfType('Plsql_import_packages_'||plsqlVersion||'.sql',user,CREATE_DROP_SCRIPT,'PACKAGE%', false);
      --CFvExportObjectsOfType('Plsql_import_packages_'||plsqlVersion||'.sql','ABSSOLUTE',0,CREATE_DROP_SCRIPT,0,'PACKAGE%', false);
 end;

 procedure CFvExportAllObjects(FPsDirName varchar2 default UTLDIR, revNr varchar2) is
    --plsqlVersion            VARCHAR2(30):=pack_abssoluteversion.getversion();
    plsqlVersion varchar2(30) := substr((pack_abssoluteversion.GetShortDatabaseVersion ||'.' || revNr),2);
 begin
      UTLDIR := FPsDirName;
     -- CFvExportObjectsOfType('Plsql_types_'||plsqlVersion||'.sql',user,CREATE_DROP_SCRIPT,'TYPE%');
      CFvExportObjectsOfType('Plsql_packages_'||plsqlVersion||'.sql',user,CREATE_DROP_SCRIPT,'PACKAGE%');
      CFvExportObjectsOfType('Plsql_functions_'||plsqlVersion||'.sql',user,CREATE_DROP_SCRIPT,'FUNCTION');
      CFvExportObjectsOfType('Plsql_procedures_'||plsqlVersion||'.sql',user,CREATE_DROP_SCRIPT,'PROCEDURE');
      CFvExportViews('Plsql_views_'||plsqlVersion||'.sql');
      CFvExportTriggers('Plsql_triggers_'||plsqlVersion||'.sql',user,CREATE_DROP_SCRIPT);
      return;
 end;

 procedure CFvExportAllViews(FPsDirName varchar2 default UTLDIR) is
    plsqlVersion            VARCHAR2(30):=pack_abssoluteversion.GetShortDatabaseVersion();
 begin
      UTLDIR := FPsDirName;
      CFvExportViews('Plsql_views_'||plsqlVersion||'.sql');
      return;
 end;

  function exportObjectsOfTypeToClob(FPsObjectsType varchar2) return clob is
    /* objects */
    cursor c_objects is
      select distinct name, type
        from user_source
       where type like fpsobjectstype||'%'
         and upper(name) <> upper('PACK_EXPORT_EMPTYDBSCRIPT')
         and upper(name) <> upper('PACK_SCRIPT')
         and upper(name) <> upper('PACK_STARTUP')
         and upper(name) NOT like upper('PACK_IMPORT%')
         and upper(name) <> upper('PACK_ABSDBENCRYPT')
         and upper(name) <> upper('PACK_ABSDBENCRYPT_CUSTOMER')
       order by name, type;
    cursor c_text(obj_name  in varchar2,
                  obj_type  in varchar2) is
      select text
        from user_source
       where name = upper(obj_name)
         and type = upper(obj_type)
       order by line;
  begin
    exportHeaderToClob(FPsObjectsType || 'S');
    for r_objects in c_objects
    loop
      writeToClob('create or replace ');
      for r_text in c_text(r_objects.name, r_objects.type)
      loop
        writeToClob(r_text.text);
      end loop;
      writeToClobWithNewLine('');
      writeToClobWithNewLine('/');
    end loop;
    writeToClobWithNewLine('set define on ');
    writeToClobWithNewLine('/');
    dbms_output.put_line(FPsObjectsType || ' exported succesfuly! ');
    return gv_content;
  exception
    when others then
      dbms_output.put_line('Error: An unhandled exception occured ');
      raise;
  end exportObjectsOfTypeToClob;
   function exportProceduresToClob return clob is
   begin
     return exportObjectsOfTypeToClob('PROCEDURE');
   end exportProceduresToClob;

   function exportFunctionsToClob return clob is
   begin
     return exportObjectsOfTypeToClob('FUNCTION');
   end exportFunctionsToClob;

   function exportPackagesToClob return clob is
   begin
     return exportObjectsOfTypeToClob('PACKAGE');
   end exportPackagesToClob;
   function exportImportPackagesToClob return clob is
     lv_conversionpack clob;
   begin
     export_conversion(lv_conversionpack);
     return lv_conversionpack;
   end exportImportPackagesToClob;

 procedure CFvExportObjectsOfType (
               FPsFilename          VARCHAR2, -- file to export objects to
               FPsUserName          VARCHAR2, -- owner of the objects
               FPbDropScript        integer,  -- create  drop script
               FPsObjectsType       VARCHAR2, -- objects type ( 'PROCEDURE','FUNCTION','PACKAGE%')
               FPbAllObjects        boolean default true) is

  noOfChars NUMBER;
  fSqlFile UTL_FILE.FILE_TYPE;
  sObjectsType                VARCHAR2(30);
  /* objects */
  CURSOR c_objects IS
     SELECT distinct owner, name, type
     FROM   sys.all_source
     WHERE  UPPER(owner) = UPPER(FPsUserName)
     and type like FPsObjectsType
     and UPPER(name) <> UPPER('PACK_EXPORT_EMPTYDBSCRIPT')
     and UPPER(name) <> UPPER('PACK_SCRIPT')
	 and UPPER(name) <> UPPER('PACK_STARTUP')
   and upper(name) <> upper('PACK_ABSDBENCRYPT')
   and upper(name) <> upper('PACK_ABSDBENCRYPT_CUSTOMER')
	 ORDER BY name, type;

  /* Text */
  CURSOR c_text (obj_owner in varchar2, obj_name in varchar2, obj_type in varchar2) IS
     SELECT text
     FROM   sys.all_source
     WHERE  owner = UPPER(obj_owner)
     AND    name  = UPPER(obj_name)
     AND    type  = UPPER(obj_type)
     ORDER BY line;

BEGIN


  fSqlFile := UTL_FILE.FOPEN(UTLDIR, FPsFilename, 'w');

  if FPsObjectsType= 'PROCEDURE' then sObjectsType:='PROCEDURE'; end if;
  if FPsObjectsType= 'FUNCTION' then sObjectsType:='FUNCTION'; end if;
  if FPsObjectsType= 'PACKAGE%' then sObjectsType:='PACKAGE'; end if;
  --if FPsObjectsType= 'TYPE%' then sObjectsType:='TYPE'; end if;

  noOfChars := 0;
  export_header(sObjectsType || 'S', fSqlFile);

  FOR r_objects IN c_objects LOOP

    if (FPbAllObjects or substr(r_objects.name, 0, 11) = 'PACK_IMPORT') then

      if (FPbDropScript=1 and r_objects.type!='PACKAGE BODY') then
          UTL_FILE.PUT_LINE(fSqlFile, 'drop ' ||sObjectsType || ' ' || r_objects.name );
          UTL_FILE.PUT_LINE(fSqlFile, '/');
      end if;

      UTL_FILE.PUT(fSqlFile, 'create or replace ' );
      UTL_FILE.fflush(fSqlFile);
      noOfChars := 0;
      FOR r_text in c_text (r_objects.owner, r_objects.name, r_objects.type) LOOP
         IF (length(r_text.text) + noOfChars > 30000) THEN
           UTL_FILE.fflush(fSqlFile);
           noOfChars := 0;
         END IF;
         noOfChars := noOfChars + length(r_text.text);
         UTL_FILE.PUT(fSqlFile, r_text.text);
      END LOOP;
      UTL_FILE.NEW_LINE(fSqlFile);
      UTL_FILE.PUT_LINE(fSqlFile, '/');
    end if;

    UTL_FILE.fflush(fSqlFile);
    noOfChars := 0;
  END LOOP;

   UTL_FILE.PUT_LINE(fSqlFile, 'set define on ' );
   UTL_FILE.PUT_LINE(fSqlFile, '/');

  UTL_FILE.FCLOSE(fSqlFile);
  dbms_output.put_line ( sObjectsType || ' exported succesfuly! ');


  EXCEPTION
  WHEN UTL_FILE.WRITE_ERROR THEN
       dbms_output.put_line ('Error: Utl_file.Write Error' );
       dbms_output.put_line ('An operating system error occured during write operation');
       raise;
  WHEN UTL_FILE.READ_ERROR THEN
       dbms_output.put_line ('Error: Utl_file.Read Error ');
       dbms_output.put_line ('An operating system error occured during read operation');
       raise;
  WHEN UTL_FILE.INVALID_FILEHANDLE THEN
       dbms_output.put_line ('Error: Utl_file.Invalid_Filehandle ');
       dbms_output.put_line ('The filehandle was invalid');
       raise;
  WHEN UTL_FILE.INTERNAL_ERROR THEN
       dbms_output.put_line ('Error: Utl_file.Internal Error ');
       dbms_output.put_line ('An unspecified error in PL/SQL occured ');
       raise;
  WHEN OTHERS THEN
       dbms_output.put_line ('Error: An unhandled exception occured ');
       raise;

 end;


 -----------------------------------------------------
 function exportViewsToClob return clob is
   separator           varchar2(10) := '/';
   sqlScriptInsert     varchar2(50) := '';
   sqlScriptUpdate     varchar2(50) := '';
   currentView         user_views.VIEW_NAME%type := '';

    procedure exportoneviewtoclob(fpviewname user_views.view_name%type, fpseparator varchar2) is
      gv_view clob;
    begin
      if fpviewname = 'ERP_TRANSACTION_LOG' then
        begin
          --do not export
          null;
        end;
      elsif fpviewname in ('V_INVOICECLIENT', 'V_INVOICECLIENTLAYOUTCWS', 'V_INVOICEHEADER') then
        begin
          --remove the column list because it is too long
          gv_view    := trim(both chr(10) from replace(rtrim(dbms_metadata.get_ddl('VIEW', fpviewname), chr(10)), ';'));
          gv_content := gv_content || 'CREATE OR REPLACE VIEW ' || fpviewname || ' AS ' || gv_cr ||
                        substr(gv_view, instr(gv_view, '") AS ') + 9) || gv_cr || fpseparator ||
                        gv_cr;
        end;
      else
        begin
          --let Oracle do the whole export
          gv_content := gv_content ||
                        replace(rtrim(dbms_metadata.get_ddl('VIEW', fpviewname), ';'),
                                'CREATE OR REPLACE EDITIONABLE VIEW', 'CREATE OR REPLACE VIEW') ||
                        gv_cr || fpseparator||
                        gv_cr;
        end;
      end if;
    end exportoneviewtoclob;
 begin
  --
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'FORCE', false);
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'SPECIFICATION', true);
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'SEGMENT_ATTRIBUTES', false);
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'EMIT_SCHEMA', false);
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'PRETTY', true);
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'SQLTERMINATOR', true);
  dbms_metadata.set_transform_param(dbms_metadata.session_transform, 'STORAGE', false);
  --
   writeToClobWithNewLine(' ');
   if length(sqlScriptInsert) > 1 then
     writeToClobWithNewLine(sqlScriptInsert || 'Plsql_views' || '''');
     writeToClobWithNewLine(separator);
   end if;
   exportHeaderToClob('VIEWS');
   for x in (select dp.referenced_name viewname
               from user_dependencies dp
              where  dp.type = 'VIEW'
                and dp.referenced_type = 'VIEW'
                and exists (select ud.referenced_name
                       from user_dependencies ud
                      where dp.name = ud.referenced_name
                        and ud.type = 'VIEW')
              group by dp.referenced_name
              order by dp.referenced_name)
   loop
     begin
       currentView :=x.viewname;
       exportOneViewToClob(x.viewname, separator);
     end;
   end loop;
   for x in (select dp.name viewname
               from user_dependencies dp
              where dp.type = 'VIEW'
                and dp.referenced_type = 'VIEW'
                and exists (select ud.referenced_name
                       from user_dependencies ud
                      where dp.name = ud.referenced_name
                        and ud.type = 'VIEW')
              group by dp.name
              order by dp.name)
   loop
     begin
       currentView :=x.viewname;
       exportOneViewToClob(x.viewname, separator);
     end;
   end loop;
   for y in (select distinct dp3.referenced_name viewname
               from user_dependencies dp3
              where dp3.type = 'VIEW'
                and dp3.referenced_type = 'VIEW'
                and (select count(*)
                       from user_dependencies dp
                      inner join user_dependencies ud on ud.referenced_name = dp.name
                                                    and ud.referenced_type = dp.referenced_type
                                                    and ud.type = dp.type
                      where dp.type = 'VIEW'
                        and dp.referenced_type = 'VIEW'
                        and dp.referenced_name = dp3.referenced_name) = 0
                and (select count(*)
                       from user_dependencies dp
                      inner join user_dependencies ud on ud.referenced_name = dp.name
                                                    and ud.referenced_type = dp.referenced_type
                                                    and ud.type = dp.type
                      where dp.type = 'VIEW'
                        and dp.referenced_type = 'VIEW'
                        and dp.name = dp3.referenced_name) = 0
              order by dp3.referenced_name)
   loop
     begin
       currentView :=y.viewname;
       exportOneViewToClob(y.viewname, separator);
     end;
   end loop;
   for y in (select distinct dp3.name viewname
               from user_dependencies dp3
              where dp3.type = 'VIEW'
                and dp3.referenced_type = 'VIEW'
                and (select count(*)
                       from user_dependencies dp
                      inner join user_dependencies ud on ud.referenced_name = dp.name
                                                    and ud.referenced_type = dp.referenced_type
                                                    and ud.type = dp.type
                      where dp.type = 'VIEW'
                        and dp.referenced_type = 'VIEW'
                        and dp.referenced_name = dp3.name) = 0
                and (select count(*)
                       from user_dependencies dp
                      inner join user_dependencies ud on ud.referenced_name = dp.name
                                                    and ud.referenced_type = dp.referenced_type
                                                    and ud.type = dp.type
                      where dp.type = 'VIEW'
                        and dp.referenced_type = 'VIEW'
                        and dp.name = dp3.name) = 0
              order by dp3.name)
   loop
     begin
       currentView :=y.viewname;
       exportOneViewToClob(y.viewname, separator);
     end;
   end loop;
   for z in (select v.view_name viewname
               from user_views v
              where (select count(*)
                       from user_dependencies dp3
                      where dp3.referenced_name = v.view_name
                        and dp3.type = 'VIEW'
                        and dp3.referenced_type = 'VIEW') = 0
                and (select count(*)
                       from user_dependencies dp3
                      where dp3.name = v.view_name
                        and dp3.type = 'VIEW'
                        and dp3.referenced_type = 'VIEW') = 0
              order by v.view_name)
   loop
     begin
       currentView :=z.viewname;
       exportOneViewToClob(z.viewname, separator);
     end;
   end loop;
   if length(sqlScriptUpdate) > 1 then
     writeToClobWithNewLine(' ');
     writeToClobWithNewLine(sqlScriptUpdate || 'Plsql_views' || '''');
     writeToClobWithNewLine(separator);
   end if;
   dbms_output.put_line('Views exported succesfuly! ');
   return gv_content;
 exception
   when others then
     dbms_output.put_line('Error at '||currentView||': An unhandled exception occured '|| sqlerrm);
     raise;
 end exportViewsToClob;

 procedure cfvexportviews(fpsfilename varchar2) is
 begin
   dbms_xslprocessor.clob2file(flocation => utldir, fname => fpsfilename, cl => exportviewstoclob, csid => 0);
 end cfvexportviews;

 --------------------------------------------------------
 function exportTriggersToClob return clob is
   cursor c_trig is
     select owner, trigger_name, description, when_clause, trigger_body
       from sys.all_triggers
      where owner = user
        and trigger_name not like 'TRG\_A\_%' escape '\'
        and table_name not like q'[I\_%]' escape '\'
      order by trigger_name;
 begin
   exportHeaderToClob('TRIGGERS');
   for r_trig in c_trig
   loop
     writeToClob('create or replace trigger ');
     writeToClob(substr(r_trig.description, instr(r_trig.description, '.') + 1));
     if (trim(r_trig.when_clause) is not null) then
       writeToClobWithNewLine('WHEN (' || r_trig.when_clause || ')');
     end if;
     writeToClobWithNewLine(r_trig.trigger_body);
     writeToClobWithNewLine('/');
   end loop;
   dbms_output.put_line('Triggers exported succesfuly! ');
   return gv_content;
 exception
   when others then
     dbms_output.put_line('Error: An unhandled exception occured ');
     raise;
 end exportTriggersToClob;

  procedure CFvExportTriggers (
               FPsFilename          VARCHAR2,
               FPsUserName          VARCHAR2,
               FPbDropScript        integer) is

  fSqlFile    utl_file.file_type;
   /* Triggers */
  CURSOR c_trig IS
     SELECT owner, trigger_name, description, when_clause, trigger_body
     FROM   sys.all_triggers
     WHERE  owner = UPPER(FPsUserName)
     and trigger_name not like 'TRG\_A\_%' escape '\'
     and table_name not like q'[I\_%]' escape '\'
     ORDER BY  trigger_name;

 begin

  fSqlFile := UTL_FILE.FOPEN(UTLDIR, FPsFilename, 'w');

  export_header('TRIGGERS', fSqlFile);

  FOR r_trig IN c_trig LOOP
   if FPbDropScript=1 then
        UTL_FILE.PUT_LINE(fSqlFile, 'drop trigger ' || r_trig.trigger_name );
        UTL_FILE.PUT_LINE(fSqlFile, '/');
    end if;
    UTL_FILE.PUT(fSqlFile, 'create or replace trigger ' );
    UTL_FILE.PUT_LINE(fSqlFile, substr(r_trig.description, instr(r_trig.description, '.') + 1));
    if (trim(r_trig.when_clause) is not null) then
       UTL_FILE.PUT_LINE(fSqlFile, 'WHEN (' || r_trig.when_clause || ')');
    end if;
    UTL_FILE.PUT_LINE(fSqlFile, r_trig.trigger_body);
    UTL_FILE.PUT_LINE(fSqlFile, '/');
  END LOOP;

  UTL_FILE.FCLOSE(fSqlFile);
  dbms_output.put_line ( 'Triggers exported succesfuly! ');

  EXCEPTION
  WHEN UTL_FILE.WRITE_ERROR THEN
       dbms_output.put_line ('Error: Utl_file.Write Error' );
       dbms_output.put_line ('An operating system error occured during write operation');
       raise;
  WHEN UTL_FILE.READ_ERROR THEN
       dbms_output.put_line ('Error: Utl_file.Read Error ');
       dbms_output.put_line ('An operating system error occured during read operation');
       raise;
  WHEN UTL_FILE.INVALID_FILEHANDLE THEN
       dbms_output.put_line ('Error: Utl_file.Invalid_Filehandle ');
       dbms_output.put_line ('The filehandle was invalid');
       raise;
  WHEN UTL_FILE.INTERNAL_ERROR THEN
       dbms_output.put_line ('Error: Utl_file.Internal Error ');
       dbms_output.put_line ('An unspecified error in PL/SQL occured ');
       raise;
  WHEN OTHERS THEN
       dbms_output.put_line ('Error: An unhandled exception occured ');
       raise;
 end;


----------------------------------------------------------------------------

procedure createPublicSynonyms is
  userName  varchar2(30);
begin
  select user into userName from dual;
  if userName = 'ABSSOLUTE' then
    for vCursor in (select table_name as objectName from user_tables
                    union all
                    select view_name as objectName from user_views) loop
      begin
        execute immediate 'create public synonym "'||vCursor.objectName||'" for "'||vCursor.objectName ||'"';
      exception when others then
        if sqlcode = -955 then null; else raise; end if;
      end;
    end loop;
  end if;
end;

procedure grantToAbssoluteSelectTables is
begin
  for vcursor in (select ut.table_name
                    from user_tables ut
                   where ut.table_name not in (select utp.table_name
                                                 from user_tab_privs utp
                                                where upper(utp.grantee) = 'ABSSOLUTE_SELECT_TABLES'
                                                  and utp.privilege = 'SELECT'))
  loop
    begin
      execute immediate 'grant select on "' || vcursor.table_name || '" to abssolute_select_tables';
    exception
      when others then
        null;
    end;
  end loop;
  commit;
end;

procedure grantToAbssoluteSelectViews is
begin
  for vCursor in (select uv.view_name
  from user_views uv
 where uv.view_name not in (select utp.table_name
                              from user_tab_privs utp
                             where upper(utp.grantee) = 'ABSSOLUTE_SELECT_VIEWS'
                               and utp.privilege = 'SELECT')) loop
    begin
      execute immediate 'grant select on "'||vCursor.view_name||'" to abssolute_select_views';
    exception when others then null;
    end;
  end loop;
  commit;
end;

----------------------------------------------------------------------------

procedure displayUserVersion is
  version varchar2(20);
begin
  for c in (select username, created from all_users order by username) loop
    begin
      execute immediate 'select '||c.username||'.pack_abssoluteversion.getshortdatabaseversion() from dual' into version;
      dbms_output.put_line(rpad(c.username, 30)||rpad(version, 12)||c.created);
    exception when others then null;
    end;
  end loop;
end;

----------------------------------------------------------------------------

procedure ExportCheckConstraints is
  hExportFile       utl_file.file_type;
  line              varchar2(500);
begin

  hExportFile:=utl_file.fopen(UTLDIR,
        'CheckConstraints_'||pack_abssoluteversion.getshortdatabaseversion()||'.sql', 'w');
  UTL_FILE.PUT_LINE(hExportFile, 'set serveroutput on;');
  UTL_FILE.PUT_LINE(hExportFile, 'declare');
  UTL_FILE.PUT_LINE(hExportFile, 'begin');
  UTL_FILE.PUT_LINE(hExportFile, '  for vCursor in (select a.table_name, b.constraint_name from user_constraints a, loader_constraint_info b');
  UTL_FILE.PUT_LINE(hExportFile, '                  where a.constraint_name = b.constraint_name and a.table_name = b.table_name');
  UTL_FILE.PUT_LINE(hExportFile, '                    and a.constraint_type = ''C'' and b.type = 1 and a.owner = b.owner) loop');
  UTL_FILE.PUT_LINE(hExportFile, '    execute immediate ''alter table ''||vCursor.table_name||'' drop constraint ''||vCursor.constraint_name;');
  UTL_FILE.PUT_LINE(hExportFile, '  end loop;');
  UTL_FILE.PUT_LINE(hExportFile, 'exception when others then');
  UTL_FILE.PUT_LINE(hExportFile, '  dbms_output.put_line(sqlerrm);');
  UTL_FILE.PUT_LINE(hExportFile, 'end;');
  UTL_FILE.PUT_LINE(hExportFile, '/');

  for vCursor in (select a.table_name, b.constraint_name, a.search_condition
                  from user_constraints a, loader_constraint_info b
                  where a.constraint_name = b.constraint_name and a.table_name = b.table_name
                    and a.constraint_type = 'C' and b.type = 1 and a.owner = b.owner) loop
    line:='ALTER TABLE '||vCursor.table_name||' ADD (CONSTRAINT '||vCursor.constraint_name||' CHECK ('||vCursor.search_condition||'));';
    UTL_FILE.PUT_LINE(hExportFile, line);
  end loop;

  utl_file.fclose(hExportFile);

exception
  when utl_file.invalid_path then
      dbms_output.put_line('Fail to open file check_constraints.sql - invalid path.');
      raise;
  when utl_file.invalid_mode then
      dbms_output.put_line('Fail to open file check_constraints.sql - invalid mode.');
      raise;
  when others then
      dbms_output.put_line(sqlcode||' '||substr(sqlerrm, 1, 512));
      rollback;
      if utl_file.is_open(hExportFile) then
        UTL_FILE.PUT_LINE(hExportFile, sqlcode||' '||substr(sqlerrm, 1, 512));
        utl_file.fclose(hExportFile);
      end if;
      raise;
end;


----------------------------------------------------------------------------
procedure CreateMyConstraintsAndIndexes is
  userName varchar2(30);
begin
  select user into userName from dual;
  if userName = 'ABSSOLUTE' then return; end if;
  -- user_constraints
  begin
    execute immediate 'drop table my_constraints';
  exception when others then null;
  end;
  begin
    execute immediate 'create table my_constraints as ' ||
                      '  select c.constraint_name, c.constraint_type, c.table_name, ' ||
                      '    c.r_constraint_name, c.delete_rule, c.generated ' ||
                      ' from user_constraints c';
  exception when others then null;
  end;
  -- user_cons_columns
  begin
    execute immediate 'drop table my_cons_columns';
  exception when others then null;
  end;
  begin
    execute immediate 'create table my_cons_columns as ' ||
                      '  select c.constraint_name, c.table_name, c.column_name, c.position ' ||
                      '  from user_cons_columns c';
  exception when others then null;
  end;
  -- user_indexes
  begin
    execute immediate 'drop table my_indexes';
  exception when others then null;
  end;
  begin
    execute immediate 'create table my_indexes as ' ||
                      ' select i.index_name, i.index_type, i.table_name, i.uniqueness ' ||
                      ' from user_indexes i';
  exception when others then null;
  end;
  -- user_ind_columns
  begin
    execute immediate 'drop table my_ind_columns';
  exception when others then null;
  end;
  begin
    execute immediate 'create table my_ind_columns as ' ||
                      ' select i.index_name, i.table_name, i.column_name, i.column_position ' ||
                      ' from user_ind_columns i';
  exception when others then null;
  end;

end;

end PACK_ABS_DBM;
/
create or replace PACKAGE "PACK_ADVANCEDPICKING" is

  /******************************************************************************\
  * -- Author   : RVI                                                            *
  * -- Created  : 04-02-2013 .. 19-05-2015   v A58                               *
  *    Updated  : 26-03-2013 Use exact order priority in candidate search        *
  *    Updated  : 28-03-2013 Check for previous picklists when validating pool   *
  *    Updated  : 02-04-2013 Reference workorder may exceed max batch qty        *
  *    Updated  : 08-04-2013 Corrected check on mobile device, check on prio     *
  *    Updated  : 10-04-2013 Set PickListPrinted for Pickist and WorkOrder       *
  *    Updated  : 23-08-2013 Corrected incorrect check on availabe stock qty     *
  *                          for unique items while non-unique reserved          *                                                              *
  *    Updated  : 13-01-2014 Corrected incorrect check on availabe stock qty     *
  *                          for unique items while unique reserved in methods   *
  *                          select_first_wo, f_wo_has_sufficient_stock,         *
  *                          determine_item_distr_for_cand                       *
  *    Updated  : 15-01-2014 Improved check on max batch qty in select_first_wo  *
  *    Updated  : 10-02-2014 Added check on sufficient stock in select_first_wo  *
  *                          Improved check in f_wo_has_sufficient_stock         *
  *    Updated  : 11-02-2014 Added check on creation of pick list lines when     *
  *                          no stock was found in the end                       *
  *    Updated  : 24-02-2014 Added check if forced stock count is required on    *
  *                          PDA. If required then mark pick location as to be   *
  *                          on pick list.                                       *
  *    Updated  : 30-04-2014 Corrected incorrect check on allow_phased_delivery  *
  *                          in method select_first_wo                           *
  *    Updated  : 22-05-2014 Forgot to end the loop when checking for available  *
  *                          stock in method select_first_wo in case sufficient  *
  *                          items were on stock and allow_phased_delivery = N   *
  *    Updated  : 26-05-2014 Added mechanism to avoid that multiple identical    *
  *                          pick lists will be created for a work order that    *
  *                          has allow_phased_delivery = Y and for which no      *
  *                          items have been picked yet                          *
  *    Updated  : 03-06-2014 Changed cursor in validate_pickingpool to make sure *
  *                          sure that also general pool workorders are selected *
  *    Updated  : 19-06-2014 Changed returned error codes for the procedure      *
  *                          lock_for_picklist_generation in case it fails       *
  *    Updated  : 08-09-2014 Changed cursor in determine_item_distr_for_cand for *
  *                          testing result of not_confirmed_picklists_exists,   *
  *                          test for value 0 instead of null to match function  *
  *    Updated  : 07-01-2015 Changed function f_wo_has_sufficient_stock to cover *
  *                          situation that cursor returns no lines. Correct the *
  *                          qty to pick for pick list lines in case less can be *
  *                          picked than requested and partial delivery allowed  *
  *                          via new procedure recalc_lines_for_picklst          *
  *    Updated  : 14-01-2015 Changed checks on maximum batch size. When looking  *
  *                          for first_wo and allow_phased_delivery = N then     *
  *                          select wo although batch size will be exceeded.     *
  *                          After selecting candidate wo that has allow_phased  *
  *                          delivery = Y and a surplus is determined for stock  *
  *                          then wo should be all together on next pick list    *
  *                          and current pick list is considered closed          *
  *    Updated  : 15-01-2015 Several changes regarding maximum number of items   *
  *                          on pick list in several methods                     *
  *    Updated  : 02-03-2015 Changed procedures recalc_lines_for_picklist,       *
  *                          create_picklist_lines, create_optimized_picklist    *
  *                          select_first_wo, find_prio1_same_awopc,             *
  *                          find_prio2_contains_part_awopc,                     *
  *                          find_prio3_part_awopc_and_new,                      *
  *                          find_prio4_no_part_awopc                            *
  *    Updated  : 03-03-2015 Added function f_wo_has_items_to_pick, changed      *
  *                          procedure select_first_wo                           *
  *    Updated  : 04-03-2015 Changed procedures determine_item_distr_for_cand,   *
  *                          determine_item_distr_for_wo, create_picklist_lines  *
  *    Updated  : 05-03-2015 Changed procedures validate_pickingpool,            *
  *                          select_first_wo, create_picklist_lines,             *
  *                          determine_item_distr_for_wo, f_wo_has_items_to_pick *
  *    Updated  : 06-03-2015 Changed procedures validate_pickingpool,            *
  *                          select_first_wo, determine_item_distr_for_wo,       *
  *                          determine_item_distr_for_cand                       *
  *    Updated  : 24-03-2015 Changed functions f_wo_has_sufficient_stock,        *
  *                          f_wo_has_surplus_stock,                             *
  *                          procedures select_first_wo, create_picklist_lines   *
  *    Updated  : 02-04-2015 Changed procedure determine_item_distr_for_wo       *
  *    Updated  : 03-04-2015 Changed procedure create_picklist_lines             *
  *    Updated  : 17-04-2015 Changed procedures select_first_wo,                 *
  *                          create_picklist_lines                               *
  *    Updated  : 20-04-2015 Changed procedures select_first_wo,                 *
  *                          create_picklist_lines. Changed functions            *
  *                          f_wo_has_sufficient_stock, f_wo_has_items_to_pick,  *
  *    Updated  : 23-04-2015 Changed sorting order for procedures find_prio_...  *
  *                          Changed procedure create_optimized_picklist with    *
  *                          respect to log message in case of surplus stock     *
  *    Updated  : 01-05-2015 Changed procedures create_picklist_lines,           *
  *                          determine_item_distr_for_wo,                        *
  *                          create_optimized_picklist                           *
  *    Updated  : 12-05-2015 Changed procedure(s) select_first_wo,               *
  *                          determine_item_distr_for_cand                       *
  *    Updated  : 15-05-2015 Changed procedure(s) create_optimized_picklist,     *
  *                          determine_item_distr_for_cand,                      *
  *                          determine_item_distr_for_wo                         *
  *    Updated  : 19-05-2015 Changed procedure determine_item_distr_for_wo       *
  *                                                                              *
  * -- Purpose  : Create/Update Pick Lists                                       *
  *               Create/Update Pick List Lines                                  *
  *               Create/Update Work Order Lines                                 *
  *               Read workorder lines                                           *
  * -- Messages : 0 ok                                                           *
  *               1 no data found                                                *
  *               2 wrong value used                                             *
  *               3 duplicate value on index                                     *
  *               4 other error message                                          *
  \******************************************************************************/

  procedure create_optimized_picklist(fp_stockroomid    in stockroom.stockroom_id%type,
                                      fp_areacode       in stockroomlocation.areacode%type,
                                      fp_mobiledeviceid in mobiledevice.mobiledevice_id%type,
                                      fp_systemuserid   in systemuser.systemuser_id%type,
                                      fp_picklistid     out picklist.picklist_id%type,
                                      fp_picklistnumber out picklist.picklistnumber%type,
                                      fp_messagenumber  out number);

  function not_confirmed_picklists_exists(fp_workorderid in number,
                                            fp_stockroomid in stockroom.stockroom_id%type,
                                            fp_areacode    in stockroomlocation.areacode%type) return number;

  function f_determine_awopc_string(fp_workorder_id in number,
                                    fp_picklist_id  in number) return varchar2;

  function f_partial_awopc_match(fp_reference_wo_id in number,
                                 fp_candidate_wo_id in number,
                                 fp_picklist_id     in number) return number;

  function f_partial_awopc_match_and_new(fp_reference_wo_id in number,
                                         fp_candidate_wo_id in number,
                                         fp_picklist_id     in number) return number;

END PACK_ADVANCEDPICKING;
/
create or replace PACKAGE BODY "PACK_ADVANCEDPICKING" is
  gv_message                abslog.message%type;
  gv_defaultdate            date := to_date('31-12-2099', 'dd-mm-yyyy');
  gv_picking_userid         number := 0;
  gv_addedtoitempickingpool number := 1;
  gv_maximum_items_to_pick  number := 100;
  gv_lockingdelay           number := 10;
  gv_debuglevel             number := 1;
  gv_plantid                plant.plant_id%type := null;
  gv_plantcode              plant.code%type := null;

  ------------------------------------------------------------------------

  ----- Internal procedures/functions ------------------------------------
  procedure write_log(fp_message  in abslog.message%type,
                      fp_priority in abslog.priority%type default 1) is
  begin
    /*
    Write message in ABSLOG with these priorities
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info
    */
    if ((fp_priority < 5) or (fp_priority = 5 and gv_debuglevel > 5)) then
      abslogwrite.abslog_write(5, 'PACK_ADVANCEDPICKING', gv_plantid, fp_priority, fp_message,
                               coalesce(gv_picking_userid, 0));
    end if;
  end write_log;


  procedure get_plant_info(fp_stockroomid in stockroom.stockroom_id%type,
                           fp_plantid     out plant.plant_id%type,
                           fp_plantcode   out plant.code%type) is
  begin
    select pl.plant_id, pl.code
      into fp_plantid, fp_plantcode
      from stockroom sr, businessunit bu, plant pl
     where bu.businessunit_id = sr.managedbybu_id
       and pl.plant_id = bu.plant_id
       and sr.stockroom_id = fp_stockroomid;
    exception
      when others then
        null;
  end get_plant_info;


  procedure get_businessunit_info(fp_stockroomid      in stockroom.stockroom_id%type,
                                  fp_businessunitid   out businessunit.businessunit_id%type,
                                  fp_businessunitcode out businessunit.code%type) is
  begin
    select bu.businessunit_id, bu.code
      into fp_businessunitid, fp_businessunitcode
      from stockroom sr, businessunit bu
     where bu.businessunit_id = sr.managedbybu_id
       and sr.stockroom_id = fp_stockroomid;
    exception
      when others then
        null;
  end get_businessunit_info;


  procedure get_pickliststatuscode(fp_pickliststatusid in status.status_id%type,
                                   fp_pickliststatus   out status.code%type) is
  begin
    select st.code
    into   fp_pickliststatus
    from   status st
    where  st.statustype = 'PL'
    and    st.status_id = fp_pickliststatusid;
  end get_pickliststatuscode;


  procedure get_pickliststatusid(fp_pickliststatus   in status.code%type,
                               fp_pickliststatusid out status.status_id%type) is
  begin
    select st.status_id
    into   fp_pickliststatusid
    from   status st
    where  st.statustype = 'PL'
    and    st.code = fp_pickliststatus;
  end get_pickliststatusid;


  procedure get_workordernumber(fp_workorderid     in number,
                                fp_workordernumber out number) is
  begin
    select w.workordernumber
    into   fp_workordernumber
    from   workorder w
    where  w.workorder_id = fp_workorderid;
  end get_workordernumber;


  procedure get_allowphasedelivery(fp_workorderid        in number,
                                   fp_allowphasedelivery out workorder.allowphasedelivery%type) is
  begin
    select w.allowphasedelivery
    into   fp_allowphasedelivery
    from   workorder w
    where  w.workorder_id = fp_workorderid;
  end get_allowphasedelivery;


  procedure get_prioritycode(fp_priority     in number,
                             fp_prioritycode out orderpriority.prioritycode%type) is
  begin
    select op.prioritycode
      into fp_prioritycode
      from orderpriority op
     where op.ordertype = 1
       and op.sequencenumber = fp_priority;
  end get_prioritycode;


  function get_systemsetting(fp_stockroom_id      in stockroom.stockroom_id%type,
                             fp_systemsettingname in systemsetting.name%type) return varchar2 is
    lv_systemsettingvalue systemsetting.value%type := null;
  begin
    --get the system setting value and return it
    gv_message := 'getting the system setting value for ' || fp_systemsettingname ||
                  ' for plant of stockroom_id ' || fp_stockroom_id;
    select nvl(trim(st.value), trim(st.factorydefault))
      into   lv_systemsettingvalue
      from systemsetting st, businessunit bu, stockroom s
     where st.plant_id = bu.plant_id
       and bu.businessunit_id = s.managedbybu_id
       and s.stockroom_id = fp_stockroom_id
       and st.name = fp_systemsettingname;
    return lv_systemsettingvalue;
  end get_systemsetting;


  function build_init_query(fp_tablename in varchar2) return varchar2 is
    lv_query varchar2(1000);
  begin
    --init fill the record with all default values
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = fp_tablename
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    return lv_query;
  end build_init_query;


  function set_timerstart return date is
  begin
    return(sysdate);
  end set_timerstart;


  function get_elapsedtime(fp_starttime in date) return number is
    lv_elapsedtime number;
  begin
    lv_elapsedtime := sysdate - fp_starttime + 0.000001;
    lv_elapsedtime := mod(trunc(lv_elapsedtime * 86400),60);
    return(lv_elapsedtime);
  end get_elapsedtime;


  function get_reserved_from_location(fp_picklist_id                 in number,
                                      fp_stockroomlocation_id        in number,
                                      fp_stockreservationpergrade_id in number,
                                      fp_stocktype                   in number) return number is

    cursor get_res is
      select sum(woid.qty_to_pick) reserved
       from workorderitemdistribution woid
      where woid.picklist_id = fp_picklist_id
        and woid.stockreservationpergrade_id = fp_stockreservationpergrade_id
        and woid.stockroomlocation_id = fp_stockroomlocation_id
        and woid.stocktype = fp_stocktype;

    lv_result number := 0;
  begin
    for res_rec in get_res loop
      lv_result := res_rec.reserved;
    end loop;
    return nvl(lv_result,0);
  end get_reserved_from_location;


  function not_confirmed_picklists_exists(fp_workorderid in number,
                                          fp_stockroomid in stockroom.stockroom_id%type,
                                          fp_areacode    in stockroomlocation.areacode%type) return number is

    cursor get_res is
      select min(pl.picklistnumber) first_open_pl_for_wo
        from picklist pl, picklistline pll, picklistlineorigin pllo, workorder wo, workorderline  wol
       where pll.picklist_id = pl.picklist_id
         and pllo.picklistline_id = pll.picklistline_id
         and pllo.baselinetype = wo.origin
         and pllo.baselinetable_link_id = wol.workorderline_id
         and wol.workorder_id = wo.workorder_id
         and wo.workorder_id = fp_workorderid
         and wo.processingstockroom_id = fp_stockroomid
         and pl.processingstockroom_id = fp_stockroomid
         and ((fp_areacode is null) or
             ((fp_areacode is not null) and (pl.areacode = fp_areacode)))
         and pl.status_id in (select status_id
                                from status s
                               where s.statustype = 'PL'
                                 and s.code in ('10', '20'));

    lv_result number := 0;
  begin
    for res_rec in get_res loop
      lv_result := res_rec.first_open_pl_for_wo;
    end loop;
    return nvl(lv_result,0);
  end not_confirmed_picklists_exists;


  procedure clean_temp_tables(fp_picklist_id in number) is
  begin
    gv_message := 'for table WORKORDERPICKSEQUENCE';
    -- Clean up WORKORDERPICKSEQUENCE
    delete
    from workorderpicksequence wps
    where wps.picklist_id = fp_picklist_id;

    gv_message := 'for table WORKORDERNCPICKSEQUENCE';
    -- Clean up WORKORDERNCPICKSEQUENCE
    delete
    from workorderncpicksequence wncps
    where wncps.picklist_id = fp_picklist_id;

    gv_message := 'for table WORKORDERITEMDISTRIBUTION';
    -- Clean up WORKORDERITEMDISTRIBUTION
    delete
    from workorderitemdistribution woid
    where woid.picklist_id = fp_picklist_id;
  exception
    when no_data_found then
      begin
        write_log('Error clean_temp_tables: No_Data_Found ' || gv_message, 3);
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error clean_temp_tables: Others ' || gv_message, 3);
      end;
  end clean_temp_tables;


  procedure validate_parameters(fp_stockroomid    in stockroom.stockroom_id%type,
                                fp_areacode       in stockroomlocation.areacode%type,
                                fp_mobiledeviceid in mobiledevice.mobiledevice_id%type,
                                fp_systemuserid   in systemuser.systemuser_id%type,
                                fp_messagenumber  out number) is
    lv_result        number;
    lv_plantid       number;
    lv_pickingassist mobiledevice.pickingassistant%type;
  begin
    fp_messagenumber := 0;
    -- check for valid stockroom
    if (fp_stockroomid is not null) then
      begin
        gv_message := 'Stockroom not found';
        fp_messagenumber := 8;
        --
        select 1, b.plant_id into lv_result, lv_plantid
          from stockroom s, businessunit b
        where b.businessunit_id = s.managedbybu_id
          and s.stockroom_id = fp_stockroomid;
        --
        if ((lv_result = 1)) then
          gv_message := 'Stockroom found';
          fp_messagenumber := 0;
        end if;
      end;
    else
       gv_message := 'No stockroom defined';
       fp_messagenumber := 8;
    end if;
    -- check for valid area code
    if (fp_messagenumber = 0) and (fp_areacode is not null) then
       begin
          gv_message := 'Area code not found for stockroom';
          fp_messagenumber := 9;
          --
          select 2 into lv_result
            from stockroomlocation sl
           where sl.stockroom_id = fp_stockroomid
             and trim(upper(sl.areacode)) = trim(upper(fp_areacode))
           group by sl.stockroom_id, sl.areacode;
          --
          if (lv_result = 2) then
            gv_message := 'Area code found for stockroom';
            fp_messagenumber := 0;
          end if;
       end;
    end if;
    -- check for valid mobile device
    if (fp_messagenumber = 0) and (fp_mobiledeviceid is not null) then
      begin
        gv_message := 'Mobile device not found';
        fp_messagenumber := 2;
        --
        select 3 into lv_result
          from mobiledevice m
         where m.mobiledevice_id = fp_mobiledeviceid;
        --
        if (lv_result = 3) then
          begin
            -- check if mobile device belongs to plant of stockroom
            gv_message := 'Mobile device does not belong to plant of stockroom';
            fp_messagenumber := 3;
            --
            select 4, m.pickingassistant into lv_result, lv_pickingassist
              from mobiledevice m
             where m.plant_id = lv_plantid
               and m.mobiledevice_id = fp_mobiledeviceid;
            --
            if (lv_result = 4) then
              begin
                -- check if mobile device is setup for picking assistant
                if (lv_pickingassist = 'N') then
                  begin
                    gv_message := 'Mobile device is not configured for running the picking assistant';
                    fp_messagenumber := 4;
                    raise no_data_found;
                  end;
                else
                   begin
                     gv_message := 'Mobile device found';
                     fp_messagenumber := 0;
                   end;
                 end if;
              end;
            else
              begin
                gv_message := 'Mobile device found';
                fp_messagenumber := 0;
              end;
            end if;
          end;
        end if;
      end;
    end if;
    -- check for valid system user
    if (fp_messagenumber = 0) then
      begin
        if (fp_systemuserid is not null) then
          -- system user specified
          begin
            gv_message := 'System user not found';
            fp_messagenumber := 5;
            --
            select 5 into lv_result
              from systemuser s
             where s.systemuser_id = fp_systemuserid;
            --
            if (lv_result = 5) then
              begin
                gv_message := 'System user found';
                fp_messagenumber := 0;
              end;
            end if;
          end;
        else
          -- no system user specified
          begin
            -- dummy system user will be used
            if (gv_picking_userid = 0) then
              begin
                gv_message := 'no system user found, instead value 0 will be used';
                write_log('Sucessfully ran validate_parameters: ' || gv_message, 5);
                fp_messagenumber := 0;
              end;
            else
              begin
                -- dedicated Advanced Picking User (APU) will be used
                if (gv_picking_userid > 0) then
                  begin
                    gv_message := 'no system user defined, instead system user APU will be used';
                    write_log('Sucessfully ran validate_parameters: ' || gv_message, 5);
                    fp_messagenumber := 0;
                  end;
                else
                  -- no system user could be determined, raise error
                  begin
                    gv_message := 'No system user could be determined';
                    fp_messagenumber := 6;
                    raise no_data_found;
                  end;
                end if; -- if (gv_picking_userid > 0) then
              end;
            end if; -- if (gv_picking_userid = 0) then
          end;
         end if; -- if (fp_systemuserid is not null) then
      end;
    end if; -- if (fp_messagenumber = 0) then
  exception
    when no_data_found then
      begin
        null;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error validate_parameters: Others ' || gv_message, 3);
      end;
  end validate_parameters;


  procedure validate_pickingpool(fp_stockroomid   in stockroom.stockroom_id%type,
                                 fp_messagenumber out number) is
    lv_workorders    number;
  begin
    fp_messagenumber := 1;
    gv_message := 'No work orders found in picking pool for stockroom';
    -- check for at least one order in item picking pool
    select count(*)
      into lv_workorders
      from (select wo.workorder_id,
                   wo.workordernumber,
                   c.customernumber,
                   op.sequencenumber orderprio,
                   wo.neededdate,
                   nvl(cr.priority,9999) customerprio,
                   wo.addedtoitempickingpool,
                   (select sum(wol.quantityordered - wol.quantityfilled -
                               wol.quantitycancelled)
                      from workorderline wol
                     where wol.workorder_id = wo.workorder_id) qty_ordered,
                   ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                       from picklist pl, picklistline pll, picklistlineorigin plo, workorderline wol
                      where pll.picklist_id = pl.picklist_id
                        and plo.picklistline_id = pll.picklistline_id
                        and plo.baselinetype = wo.origin
                        and plo.baselinetable = 'WORKORDERLINE'
                        and wol.workorderline_id = plo.baselinetable_link_id
                        and wol.workorder_id = wo.workorder_id
                        -- RVI 05-03-2015 Begin
                        --and plo.qtyissued > 0
                        -- RVI 05-03-2015 End
                        and pl.status_id in (select s.status_id
                                               from status s
                                              where s.statustype = 'PL'
                   -- RVI 01-05-2015 Begin
                   --                             and s.code not in ('20','30','40','60')))
                                                and s.code in ('10')))
                    +
                    (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
                       from picklist pl, picklistline pll, picklistlineorigin plo, workorderline wol
                      where pll.picklist_id = pl.picklist_id
                        and plo.picklistline_id = pll.picklistline_id
                        and plo.baselinetype = wo.origin
                        and plo.baselinetable = 'WORKORDERLINE'
                        and wol.workorderline_id = plo.baselinetable_link_id
                        and wol.workorder_id = wo.workorder_id
                        and pl.status_id in (select s.status_id
                                               from status s
                                              where s.statustype = 'PL'
                                                and s.code in ('50')))
                   -- RVI 01-05-2015 End
                   -- RVI 05-03-2015 Begin
                    +
                    (select nvl(sum(plo.qtypicked),0)
                       from picklist pl, picklistline pll, picklistlineorigin plo, workorderline wol
                      where pll.picklist_id = pl.picklist_id
                        and plo.picklistline_id = pll.picklistline_id
                        and plo.baselinetype = wo.origin
                        and plo.baselinetable = 'WORKORDERLINE'
                        and wol.workorderline_id = plo.baselinetable_link_id
                        and wol.workorder_id = wo.workorder_id
                        --and plo.qtyissued = 0
                        and pl.status_id in (select s.status_id
                                               from status s
                                              where s.statustype = 'PL'
                                                --and s.code not in ('40','60')))
                                                and s.code in ('20','30')))
                   -- RVI 05-03-2015 End
                   ) qty_prev_picklists
              from workorder        wo,
                   customer         c,
                   customerranking  cr,
                   orderpriority    op
             where c.customer_id(+) = wo.customer_link_id
               and op.orderpriority_id = wo.orderpriority_id
               and cr.customerranking_id(+) = c.customerranking_id
               and wo.addedtoitempickingpool = gv_addedtoitempickingpool
               and wo.processingstockroom_id = fp_stockroomid
               and wo.deliverfrom = 2
               and wo.origin in (1,2,3,4,5,6,8,9)
               and wo.status_id in (select s.status_id
                                      from status s
                                     where s.statustype = 'WO'
                                       and s.code in ('10','15', '20', '25'))) x
             where (x.qty_ordered - x.qty_prev_picklists > 0)
             order by x.orderprio,
                      x.neededdate,
                      x.customerprio,
                      x.workordernumber;
    -- check for number of workorders found
    if ((lv_workorders > 0)) then
      begin
        gv_message := to_char(lv_workorders)||' work orders found in picking pool for stockroom';
        write_log('Sucessfully ran validate_pickingpool: ' || gv_message, 5);
        fp_messagenumber := 0;
      end;
    end if;
  exception
    when no_data_found then
      begin
        null;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error validate_pickingpool: Others ' || gv_message, 3);
      end;
  end validate_pickingpool;


  procedure determine_batchsizes(fp_stockroomid    in number,
                                 fp_min_batch_size out number,
                                 fp_max_batch_size out number) is
    cursor get_batchsize is
      select s.pickgroupminbatchqty, s.pickgroupmaxbatchqty
        from stockroom s
       where s.stockroom_id = fp_stockroomid;
  begin
    gv_message := 'for stockroom_id = '||fp_stockroomid;
    -- determine batch sizes for stockroom
    for bs_rec in get_batchsize loop
       fp_min_batch_size := bs_rec.pickgroupminbatchqty;
       fp_max_batch_size := bs_rec.pickgroupmaxbatchqty;
    end loop;
  exception
    when no_data_found then
      begin
        write_log('Error determine_batchsizes: No_Data_Found ' || gv_message, 2);
        fp_min_batch_size := 0;
        fp_min_batch_size := 0;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error determine_batchsizes: Others ' || gv_message, 2);
        fp_min_batch_size := 0;
        fp_min_batch_size := 0;
      end;
  end determine_batchsizes;


  procedure determine_next_priority(fp_reference_wo_id in number,
                                    fp_picklistid      in number,
                                    fp_qty_poss_to_add in number,
                                    fp_prev_priority   in  number,
                                    fp_next_priority   out number,
                                    fp_messagenumber   out number) is

    cursor get_next_prio is
      select min(y.orderpriority) orderpriority
        from
          (select wo.workorder_id, wo.workordernumber, wo.origin, wo.neededdate,
                  op.sequencenumber orderpriority,
                 nvl((select cr.priority
                        from customer c, customerranking cr
                       where cr.customerranking_id = c.customerranking_id
                         and c.customer_id = wo.customer_link_id),9999) customerpriority,
                 (select sum(wolr.quantity)
                    from workorderline wol, workorderlinereservation wolr
                   where wolr.workorderline_id = wol.workorderline_id
                     and wol.workorder_id = wo.workorder_id) quantity_wo -- to do sum

           from
             (select distinct w.workorder_id
               from workorderpicksequence w
              where w.picklist_id = fp_picklistid
                and w.workorder_id != fp_reference_wo_id
                -- make sure that workorder was not added to current pick list yet
                and not exists (select 1
                                  from picklistline pll, picklistlineorigin pllo, workorderline wol
                                 where pllo.picklistline_id = pll.picklistline_id
                                   and pll.picklist_id =  fp_picklistid
                                   and pllo.baselinetable = 'WORKORDERLINE'
                                   and wol.workorderline_id = pllo.baselinetable_link_id
                                   and wol.workorder_id = w.workorder_id)) x,
              workorder wo, orderpriority op
          where wo.workorder_id = x.workorder_id
            and op.orderpriority_id = wo.orderpriority_id) y
        -- only lower priorities are allowed (1 = highest)
        where y.orderpriority > fp_prev_priority
         and y.quantity_wo <= fp_qty_poss_to_add
      order by y.quantity_wo desc, y.orderpriority, y.neededdate, y.customerpriority, y.workordernumber;

    lv_next_priority      number := -1;
    lv_prioritycode       orderpriority.prioritycode%type;
    le_no_next_prio_found exception;
  begin
    -- Try to determine next priority
    for prio_rec in get_next_prio loop
      lv_next_priority := prio_rec.orderpriority;
    end loop;
    fp_next_priority := lv_next_priority;
    if (lv_next_priority = -1 or lv_next_priority is null) then
      gv_message := 'no next priority found';
      raise le_no_next_prio_found;
    end if;
    -- all ok return 0
    fp_messagenumber := 0;
    -- determine priority code for next order priority
    get_prioritycode(lv_next_priority, lv_prioritycode);
    write_log('Succesfully ran determine_next_priority, next order priority found = ' || lv_prioritycode, 5);
  exception
    when le_no_next_prio_found then
      begin
        write_log('Successfully ran determine_next_priority: ' || gv_message, 5);
        fp_messagenumber := 0;
      end;
    when no_data_found then
      begin
        write_log('Error determine_next_priority: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error determine_next_priority: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error fdetermine_next_priority: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end determine_next_priority;


  procedure lock_for_picklist_generation(fp_stockroomid  in stockroom.stockroom_id%type,
                                        fp_messagenumber out number) is
    lv_timeout     number := -1;
    lv_timerstart  date;
    lv_elapsedtime number;
    le_timeout     exception;
  begin
    /* wait until other process releases lock
       while stockroom table new column set to 1 wait 250 ms
       after 10 sec give time out message result:=1  error# time out
    if not time out
      then set to 1 (so lock myself)   result:=-1
    */
    dbms_output.put_line(to_char(sysdate,'HH:MM:SS'));

    -- start timer
    lv_timerstart := set_timerstart;
    lv_elapsedtime := get_elapsedtime(lv_timerstart);
    -- check stockroom for lock during 10 seconds maximum
    gv_message := 'check if stockroom was locked by other process';
    while (lv_timeout != 0 and lv_elapsedtime < gv_lockingdelay) Loop
      select s.lockedforpicklistgeneration
        into lv_timeout
      from stockroom s
      where s.stockroom_id = fp_stockroomid;
      -- determine elapsed time
      lv_elapsedtime := get_elapsedtime(lv_timerstart);
    end loop;

    dbms_output.put_line(to_char(sysdate,'HH:MM:SS'));
    -- Give timeout error in case stockroom waa still locked after 10 seconds
    if (lv_elapsedtime >= gv_lockingdelay) then
      gv_message := 'stockroom was locked by other process';
      raise le_timeout;
    end if;
    -- If stockroom was not locked, then lock it now
    if (lv_timeout = 0)then
       gv_message := 'mark stockroom as locked';
       update stockroom s
       set s.lockedforpicklistgeneration = 1
       where s.stockroom_id = fp_stockroomid;
       fp_messagenumber := 0;
    else
       fp_messagenumber := 1;
    end if;
  exception
    when no_data_found then
      begin
        write_log('Error lock_for_picklist_generation: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 11;
      end;
    when le_timeout then
      begin
        write_log('Error lock_for_picklist_generation: Timeout ' || gv_message, 3);
        fp_messagenumber := 12;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error lock_for_picklist_generation: Others ' || gv_message, 3);
        fp_messagenumber := 13;
      end;
  end lock_for_picklist_generation;


  procedure unlock_for_picklist_generation(fp_stockroomid  in stockroom.stockroom_id%type) is
  begin
    /* wait until other process releases lock
       then set to 0 (so unlock myself)
    */
    update stockroom s
    set s.lockedforpicklistgeneration = 0
    where s.stockroom_id = fp_stockroomid;
  end unlock_for_picklist_generation;


  function f_wo_has_sufficient_stock(fp_workorder_id in number,
                                     fp_picklist_id  in number,
                                     fp_areacode     in stockroomlocation.areacode%type,
                                     fp_allowsplit   in workorder.allowphasedelivery%type) return boolean is

    cursor stock_ok is
      select 'Y' resultstr, on_stock, reserved_other_wo, reserved_wo, allocated_other_pl
        from ( select w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id, w.stocktype,
                      w.on_stock, w.reserved_other_wo, w.allocated_other_pl,
                      sum(w.quantity) reserved_wo
                      -- RVI 20-04-2015 Begin
                      , w.quantity_picked
                      -- RVI 20-04-2015 End
        from (select wol.workorder_id, wol.workorderline_id, wolr.stocktype, wolr.quantity,
                     wolr.stockreservationpergrade_id,
              -- physically on stock for product/size/grade
              case
                 when ((wol.codeuniquely = 'N') and (wolr.stocktype = 1)) then
                 (select nvl(sum(sq.qtynonunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and sq.qtynonunique > 0
                     and lt.pickinglocation = 'Y')
                 when ((wol.codeuniquely = 'Y') and (wolr.stocktype = 1)) then
                 (select nvl(sum(sq.qtynonunique),0) + nvl(sum(sq.qtyunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                     and lt.pickinglocation = 'Y')
                 when (wolr.stocktype = 2) then
                 -- RVI 13-01-2014 Begin
                 --(select nvl(sum(sq.qtyunique),0)
                 (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
                 -- RVI 13-01-2013 End
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     -- RVI 13-01-2014 Begin
                     --and sq.qtyunique > 0
                     and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                     -- RVI 13-01-2013 End
                     and lt.pickinglocation = 'Y')
                 when (wolr.stocktype = 3) then
                 (select nvl(sum(sq.qtyuniquewithmodifications),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and sq.qtyuniquewithmodifications > 0
                     and lt.pickinglocation = 'Y')
              end on_stock,
              -- reserved on current pick list for other wo
              (select nvl(sum(woid.qty_to_pick),0)
                 from workorderitemdistribution woid
                where woid.picklist_id = fp_picklist_id
                  and woid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                  and woid.stocktype = wolr.stocktype) reserved_other_wo,
              -- RVI 24-03-2015
              -- allocated on previous pick lists for other wo that have not been confirmed yet
              ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and pll.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and pll.stocktype = wolr.stocktype
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id != wolr.workorderline_id
                   and pll.qtypicked = 0
                   and pll.confirmedcompletely = 'N'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('10','20')))
               +
               (select nvl(sum(plo.qtypicked),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and pll.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and pll.stocktype = wolr.stocktype
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id != wolr.workorderline_id
                   and ((pll.confirmedcompletely = 'Y')
                    or  (pll.confirmedcompletely = 'N' and pll.qtypicked > 0))
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('10')))
              ) allocated_other_pl,
              -- RVI 24-03-2015 End
              -- allocated on previous pick lists for wo that have not been confirmed yet, or confirmed but not issued
              -- RVI 20-04-2015 Begin
              ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
                                          and s.code in ('10')))
                +
               (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('50')))
                +
               (select nvl(sum(plo.qtypicked),0)
                  from picklistlineorigin plo, picklistline pll, picklist pl
                 where pll.picklistline_id = plo.picklistline_id
                   and pl.picklist_id = pll.picklist_id
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('20','30')))
               ) quantity_picked
              -- RVI 20-04-2015 End
               from workorderline wol, workorderlinereservation wolr
              where wolr.workorderline_id = wol.workorderline_id
                and wol.workorder_id = fp_workorder_id) w
       -- RVI 20-04-2015 Begin
       --group by w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id, w.stocktype, w.on_stock,
       --         w.reserved_other_wo, w.allocated_other_pl) w1
       --         where (w1.reserved_wo <= (w1.on_stock - w1.reserved_other_wo - w1.allocated_other_pl));
       group by w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id, w.stocktype, w.on_stock,
                w.reserved_other_wo, w.allocated_other_pl, w.quantity_picked) w1
                where ((w1.reserved_wo - w1.quantity_picked) <= (w1.on_stock - w1.reserved_other_wo - w1.allocated_other_pl));
       -- RVI 20-04-2015 End

    lv_result       boolean := false;
    lv_stock_ok     number := 0;
    lv_stock_not_ok number := 0;
    lv_lines_found  number := 0;
  begin
    -- open cursor to check if demand for all lines of workorder can be fullfilled
    for ck in stock_ok loop
      lv_lines_found := lv_lines_found + 1;
      if (ck.resultstr = 'Y') Then
        -- cursor returns 'Y', so demand for all lines of work order can be fullfilled
        lv_stock_ok := lv_stock_ok + 1;
      else
        -- cursor returns null, so demand cannot be fullfilled for all lines of work order
        lv_stock_not_ok := lv_stock_not_ok + 1;
      end if;
    end loop;
    -- cursor did not return any line
    if (lv_lines_found = 0) then
      lv_stock_not_ok := lv_stock_not_ok + 1;
    end if;
    -- Only when stock_ok, or not ok and phased delivery allowed
    if (((lv_stock_ok > 0) and (lv_stock_not_ok = 0))
     or ((lv_stock_not_ok > 0) and (fp_allowsplit = 'Y'))) then
      lv_result:= true;
    else
      lv_result := false;
    end if;
    -- return the approriate value
    return lv_result;
  end f_wo_has_sufficient_stock;


-- RVI 15-01-2015 End
  function f_wo_has_surplus_stock(fp_workorder_id in number,
                                  fp_picklist_id  in number,
                                  fp_areacode     in stockroomlocation.areacode%type) return boolean is

    cursor stock_ok is
      select 'Y' resultstr, reserved_wo, on_stock, reserved_other_wo
        from ( select w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id,
                      w.on_stock, w.reserved_other_wo, w.allocated_other_pl, sum(w.quantity) reserved_wo
                      -- RVI 20-04-2015 Begin
                      , w.quantity_picked
                      -- RVI 20-04-2015 End
        from (select wol.workorder_id, wol.workorderline_id, wolr.stocktype, wolr.quantity,
                     wolr.stockreservationpergrade_id,
              -- physically on stock for product/size/grade
              case
                 when ((wol.codeuniquely = 'N') and (wolr.stocktype = 1)) then
                 (select nvl(sum(sq.qtynonunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and sq.qtynonunique > 0
                     and lt.pickinglocation = 'Y')
                 when ((wol.codeuniquely = 'Y') and (wolr.stocktype = 1)) then
                 (select nvl(sum(sq.qtynonunique),0) + nvl(sum(sq.qtyunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                     and lt.pickinglocation = 'Y')
                 when (wolr.stocktype = 2) then
                 -- RVI 13-01-2014 Begin
                 --(select nvl(sum(sq.qtyunique),0)
                 (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
                 -- RVI 13-01-2013 End
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     -- RVI 13-01-2014 Begin
                     --and sq.qtyunique > 0
                     and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                     -- RVI 13-01-2013 End
                     and lt.pickinglocation = 'Y')
                 when (wolr.stocktype = 3) then
                 (select nvl(sum(sq.qtyuniquewithmodifications),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and sq.qtyuniquewithmodifications > 0
                     and lt.pickinglocation = 'Y')
              end on_stock,
              -- reserved on pick list for other wo
              (select nvl(sum(woid.qty_to_pick),0)
                 from workorderitemdistribution woid
                where woid.picklist_id = fp_picklist_id
                  and woid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                  and woid.stocktype = wolr.stocktype
                  and woid.workorder_id <> fp_workorder_id
                  ) reserved_other_wo,
              -- RVI 24-03-2015
              -- allocated on previous pick lists that have not been confirmed yet
              ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and pll.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and pll.stocktype = wolr.stocktype
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id != wolr.workorderline_id
                   and pll.qtypicked = 0
                   and pll.confirmedcompletely = 'N'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('10','20')))
               +
               (select nvl(sum(plo.qtypicked),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and pll.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and pll.stocktype = wolr.stocktype
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id != wolr.workorderline_id
                   and ((pll.confirmedcompletely = 'Y')
                    or  (pll.confirmedcompletely = 'N' and pll.qtypicked > 0))
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('10')))
              ) allocated_other_pl,
              -- RVI 24-03-2015 End
              -- allocated on previous pick lists for wo that have not been confirmed yet, or confirmed but not issued
              -- RVI 20-04-2015 Begin
              ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
                                          and s.code in ('10')))
                +
               (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                 where pll.picklist_id = pl.picklist_id
                   and plo.picklistline_id = pll.picklistline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('50')))
                +
               (select nvl(sum(plo.qtypicked),0)
                  from picklistlineorigin plo, picklistline pll, picklist pl
                 where pll.picklistline_id = plo.picklistline_id
                   and pl.picklist_id = pll.picklist_id
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('20','30')))
               ) quantity_picked
              -- RVI 20-04-2015 End
               from workorderline wol, workorderlinereservation wolr
              where wolr.workorderline_id = wol.workorderline_id
                and wol.workorder_id = fp_workorder_id) w
       -- RVI 20-04-2015 Begin
       --group by w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id, w.on_stock,
       --         w.reserved_other_wo, allocated_other_pl) w1
       --         where (w1.reserved_wo < (w1.on_stock - w1.reserved_other_wo - w1.allocated_other_pl));
       group by w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id, w.on_stock,
                w.reserved_other_wo, w.allocated_other_pl, w.quantity_picked) w1
                where ((w1.reserved_wo - w1.quantity_picked) < (w1.on_stock - w1.reserved_other_wo - w1.allocated_other_pl));
       -- RVI 20-04-2015 End

    lv_result       boolean := false;
    lv_stock_ok     number := 0;
    lv_surplus      number := 0;
  begin
    -- open cursor to check if demand for all lines of workorder can be fullfilled
    for ck in stock_ok loop
      if (ck.resultstr = 'Y') Then
        -- cursor returns 'Y', so demand for all lines of work order can be fullfilled
        lv_stock_ok := lv_stock_ok + 1;
        lv_surplus := lv_surplus + (ck.on_stock - ck.reserved_other_wo - ck.reserved_wo);
      end if;
    end loop;
    -- Only true when stock_ok and surplus > 0
    if ((lv_stock_ok > 0) and (lv_surplus > 0)) then
      lv_result:= true;
    else
      lv_result := false;
    end if;
    -- return the approriate value
    return lv_result;
  end f_wo_has_surplus_stock;
-- RVI 15-01-2015 End


-- RVI 03-03-2015 Begin
  function f_wo_has_items_to_pick(fp_workorder_id in number,
                                  fp_picklist_id  in number,
                                  fp_areacode     in stockroomlocation.areacode%type,
                                  fp_allowsplit   in workorder.allowphasedelivery%type) return boolean is

    cursor stock_ok is
      select 'Y' resultstr, on_stock, reserved_other_wo, reserved_wo, picked_before_wo
        from ( select w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id,
                      w.on_stock, w.reserved_other_wo, sum(w.quantity) reserved_wo, w.picked_before_wo
        from (select wol.workorder_id, wol.workorderline_id, wolr.stocktype, wolr.quantity,
                     wolr.stockreservationpergrade_id,
              -- physically on stock for product/size/grade
              case
                 when ((wol.codeuniquely = 'N') and (wolr.stocktype = 1)) then
                 (select nvl(sum(sq.qtynonunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and sq.qtynonunique > 0
                     and lt.pickinglocation = 'Y')
                 when ((wol.codeuniquely = 'Y') and (wolr.stocktype = 1)) then
                 (select nvl(sum(sq.qtynonunique),0) + nvl(sum(sq.qtyunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                     and lt.pickinglocation = 'Y')
                 when (wolr.stocktype = 2) then
                 (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                     and lt.pickinglocation = 'Y')
                 when (wolr.stocktype = 3) then
                 (select nvl(sum(sq.qtyuniquewithmodifications),0)
                    from stockquantity sq, stockroomlocation sl, locationtype lt
                   where sl.stockroomlocation_id = sq.stockroomlocation_id
                     and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                     and lt.locationtype_id = sl.locationtype_id
                     and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                     and sq.qtyuniquewithmodifications > 0
                     and lt.pickinglocation = 'Y')
              end on_stock,
              -- reserved on current pick list for other wo
              (select nvl(sum(woid.qty_to_pick),0)
                 from workorderitemdistribution woid
                where woid.picklist_id = fp_picklist_id
                  and woid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                  and woid.stocktype = wolr.stocktype) reserved_other_wo,
              -- picked before for wo
              ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                  from picklistlineorigin plo, picklistline pll, picklist pl
                 where pll.picklistline_id = plo.picklistline_id
                   and pl.picklist_id = pll.picklist_id
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
              -- RVI 20-04-2015 Begin
              --                             and s.code not in ('20','30','40','60'))) +
                                           and s.code in ('10'))) +
               (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
                  from picklistlineorigin plo, picklistline pll, picklist pl
                 where plo.picklistline_id = pll.picklistline_id
                   and pl.picklist_id = pll.picklist_id
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('50'))) +
              -- RVI 20-04-2015 End
               (select nvl(sum(plo.qtypicked),0)
                  from picklistlineorigin plo, picklistline pll, picklist pl
                 where pll.picklistline_id = plo.picklistline_id
                   and pl.picklist_id = pll.picklist_id
                   and plo.baselinetable_link_id = wolr.workorderline_id
                   and plo.baselinetable = 'WORKORDERLINE'
                   and pl.status_id in (select s.status_id
                                          from status s
                                         where s.statustype = 'PL'
                                           and s.code in ('20','30')))) picked_before_wo

               from workorderline wol, workorderlinereservation wolr
              where wolr.workorderline_id = wol.workorderline_id
                and wol.workorder_id = fp_workorder_id) w
       group by w.workorder_id, w.workorderline_id, w.stockreservationpergrade_id, w.on_stock,
                w.reserved_other_wo, w.picked_before_wo) w1
                where ((w1.reserved_wo - w1.picked_before_wo) > 0)
                and ((w1.on_stock - w1.reserved_other_wo) > 0);

    lv_result       boolean := false;
    lv_stock_ok     number := 0;
    lv_stock_not_ok number := 0;
    lv_lines_found  number := 0;
    lv_on_stock     number := 0;
  begin
    -- open cursor to check if demand for all lines of workorder can be fullfilled
    for ck in stock_ok loop
      lv_lines_found := lv_lines_found + 1;
      if (ck.resultstr = 'Y') Then
        lv_on_stock := ck.on_stock;
        -- cursor returns 'Y', so demand for all lines of work order can be fullfilled
        lv_stock_ok := lv_stock_ok + 1;
      else
        -- cursor returns null, so demand cannot be fullfilled for all lines of work order
        lv_stock_not_ok := lv_stock_not_ok + 1;
      end if;
    end loop;
    -- cursor did not return any line
    if (lv_lines_found = 0) then
      lv_stock_not_ok := lv_stock_not_ok + 1;
    end if;
    -- Only when stock_ok, or not ok and phased delivery allowed
    if (((lv_stock_ok > 0) and (lv_stock_not_ok = 0))
     or ((lv_stock_not_ok > 0) and (fp_allowsplit = 'Y'))) then
      -- Check on zero stock qty for wo
      if ((lv_stock_not_ok > 0) and (fp_allowsplit = 'Y') and (lv_on_stock = 0)) then
        lv_result:= false;
      else
        lv_result:= true;
      end if;
    else
      lv_result := false;
    end if;
    -- return the approriate value
    return lv_result;
  end f_wo_has_items_to_pick;
-- RVI 03-03-2015 End


  function select_first_wo(fp_stockroomid    in stockroom.stockroom_id%type,
                           fp_areacode       in stockroomlocation.areacode%type,
                           fp_max_batch_size in number,
                           fp_ref_wo_id      out number,
                           fp_qty_this_wo    out number,
                           fp_prio_this_wo   out number) return number is
    lv_msg_nr  number := 0;
    lv_first_wo_found boolean := false;
    lv_last_wo_read boolean := false;
    lv_ref_workordernumber number := -1;
    lv_prv_workordernumber number := -1;
    --
    lv_qty_available number := 0;
    lv_qty_reserved  number := 0;
    lv_neededdate    date := null;
    lv_customer_prio number := 999;
    lv_allowsplit    workorder.allowphasedelivery%type := 'N';
    lv_stock_found   number := 0;
    lv_open_picklist number := 0;

    -- cursor to determine the work orders that could be used as reference work order
    cursor get_reference_wo is
      select z1.workorder_id, z1.orderpriority, z1.neededdate, z1.customerpriority, z1.workordernumber,
             (z1.quantity_wo - z1.qty_picked), sum(z1.available), sum(z1.qty_reserved), z1.allowphasedelivery
      from
      (select z.orderpriority, z.neededdate, z.customerpriority, z.workordernumber, z.workorder_id,
              z.quantity_wo, z.stockreservationpergrade_id, z.available, sum(z.quantity) qty_reserved, z.allowphasedelivery
              -- RVI 01-05-2015 Begin
              --, sum(z.quantity_previous_picklists) qty_picked
              , z.quantity_previous_picklists qty_picked
              -- RVI 01-05-2015 End
      from
      (select y.workorder_id, y.orderpriority, y.workordernumber, y.allowphasedelivery, y.quantity, y.available,
              y.stockreservationpergrade_id, y.neededdate, y.customerpriority,
              (select sum(wolr.quantity)
                from workorderline wol, workorderlinereservation wolr
               where wolr.workorderline_id = wol.workorderline_id
                 and wol.workorder_id = y.workorder_id) quantity_wo -- to do sum
              -- RVI 20-04-2015 Begin
              , y.quantity_previous_picklists
              -- RVI 20-04-2015 End
        from
      (select x.*
         from
      (select wo.workorder_id, wo.workordernumber, wo.neededdate, wo.origin, wo.allowphasedelivery,
             wo.processingstockroom_id, wol.workorderline_id, wol.quantityordered, wol.quantityfilled,
             wol.quantitycancelled, wol.codeuniquely, wolr.stockreservationpergrade_id,
             wolr.stocktype, wolr.quantity, srg.qualitygrade_id, sdi.stockdefinitionperitem_id,
             sdi.stockroom_id, sdi.product_id, sdi.sizedefinition_id, sdi.customer_id, sdi.customerowned,
             op.sequencenumber orderpriority,
             nvl((select cr.priority
                    from customer c, customerranking cr
                   where cr.customerranking_id = c.customerranking_id
                     and c.customer_id = wo.customer_link_id),9999) customerpriority,
             case
               when ((wol.codeuniquely = 'N') and (wolr.stocktype = 1)) then
               (select nvl(sum(sq.qtynonunique),0)
                  from stockquantity sq, stockroomlocation sl, locationtype lt
                 where sl.stockroomlocation_id = sq.stockroomlocation_id
                   and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and lt.locationtype_id = sl.locationtype_id
                   and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                   and sq.qtynonunique > 0
                   and lt.pickinglocation = 'Y')
               when ((wol.codeuniquely = 'Y') and (wolr.stocktype = 1)) then
               (select nvl(sum(sq.qtynonunique),0) + nvl(sum(sq.qtyunique),0)
                  from stockquantity sq, stockroomlocation sl, locationtype lt
                 where sl.stockroomlocation_id = sq.stockroomlocation_id
                   and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and lt.locationtype_id = sl.locationtype_id
                   and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                   and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                   and lt.pickinglocation = 'Y')
               when (wolr.stocktype = 2) then
               (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
                  from stockquantity sq, stockroomlocation sl, locationtype lt
                 where sl.stockroomlocation_id = sq.stockroomlocation_id
                   and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and lt.locationtype_id = sl.locationtype_id
                   and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                   and (sq.qtyunique > 0 or sq.qtynonunique > 0)
                   and lt.pickinglocation = 'Y')
               when (wolr.stocktype = 3) then
               (select nvl(sum(sq.qtyuniquewithmodifications),0)
                  from stockquantity sq, stockroomlocation sl, locationtype lt
                 where sl.stockroomlocation_id = sq.stockroomlocation_id
                   and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                   and lt.locationtype_id = sl.locationtype_id
                   and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                   and sq.qtyuniquewithmodifications > 0
                   and lt.pickinglocation = 'Y')
             end available,
             ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                 from picklist pl, picklistline pll, picklistlineorigin plo
                where pll.picklist_id = pl.picklist_id
                  and plo.picklistline_id = pll.picklistline_id
                  and plo.baselinetype = wo.origin
                  and plo.baselinetable = 'WORKORDERLINE'
                  and plo.baselinetable_link_id = wolr.workorderline_id
             -- RVI 05-03-2015 Begin
             --     and plo.qtyissued > 0
             -- RVI 05-03-2015 End
                  and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
             -- RVI 17-04-2015 Begin
             --                            and s.code not in ('20','30','40','60')))
                                         and s.code in ('10')))
             +
              (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
                 from picklistlineorigin plo, picklistline pll, picklist pl
                where pll.picklistline_id = plo.picklistline_id
                  and pl.picklist_id = pll.picklist_id
                  and plo.baselinetable_link_id = wolr.workorderline_id
                  and plo.baselinetable = 'WORKORDERLINE'
                  and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
                                          and s.code in ('50'))) +
             -- RVI 17-04-2015 End
             -- RVI 05-03-2015 Begin
             +
              (select nvl(sum(plo.qtypicked),0)
                 from picklistlineorigin plo, picklistline pll, picklist pl
                where pll.picklistline_id = plo.picklistline_id
                  and pl.picklist_id = pll.picklist_id
                  and plo.baselinetable_link_id = wolr.workorderline_id
                  and plo.baselinetable = 'WORKORDERLINE'
                  --and plo.qtyissued = 0
                  and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
                                          --and s.code not in ('40','60')))
                                          and s.code in ('20','30')))
             -- RVI 05-03-2015 End
             ) quantity_previous_picklists
      from workorder wo, orderpriority op, workorderline wol, workorderlinereservation wolr,
           stockreservationpergrade srg, stockdefinitionperitem sdi
      where wol.workorder_id = wo.workorder_id
      and wolr.workorderline_id = wol.workorderline_id
      and srg.stockreservationpergrade_id = wolr.stockreservationpergrade_id
      and sdi.stockdefinitionperitem_id = srg.stockdefinitionperitem_id
      and sdi.stockroom_id = wo.processingstockroom_id
      and op.orderpriority_id = wo.orderpriority_id
      and wo.processingstockroom_id = fp_stockroomid
      and wo.addedtoitempickingpool = gv_addedtoitempickingpool
      and wo.deliverfrom = 2
      and wo.origin in (1,2,3,4,5,6,8,9)
      and wo.status_id in (select s.status_id
                             from status s
                            where s.statustype = 'WO'
                              and s.code in ('10','15', '20', '25'))
      -- Ignore WO that has to be delivered as a whole for which not sufficient stock is available
      and ((wo.allowphasedelivery = 'Y')
        or (wo.allowphasedelivery = 'N')
          and not exists
             (select 1
                from
                   (select wol.workorder_id, wol.workorderline_id, wolr.stocktype, wolr.quantity,
                           -- RVI 06-03-2015 Begin
                           (select sum(wolr2.quantity)
                              from workorderlinereservation wolr2
                             where wolr2.workorderline_id = wolr.workorderline_id
                               and wolr2.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                               and wolr2.stocktype = wolr.stocktype) total_quantity,
                           -- RVI 06-03-2015 End
                           -- RVI 20-04-2015 begin
                           ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                             from picklist pl, picklistline pll, picklistlineorigin plo
                            where pll.picklist_id = pl.picklist_id
                              and plo.picklistline_id = pll.picklistline_id
                              and plo.baselinetable = 'WORKORDERLINE'
                              and plo.baselinetable_link_id = wolr.workorderline_id
                              and pl.status_id in (select s.status_id
                                                    from status s
                                                   where s.statustype = 'PL'
                                                     and s.code in ('10')))
                             -- Issue in Progress (= Picked but not issued yet)
                             +
                             (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
                             from picklist pl, picklistline pll, picklistlineorigin plo
                            where pll.picklist_id = pl.picklist_id
                              and plo.picklistline_id = pll.picklistline_id
                              and plo.baselinetable = 'WORKORDERLINE'
                              and plo.baselinetable_link_id = wolr.workorderline_id
                              and pl.status_id in (select s.status_id
                                                    from status s
                                                   where s.statustype = 'PL'
                                                     and s.code in ('50')))
                             -- Picking in Progress or Picking Confirmed
                             +
                             (select nvl(sum(plo.qtypicked),0)
                              from picklistlineorigin plo, picklistline pll, picklist pl
                             where pll.picklistline_id = plo.picklistline_id
                               and pl.picklist_id = pll.picklist_id
                               and plo.baselinetable_link_id = wolr.workorderline_id
                               and plo.baselinetable = 'WORKORDERLINE'
                               and pl.status_id in (select s.status_id
                                                      from status s
                                                     where s.statustype = 'PL'
                                                       and s.code in ('20','30')))
                           ) quantity_picked,
                           -- RVI 20-04-2015 End
                           case
                             when ((wol.codeuniquely = 'N') and (wolr.stocktype = 1)) then
                             (select nvl(sum(sq.qtynonunique),0)
                                from stockquantity sq, stockroomlocation sl, locationtype lt
                               where sl.stockroomlocation_id = sq.stockroomlocation_id
                                 and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                 and lt.locationtype_id = sl.locationtype_id
                                 and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                 and sq.qtynonunique > 0
                                 and lt.pickinglocation = 'Y')
                             when ((wol.codeuniquely = 'Y') and (wolr.stocktype = 1)) then
                             (select nvl(sum(sq.qtynonunique),0) + nvl(sum(sq.qtyunique),0)
                                from stockquantity sq, stockroomlocation sl, locationtype lt
                               where sl.stockroomlocation_id = sq.stockroomlocation_id
                                 and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                 and lt.locationtype_id = sl.locationtype_id
                                 and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                 and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                                 and lt.pickinglocation = 'Y')
                             when (wolr.stocktype = 2) then
                             (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
                                from stockquantity sq, stockroomlocation sl, locationtype lt
                               where sl.stockroomlocation_id = sq.stockroomlocation_id
                                 and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                 and lt.locationtype_id = sl.locationtype_id
                                 and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                 and (sq.qtyunique > 0 or sq.qtynonunique > 0)
                                 and lt.pickinglocation = 'Y')
                             when (wolr.stocktype = 3) then
                             (select nvl(sum(sq.qtyuniquewithmodifications),0)
                                from stockquantity sq, stockroomlocation sl, locationtype lt
                               where sl.stockroomlocation_id = sq.stockroomlocation_id
                                 and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                 and lt.locationtype_id = sl.locationtype_id
                                 and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                 and sq.qtyuniquewithmodifications > 0
                                 and lt.pickinglocation = 'Y')
                           end available
                      from workorderline wol, workorderlinereservation wolr
                     where wolr.workorderline_id = wol.workorderline_id) w
               where w.workorder_id = wo.workorder_id
               -- RVI 06-03-2015 Begin
               --and w.quantity > available))) x
               --and w.total_quantity > available))) x
               -- RVI 06-03-2015 End
               -- RVI 20-04-2015 Begin
               and (w.total_quantity - w.quantity_picked) > available))) x
               -- RVI 20-04-2015 End
        -- take into account items that were intended to be picked on previous pick lists
        where ((x.quantityordered - x.quantityfilled - x.quantitycancelled) - x.quantity_previous_picklists > 0)
      order by x.orderpriority, x.neededdate, x.customerpriority, x.workordernumber) y
      ) z
        group by z.orderpriority, z.neededdate, z.customerpriority, z.workordernumber, z.workorder_id,
                 z.quantity_wo, z.stockreservationpergrade_id, z.available, z.allowphasedelivery
                 -- RVI 20-04-2015 Begin
                 , z.quantity_previous_picklists
                 -- RVI 20-04-2015 End
        ) z1
          group by z1.orderpriority, z1.neededdate, z1.customerpriority, z1.workordernumber, z1.workorder_id, z1.quantity_wo,
                   z1.allowphasedelivery
                   -- RVI 20-04-2015 Begin
                   , z1.qty_picked
                   -- RVI 20-04-2015 End
          order by 2,3,4,5;

    -- cursor to examine the reservations for a potential reference work order that may be delivered in phases
    cursor get_wolr_lines (fp_wo_id number, fp_areacode stockroomlocation.areacode%type) is
      select wolr.*, wo.origin
        from workorderline wol, workorderlinereservation wolr, workorder wo
       where wolr.workorderline_id = wol.workorderline_id
         and wo.workorder_id = wol.workorder_id
         and wol.workorder_id = fp_wo_id
         and exists (select 1
                       from stockquantity sq, stockroomlocation sl, locationtype lt
                      where sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                        and sl.stockroomlocation_id = sq.stockroomlocation_id
                        and lt.locationtype_id = sl.locationtype_id
                        and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                        and lt.pickinglocation = 'Y'
                        and (case
                               when (wolr.stocktype = 1) then sq.qtynonunique
                               when (wolr.stocktype = 2) then sq.qtyunique
                               when (wolr.stocktype = 3) then sq.qtyuniquewithmodifications
                             end > 0));
--
  begin
    fp_ref_wo_id := -1;
    -- to do uitbreiden met filter op stockroom and areacode  en restrictie op phased delivery
    begin
      -- open cursor to find candidate reference work orders
      open get_reference_wo;
      -- try to find a reference work order as long as not found or no more candidates selected from cursor
      while ((not lv_first_wo_found) and (not lv_last_wo_read))
        loop
          -- retrieve values for current work order
          fetch get_reference_wo into fp_ref_wo_id, fp_prio_this_wo, lv_neededdate, lv_customer_prio, lv_ref_workordernumber,
                                      fp_qty_this_wo, lv_qty_available, lv_qty_reserved, lv_allowsplit;
          -- if no (next) work order found then loop should be ended
          if get_reference_wo%notfound then
            lv_last_wo_read := true;
          end if;
          -- check if total number of ordered items of WO exceeds max batch size
          -- RVI 15-01-2015 Begin
          /*
          if ((fp_max_batch_size > 0) and (fp_qty_this_wo > fp_max_batch_size)) then
             -- skip current work order since it exceeds maximum size
            if (lv_ref_workordernumber != lv_prv_workordernumber) then
              -- only add message to log when it concerns a reservation for another work order than the previous one
              gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
              write_log('select_first_wo: '|| gv_message, 5);
              gv_message := 'Number of requested items '|| to_char(fp_qty_this_wo);
              gv_message := gv_message || ' exceeds max batch size ' || to_char(fp_max_batch_size);
              write_log('select_first_wo: '|| gv_message, 5);
              lv_prv_workordernumber := lv_ref_workordernumber;
            end if;
          else
          */
          if (fp_max_batch_size >= 0) then
          -- RVI 15-01-2015 End
            -- check if sufficient items on stock for work order
            if (lv_allowsplit = 'N' and (fp_qty_this_wo > lv_qty_available)) then
             -- skip current work order since not enough items on stock
              if (lv_ref_workordernumber != lv_prv_workordernumber) then
                -- only add message to log when it concerns a reservation for another work order than the previous one
                gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                write_log('select_first_wo: '|| gv_message, 5);
                gv_message := 'Number of requested items '|| to_char(fp_qty_this_wo);
                gv_message := gv_message || ' > number of available items '|| to_char(lv_qty_available);
                gv_message := gv_message || ' on stock!';
                write_log('select_first_wo: '|| gv_message, 5);
                lv_prv_workordernumber := lv_ref_workordernumber;
              end if;
            else
              -- check if stock can be found for work order line
              if (lv_allowsplit = 'N') then
                -- skip current work order when no stock found for at least one work order line
                if (lv_ref_workordernumber != lv_prv_workordernumber) then
                  begin
                    lv_stock_found := 0;
                    -- check all reservations in a loop
                    for wolr_rec in get_wolr_lines(fp_ref_wo_id, fp_areacode) loop
                      lv_stock_found := lv_stock_found + 1;
                    end loop;
                    -- if no locations found then work order should be skipped since it will crash the pick list
                    if (lv_stock_found = 0) then
                      -- only add message to log when it concerns a reservation for another work order than the previous one
                      gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                      write_log('select_first_wo: '|| gv_message, 5);
                      gv_message := 'No stockroom location could be determined for at least one order line!';
                      write_log('select_first_wo: '|| gv_message, 5);
                      lv_prv_workordernumber := lv_ref_workordernumber;
                    else
                      -- RVI 05-03-2015 Begin
                      -- select current work order as Reference work order and loop should be ended
                      --lv_first_wo_found := true;

                      -- Check if there exists a previous picklist that has not been confirmed yet
                      lv_open_picklist := not_confirmed_picklists_exists(fp_ref_wo_id, fp_stockroomid, null);
                      if (lv_open_picklist > 0) then
                        -- only add message to log when it concerns a reservation for another work order than the previous one
                        gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                        write_log('select_first_wo: '|| gv_message, 5);
                        gv_message := 'Pick list '|| lv_open_picklist || ' for this work order has not been confirmed and picked yet!';
                        write_log('select_first_wo: '|| gv_message, 5);
                        lv_prv_workordernumber := lv_ref_workordernumber;
                      else
                        -- RVI 24-03-2015 Begin
                        -- check if there is sufficient stock for WO, if not then skip to avoid double pick list lines
                        if (f_wo_has_sufficient_stock(fp_ref_wo_id,null,fp_areacode,lv_allowsplit)) then
                        -- RVI 24-03-2015 End
                          -- Check if there is anything to pick for WO, if not then skip to avoid double pick list lines
                          if (f_wo_has_items_to_pick(fp_ref_wo_id,null,fp_areacode,lv_allowsplit)) then
                          -- select current work order as Reference work order and loop should be ended
                            lv_first_wo_found := true;
                          else
                            -- only add message to log when it concerns a reservation for another work order than the previous one
                            gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                            write_log('select_first_wo: '|| gv_message, 5);
                            gv_message := 'No items can be picked for any order line!';
                            write_log('select_first_wo: '|| gv_message, 5);
                            lv_prv_workordernumber := lv_ref_workordernumber;
                          end if;
                        -- RVI 24-03-2015 Begin
                        else
                          -- only add message to log when it concerns a reservation for another work order than the previous one
                          gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                          write_log('select_first_wo: '|| gv_message, 5);
                          gv_message := 'No sufficient items on stock!';
                          write_log('select_first_wo: '|| gv_message, 5);
                          lv_prv_workordernumber := lv_ref_workordernumber;
                        end if;
                        -- RVI 24-03-2015 End
                      end if;
                      -- RVI 05-03-2015 End
                    end if;
                  end;
                end if;
              else
                -- check if there are still pick lists for work order that may be delivered partially that are not in progress yet
                if (lv_ref_workordernumber != lv_prv_workordernumber) then
                  begin
                    lv_open_picklist := not_confirmed_picklists_exists(fp_ref_wo_id, fp_stockroomid, null);
                    if (lv_open_picklist > 0) then
                      -- only add message to log when it concerns a reservation for another work order than the previous one
                      gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                      write_log('select_first_wo: '|| gv_message, 5);
                      gv_message := 'Pick list '|| lv_open_picklist || ' for this work order has not been confirmed and picked yet!';
                      write_log('select_first_wo: '|| gv_message, 5);
                      lv_prv_workordernumber := lv_ref_workordernumber;
                    else
                      -- RVI 03-03-2015 Begin
                      -- select current work order as Reference work order and loop should be ended
                      --lv_first_wo_found := true;

                      -- check if there is enough stock for at least one the WO lines to issue
                      lv_stock_found := 0;
                      -- check all reservations in a loop
                      for wolr_rec in get_wolr_lines(fp_ref_wo_id, fp_areacode) loop
                        lv_stock_found := lv_stock_found + 1;
                      end loop;
                      -- if no locations found then work order should be skipped since it will crash the pick list
                      if (lv_stock_found = 0) then
                        -- only add message to log when it concerns a reservation for another work order than the previous one
                        gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                        write_log('select_first_wo: '|| gv_message, 5);
                        gv_message := 'No stockroom location could be determined for any order line!';
                        write_log('select_first_wo: '|| gv_message, 5);
                        lv_prv_workordernumber := lv_ref_workordernumber;
                      else
                        -- Check if there is anything to pick for WO, if not then skip to avoid double pick list lines
                        if (f_wo_has_items_to_pick(fp_ref_wo_id,null,fp_areacode,lv_allowsplit)) then
                        -- select current work order as Reference work order and loop should be ended
                          lv_first_wo_found := true;
                        else
                          -- only add message to log when it concerns a reservation for another work order than the previous one
                          gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
                          write_log('select_first_wo: '|| gv_message, 5);
                          gv_message := 'No items can be picked for any order line!';
                          write_log('select_first_wo: '|| gv_message, 5);
                          lv_prv_workordernumber := lv_ref_workordernumber;
                        end if;
                      end if;
                      -- RVI 03-03-2015 End
                    end if;
                  end;
                end if;
              end if;
            end if;
          end if;
        end loop;
      -- if no reference work order found after reading last record from cursor
      if (lv_last_wo_read) then
        raise no_data_found;
      end if;
      -- close cursor
      close get_reference_wo;
      -- add found reference work order number to log
      write_log('Succesfully ran select_first_wo, reference workorder found = ' || lv_ref_workordernumber, 5);
      --
      return(lv_msg_nr);
  exception
    when no_data_found then
      begin
        -- close cursor in case of exception
        if (get_reference_wo%isopen) then
          close get_reference_wo;
        end if;
        gv_message := 'No work orders found';
        write_log('Error select_first_wo: '|| gv_message, 3);
        -- Add some debug messages to inform user about possible cause of failure
        write_log('Possible reasons why no work orders could be found:', 3);
        write_log('1. Work order is already connected to another pick list', 3);
        write_log('2. There are not sufficient items on stock to cover demand for a work order in case no phased delivery is allowed', 3);
        write_log('3. The requested items are stored on non-picking locations', 3);
        write_log('4. The requested items are stored on locations belonging to a different area', 3);
        --
        lv_msg_nr := 101;
        return(lv_msg_nr);  --todo
      end;
    when others then
      begin
        -- close cursor in case of exception
        if (get_reference_wo%isopen) then
          close get_reference_wo;
        end if;
        gv_message := 'Error reading work orders';
        write_log(sqlerrm, 5);
        write_log('Error select_first_wo: '|| gv_message, 3);
        lv_msg_nr := 102;  -- todo
        return(lv_msg_nr);
      end;
    end;
  end select_first_WO;


  function f_picklistline_exists(fp_picklist_id     in number,
                                 fp_srg_id          in number,
                                 fp_stocktype       in picklistline.stocktype%type,
                                 fp_picklistline_id out number) return boolean is

    lv_result          number;
    lv_picklistline_id number;
  begin
    select pl.picklistline_id, 1
      into lv_picklistline_id, lv_result
      from picklistline pl
     where pl.picklist_id = fp_picklist_id
       and pl.stockreservationpergrade_id =  fp_srg_id
       and pl.stocktype = fp_stocktype;
     -- set found picklistline_id for output
     fp_picklistline_id := lv_picklistline_id;
     return (lv_result = 1);
  exception
    when no_data_found then
      begin
        return false;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('f_picklistline_exists: Others ' || gv_message, 5);
        return false;
      end;
   end f_picklistline_exists;


  function f_picklistlinelocation_exists(fp_picklistline_id      in number,
                                         fp_stockroomlocation_id in number,
                                         fp_picklistlocation_id  out number) return boolean is

    lv_result              number;
    lv_picklistlocation_id number;
  begin
    select pll.picklistlocation_id, 1
      into lv_picklistlocation_id, lv_result
      from picklistlinelocation pll
     where pll.picklistline_id = fp_picklistline_id
       and pll.stockroomlocation_id =  fp_stockroomlocation_id;
     -- set found picklistlocation_id for output
     fp_picklistlocation_id := lv_picklistlocation_id;
     return (lv_result = 1);
  exception
    when no_data_found then
      begin
        return false;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('picklistlinelocation_exists: Others ' || gv_message, 5);
        return false;
      end;
   end f_picklistlinelocation_exists;


  function f_picklistlineorigin_exists(fp_picklistline_id       in number,
                                       fp_origin                in number,
                                       fp_baselinetable         in picklistlineorigin.baselinetable%type,
                                       fp_baselinetable_id      in number,
                                       fp_picklistlineorigin_id out number) return boolean is

    lv_result                number;
    lv_picklistlineorigin_id number;
  begin
    select plo.picklistlineorigin_id, 1
      into lv_picklistlineorigin_id, lv_result
      from picklistlineorigin plo
     where plo.picklistline_id = fp_picklistline_id
       and plo.baselinetype = fp_origin
       and plo.baselinetable_link_id = fp_baselinetable_id
       and plo.baselinetable = fp_baselinetable;
     -- set found picklistlineorigin_id for output
     fp_picklistlineorigin_id := lv_picklistlineorigin_id;
     return (lv_result = 1);
  exception
    when no_data_found then
      begin
        return false;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('f_picklistlineorigin_exists: Others ' || gv_message, 5);
        return false;
      end;
   end f_picklistlineorigin_exists;


  function f_picklistpicksequence_exists(fp_picklistid                in number,
                                         fp_picklistlineid            in number,
                                         fp_picklistlineoriginid      in number,
                                         fp_picklistlocationid        in number,
                                         fp_picklistpickingsequenceid out number) return boolean is

    lv_result                    number;
    lv_picklistpickingsequenceid number;
  begin
    select pps.picklistpickingsequence_id, 1
      into lv_picklistpickingsequenceid, lv_result
      from picklistpickingsequence pps
     where pps.picklist_id = fp_picklistid
       and pps.picklistline_id = fp_picklistlineid
       and pps.picklistlineorigin_id = fp_picklistlineoriginid
       and pps.picklistlocation_id = fp_picklistlocationid;
     -- set found picklistlinepickingsequnce_id for output
     fp_picklistpickingsequenceid := lv_picklistpickingsequenceid;
     return (lv_result = 1);
  exception
    when no_data_found then
      begin
        return false;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error f_picklistpicksequence_exists: Others ' || gv_message, 5);
        return false;
      end;
   end f_picklistpicksequence_exists;


  procedure create_picklist(fp_stockroomid    in number,
                            fp_areacode       in stockroomlocation.areacode%type,
                            fp_mobiledeviceid in number,
                            fp_systemuserid   in number,
                            fp_picklistid     out number,
                            fp_picklistnumber out number,
                            fp_messagenumber  out number) is

    lv_picklistrec           picklist%rowtype;
    lv_businessunitcode      businessunit.code%type;
    lv_picklistnumber        picklist.picklistnumber%type;

    procedure init_picklist(fp_picklistrec in out picklist%rowtype) is
      lv_query varchar2(1000);
      type cur_typ is ref cursor;
      rcur_typ cur_typ;
    begin
      --fill the PICKLIST row fp_picklistrec with default values from table picklist
      lv_query := build_init_query('PICKLIST');
      open rcur_typ for lv_query;
      fetch rcur_typ
        into fp_picklistrec;
      close rcur_typ;
    end init_picklist;

  begin
    -- init picklist, fill with default values
    gv_message := 'init picklist';
    init_picklist(lv_picklistrec);
    -- set businessunit
    gv_message := 'businessunit ' || lv_businessunitcode;
    get_businessunit_info(fp_stockroomid, lv_picklistrec.businessunit_id, lv_businessunitcode);
    -- set stockroom
    lv_picklistrec.processingstockroom_id := fp_stockroomid;
    -- set area
    lv_picklistrec.areacode := fp_areacode;
    -- set mobile device
    lv_picklistrec.mobiledevice_id := fp_mobiledeviceid;
    -- set status '10' (Proposal)
    get_pickliststatusid('10',lv_picklistrec.status_id);
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_picklistrec.systemuser_id := fp_systemuserid;
      lv_picklistrec.creationuser_id := fp_systemuserid;
    else
      lv_picklistrec.systemuser_id := gv_picking_userid;
      lv_picklistrec.creationuser_id := gv_picking_userid;
    end if;
    -- set origin
    if (fp_mobiledeviceid is not null) then
      lv_picklistrec.origin := 3; -- from PDA
    else
      lv_picklistrec.origin := 1; -- via WOSC
    end if;
    -- set picklist type
    lv_picklistrec.picklisttype := 2; -- Optimized picklist
    -- set processing timestamp
    lv_picklistrec.timestamp := sysdate;
    lv_picklistrec.creationtimestamp := lv_picklistrec.timestamp;
    -- set printed flag
    lv_picklistrec.picklistprinted := 'Y';

    -- get picklist number
    gv_message := 'pick list number for businessunit ' || lv_businessunitcode;
    execute immediate 'select seq_picklist_' || lv_businessunitcode || '.nextval from dual'
      into lv_picklistnumber;
    lv_picklistrec.picklistnumber := lv_picklistnumber;
    -- get picklist ID
    select seq_picklist.nextval into lv_picklistrec.picklist_id from dual;
    fp_picklistid                       := lv_picklistrec.picklist_id;
    --create picklist
    gv_message := 'insert into picklist';
    insert into picklist values lv_picklistrec;
    --commit
    write_log('Succesfully ran create_picklist ' || lv_picklistnumber || ' created.', 1);
    --all ok return 0
    fp_messagenumber := 0;
    fp_picklistnumber := lv_picklistnumber;
  exception
    when no_data_found then
      begin
        write_log('Error ceate_picklist: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create_picklist: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_picklist: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end create_picklist;


  procedure create_picklistline(fp_picklistid     in number,
                                fp_srg_id         in number,
                                fp_stocktype      in picklistline.stocktype%type,
                                fp_quantity       in number,
                                fp_systemuserid   in number,
                                fp_picklistlineid out number,
                                fp_messagenumber  out number) is

    lv_picklistlinerec       picklistline%rowtype;
    lv_picklistlinenumber    picklistline.linenumber%type;

    procedure init_picklistline(fp_picklistlinerec in out picklistline%rowtype) is
      lv_query varchar2(1000);
      type cur_typ is ref cursor;
      rcur_typ cur_typ;
    begin
      --fill the PICKLISTLINE row fp_picklistlinerec with default values from table picklistline
      lv_query := build_init_query('PICKLISTLINE');
      open rcur_typ for lv_query;
      fetch rcur_typ
        into fp_picklistlinerec;
      close rcur_typ;
    end init_picklistline;

    -- Determine the last used linenumber for this picklist + 1
    function get_linenumber(cp_picklistid in number) return number is
      lv_linenumber number;
    begin
       select (nvl(max(pl.linenumber),0) + 1)
         into lv_linenumber
         from picklistline pl
        where pl.picklist_id = cp_picklistid;
        return lv_linenumber;
    end get_linenumber;

  begin
    -- init picklistline, fill with default values
    gv_message := 'init picklistline';
    init_picklistline(lv_picklistlinerec);
    -- set link to parent
    lv_picklistlinerec.picklist_id := fp_picklistid;
    -- set stockreservationpergrade
    lv_picklistlinerec.stockreservationpergrade_id := fp_srg_id;
    -- set stocktype
    lv_picklistlinerec.stocktype := fp_stocktype;
    -- set qty to pick
    lv_picklistlinerec.qtytopick := fp_quantity;
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_picklistlinerec.systemuser_id := fp_systemuserid;
    else
      lv_picklistlinerec.systemuser_id := gv_picking_userid;
    end if;
    -- set processing timestamp
    lv_picklistlinerec.timestamp := sysdate;
    -- get picklistline ID
    select seq_picklistline.nextval into lv_picklistlinerec.picklistline_id from dual;
    fp_picklistlineid             := lv_picklistlinerec.picklistline_id;
    -- get linenumber
    lv_picklistlinenumber         := get_linenumber(fp_picklistid);
    lv_picklistlinerec.linenumber := lv_picklistlinenumber;
    -- create picklistline
    gv_message := 'insert into picklistline';
    insert into picklistline values lv_picklistlinerec;
    --commit
    write_log('Succesfully ran create_picklistline ' || lv_picklistlinenumber || ' created.', 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error ceate_picklistline: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create_picklistline: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_picklistline: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end create_picklistline;


  procedure update_picklistline(fp_picklistlineid in number,
                                fp_quantity       in number,
                                fp_systemuserid   in number,
                                fp_messagenumber  out number) is

    lv_systemuser_id  number;
    lv_linenumber     number;
    lv_picklistnumber number;
    -- Determine the pick list number and line number for current picklistline
    procedure get_pl_info(fp_picklistline_id in number,
                          fp_picklistnumber  out number,
                          fp_linenumber      out number) is
       cursor get_info is
         select pl.picklistnumber, pll.linenumber
           from picklistline pll, picklist pl
          where pl.picklist_id = pll.picklist_id
            and pll.picklistline_id = fp_picklistline_id;

    begin
      for pl_rec in get_info loop
        lv_picklistnumber := pl_rec.picklistnumber;
        lv_linenumber := pl_rec.linenumber;
      end loop;
      -- set return values
      fp_picklistnumber := lv_picklistnumber;
      fp_linenumber := lv_linenumber;
    end get_pl_info;

  begin
    -- init picklist, fill with default values
    gv_message := 'init picklistline';
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_systemuser_id := fp_systemuserid;
    else
      lv_systemuser_id := gv_picking_userid;
    end if;
    -- update picklistline
    gv_message := 'update picklistline';
    -- Do the actual update
    update picklistline pl
    set pl.qtytopick = pl.qtytopick + fp_quantity,
        pl.qtyrequired = pl.qtyrequired + fp_quantity,
        pl.timestamp = sysdate,
        pl.systemuser_id = lv_systemuser_id
    where pl.picklistline_id = fp_picklistlineid;
    -- get picklistnumber and linenumber
    gv_message := 'get_pl_info';
    get_pl_info(fp_picklistlineid,lv_picklistnumber,lv_linenumber);
    gv_message := 'Line number ' || lv_linenumber || ' updated for pick list ' || lv_picklistnumber || '.';
    --commit
    write_log('Succesfully ran update_picklistline.'|| gv_message, 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error update_picklistline: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error update_picklistline: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error update_picklistline: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end update_picklistline;


  procedure create_picklistlineorigin(fp_picklistlineid       in number,
                                      fp_workorderlineid      in number,
                                      fp_quantity             in number,
                                      fp_systemuserid         in number,
                                      fp_picklistlineoriginid out number,
                                      fp_messagenumber        out number) is

    lv_picklistlineoriginrec picklistlineorigin%rowtype;

    procedure init_picklistlineorigin(fp_picklistlineoriginrec in out picklistlineorigin%rowtype) is
      lv_query varchar2(1000);
      type cur_typ is ref cursor;
      rcur_typ cur_typ;
    begin
      --fill the PICKLISTLINEORIGIN row fp_picklistlineoriginrec with default values from table picklistlineorigin
      lv_query := build_init_query('PICKLISTLINEORIGIN');
      open rcur_typ for lv_query;
      fetch rcur_typ
        into fp_picklistlineoriginrec;
      close rcur_typ;
    end init_picklistlineorigin;

    function get_wo_origin(cp_workorderline_id in number) return number is
      lv_origin number;
    begin
      select wo.origin
        into lv_origin
        from workorderline wol, workorder wo
       where wo.workorder_id = wol.workorder_id
         and wol.workorderline_id = cp_workorderline_id;
        return lv_origin;
    end get_wo_origin;
  begin
    -- init picklistlineorigin, fill with default values
    gv_message := 'init picklistlineorigin';
    init_picklistlineorigin(lv_picklistlineoriginrec);
    -- set picklistline
    lv_picklistlineoriginrec.picklistline_id := fp_picklistlineid;
    -- set baselinetype
    lv_picklistlineoriginrec.baselinetype := get_wo_origin(fp_workorderlineid);
    lv_picklistlineoriginrec.baselinetable := 'WORKORDERLINE';
    lv_picklistlineoriginrec.baselinetable_link_id := fp_workorderlineid;
    -- set qty to pick
    lv_picklistlineoriginrec.qtytopick := fp_quantity;
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_picklistlineoriginrec.systemuser_id := fp_systemuserid;
    else
      lv_picklistlineoriginrec.systemuser_id := gv_picking_userid;
    end if;
    -- set processing timestamp
    lv_picklistlineoriginrec.timestamp := sysdate;
    -- get picklistlineorigin ID
    select seq_picklistlineorigin.nextval into lv_picklistlineoriginrec.picklistlineorigin_id from dual;
    fp_picklistlineoriginid            := lv_picklistlineoriginrec.picklistlineorigin_id;
    -- create picklistline
    gv_message := 'insert into picklistlineorigin';
    insert into picklistlineorigin values lv_picklistlineoriginrec;
    --commit
    write_log('Succesfully ran create_picklistlineorigin ' || fp_picklistlineoriginid || ' created.', 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error ceate_picklistlineorigin: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create_picklistlineorigin: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_picklistlineorigin: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end create_picklistlineorigin;


  procedure update_picklistlineorigin(fp_picklistlineoriginid in number,
                                      fp_quantity             in number,
                                      fp_systemuserid         in number,
                                      fp_messagenumber        out number) is

    lv_systemuser_id  number;
    lv_linenumber     number;
    lv_picklistnumber number;

    -- Determine the pick list number and line number for current picklistlineorigin
    procedure get_pl_info(fp_picklistlineorigin_id in number,
                          fp_picklistnumber        out number,
                          fp_linenumber            out number) is
       cursor get_info is
         select pl.picklistnumber, pll.linenumber
           from picklistlineorigin plo, picklistline pll, picklist pl
          where pll.picklistline_id = plo.picklistline_id
            and pl.picklist_id = pll.picklist_id
            and plo.picklistlineorigin_id = fp_picklistlineorigin_id;

    begin
      for pl_rec in get_info loop
        lv_picklistnumber := pl_rec.picklistnumber;
        lv_linenumber := pl_rec.linenumber;
      end loop;
      -- set return values
      fp_picklistnumber := lv_picklistnumber;
      fp_linenumber := lv_linenumber;
    end get_pl_info;

  begin
    -- init picklist, fill with default values
    gv_message := 'init picklistlineorigin';
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_systemuser_id := fp_systemuserid;
    else
      lv_systemuser_id := gv_picking_userid;
    end if;
    -- update picklistlineorigin
    gv_message := 'update update_picklistlineorigin';
    -- Do the actual update
    update picklistlineorigin plo
    set plo.qtytopick = nvl(plo.qtytopick,0) + fp_quantity,
        plo.timestamp = sysdate,
        plo.systemuser_id = lv_systemuser_id
    where plo.picklistlineorigin_id = fp_picklistlineoriginid;
    -- get picklistnumber, linenumber, area, row and location
    gv_message := 'get_pl_info';
    get_pl_info(fp_picklistlineoriginid,lv_picklistnumber,lv_linenumber);
    gv_message :=  'Qty Picked '||' updated for ';
    gv_message :=  gv_message ||'line number '||lv_linenumber||' from pick list ' ||lv_picklistnumber||'.';
    --commit
    write_log('Succesfully ran update_picklistlineorigin.'|| gv_message, 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error update_picklistlineorigin: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error update_picklistlineorigin: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error update_update_picklistlineorigin: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end update_picklistlineorigin;


  procedure create_picklistlinelocation(fp_picklistlineid      in number,
                                        fp_stockroomlocationid in number,
                                        fp_quantity            in number,
                                        fp_systemuserid        in number,
                                        fp_picklistlocationid  out number,
                                        fp_messagenumber       out number) is

    lv_picklistlinelocationrec picklistlinelocation%rowtype;

    procedure init_picklistlinelocation(fp_picklistlinelocationrec in out picklistlinelocation%rowtype) is
      lv_query varchar2(1000);
      type cur_typ is ref cursor;
      rcur_typ cur_typ;
    begin
      --fill the PICKLISTLINELOCATION row fp_picklistlinelocationrec with default values from table picklistlinlocation
      lv_query := build_init_query('PICKLISTLINELOCATION');
      open rcur_typ for lv_query;
      fetch rcur_typ
        into fp_picklistlinelocationrec;
      close rcur_typ;
    end init_picklistlinelocation;

  begin
    -- init picklistlinelocation, fill with default values
    gv_message := 'init picklistlinelocation';
    init_picklistlinelocation(lv_picklistlinelocationrec);
    -- set picklistline
    lv_picklistlinelocationrec.picklistline_id := fp_picklistlineid;
    -- set stockroomlocation
    lv_picklistlinelocationrec.stockroomlocation_id := fp_stockroomlocationid;
    -- set qty to pick
    lv_picklistlinelocationrec.qtytopick := fp_quantity;
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_picklistlinelocationrec.systemuser_id := fp_systemuserid;
    else
      lv_picklistlinelocationrec.systemuser_id := gv_picking_userid;
    end if;
    -- set processing timestamp
    lv_picklistlinelocationrec.timestamp := sysdate;
    -- get picklistlocation ID
    select seq_picklistlinelocation.nextval into lv_picklistlinelocationrec.picklistlocation_id from dual;
    fp_picklistlocationid := lv_picklistlinelocationrec.picklistlocation_id;
    -- create picklistlinelocation
    gv_message := 'insert into picklistlinelocation';
    insert into picklistlinelocation values lv_picklistlinelocationrec;
    --commit
    write_log('Succesfully ran create_picklistlinelocation ' || fp_picklistlocationid || ' created.', 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error create_picklistlinelocation: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create_picklistlinelocation: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_picklistlinelocation: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end create_picklistlinelocation;


  procedure update_picklistlinelocation(fp_picklistlocation in number,
                                        fp_quantity         in number,
                                        fp_systemuserid     in number,
                                        fp_messagenumber    out number) is

    lv_systemuser_id  number;
    lv_linenumber     number;
    lv_picklistnumber number;
    lv_rowcode        stockroomlocation.rowcode%type;
    lv_locationcode   stockroomlocation.locationcode%type;
    lv_areacode       stockroomlocation.areacode%type;

    -- Determine the pick list number and line number for current picklistlinelocation
    procedure get_pl_info(fp_picklistlinelocation_id in number,
                          fp_picklistnumber          out number,
                          fp_linenumber              out number,
                          fp_areacode                out stockroomlocation.areacode%type,
                          fp_rowcode                 out stockroomlocation.rowcode%type,
                          fp_locationcode            out stockroomlocation.locationcode%type) is
       cursor get_info is
         select pl.picklistnumber, pll.linenumber, sl.rowcode, sl.locationcode, sl.areacode
           from picklistlinelocation plo, picklistline pll, picklist pl, stockroomlocation sl
          where pll.picklistline_id = plo.picklistline_id
            and pl.picklist_id = pll.picklist_id
            and sl.stockroomlocation_id = plo.stockroomlocation_id
            and plo.picklistlocation_id = fp_picklistlinelocation_id;

    begin
      for pl_rec in get_info loop
        lv_picklistnumber := pl_rec.picklistnumber;
        lv_linenumber := pl_rec.linenumber;
        lv_areacode := pl_rec.areacode;
        lv_rowcode := pl_rec.rowcode;
        lv_locationcode := pl_rec.locationcode;
      end loop;
      -- set return values
      fp_picklistnumber := lv_picklistnumber;
      fp_linenumber := lv_linenumber;
      fp_areacode := lv_areacode;
      fp_rowcode := lv_rowcode;
      fp_locationcode := lv_locationcode;
    end get_pl_info;

  begin
    -- init picklist, fill with default values
    gv_message := 'init picklistlinelocation';
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_systemuser_id := fp_systemuserid;
    else
      lv_systemuser_id := gv_picking_userid;
    end if;
    -- update picklistlinelocation
    gv_message := 'update picklistlinelocation';
    -- Do the actual update
    update picklistlinelocation pl
    set pl.qtytopick = pl.qtytopick + fp_quantity,
        pl.timestamp = sysdate,
        pl.systemuser_id = lv_systemuser_id
    where pl.picklistlocation_id = fp_picklistlocation;
    -- get picklistnumber, linenumber, area, row and location
    gv_message := 'get_pl_info';
    get_pl_info(fp_picklistlocation,lv_picklistnumber,lv_linenumber,lv_areacode,lv_rowcode,lv_locationcode);
    gv_message :=  'Area/row/location '||lv_areacode||'/'||lv_rowcode||'/'||lv_locationcode||' updated for ';
    gv_message :=  gv_message ||'line number '||lv_linenumber||' from pick list ' ||lv_picklistnumber||'.';
    --commit
    write_log('Succesfully ran update_picklistlinelocation.'|| gv_message, 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error update_picklistlinelocation: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error update_picklistlinelocation: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error update_picklistlinelocation: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end update_picklistlinelocation;


  procedure create_picklistpickingsequence(fp_picklistid                in number,
                                           fp_picklistlineid            in number,
                                           fp_picklistlineoriginid      in number,
                                           fp_picklistlocationid        in number,
                                           fp_quantity                  in number,
                                           fp_systemuserid              in number,
                                           fp_picklistpickingseqeunceid out number,
                                           fp_messagenumber             out number) is

    lv_picklistpickingsequencerec  picklistpickingsequence%rowtype;
    lv_pickinglinenumber           picklistpickingsequence.pickinglinenumber%type;

    procedure init_picklistpickingsequence(fp_picklistpickingsequencerec in out picklistpickingsequence%rowtype) is
      lv_query varchar2(1000);
      type cur_typ is ref cursor;
      rcur_typ cur_typ;
    begin
      --fill the PICKLISTPICKINGSEQUENCE row fp_picklistpickingsequencerec with default values from table picklistpickingsequence
      lv_query := build_init_query('PICKLISTPICKINGSEQUENCE');
      open rcur_typ for lv_query;
      fetch rcur_typ
        into fp_picklistpickingsequencerec;
      close rcur_typ;
    end init_picklistpickingsequence;

    -- Determine the last used pickinglinenumber for this picklist + 1
    function get_linenumber(cp_picklistid in number) return number is
      lv_linenumber number;
    begin
       select (nvl(max(ps.pickinglinenumber),0) + 1)
         into lv_linenumber
         from picklistpickingsequence ps
        where ps.picklist_id = cp_picklistid;
        return lv_linenumber;
    end get_linenumber;
  begin
    -- init picklistpickingsequence, fill with default values
    gv_message := 'init picklistpickingsequence';
    init_picklistpickingsequence(lv_picklistpickingsequencerec);
    -- set picklist
    lv_picklistpickingsequencerec.picklist_id := fp_picklistid;
    -- set picklistline
    lv_picklistpickingsequencerec.picklistline_id := fp_picklistlineid;
    -- set link to workorderline
    lv_picklistpickingsequencerec.picklistlineorigin_id := fp_picklistlineoriginid;
    -- set link to stockroomlocation
    lv_picklistpickingsequencerec.picklistlocation_id := fp_picklistlocationid;
    -- set qty to pick
    lv_picklistpickingsequencerec.qtytopick := fp_quantity;
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_picklistpickingsequencerec.systemuser_id := fp_systemuserid;
    else
      lv_picklistpickingsequencerec.systemuser_id := gv_picking_userid;
    end if;
    -- set processing timestamp
    lv_picklistpickingsequencerec.timestamp := sysdate;
    -- get picklistpickingsequence ID
    select seq_picklistpickingsequence.nextval into lv_picklistpickingsequencerec.picklistpickingsequence_id from dual;
    fp_picklistpickingseqeunceid := lv_picklistpickingsequencerec.picklistpickingsequence_id;
    -- get pickinglinenumber
    lv_pickinglinenumber          := get_linenumber(fp_picklistid);
    lv_picklistpickingsequencerec.pickinglinenumber := lv_pickinglinenumber;
    -- create picklistpickingsequence
    gv_message := 'insert into picklistpickingsequence';
    insert into picklistpickingsequence values lv_picklistpickingsequencerec;
    --commit
    write_log('Succesfully ran create_picklistpickingsequence ' || fp_picklistlocationid || ' created.', 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error picklistpickingsequence: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create_picklistpickingsequence: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_picklistpickingsequence: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end create_picklistpickingsequence;


  procedure update_picklistpickingsequence(fp_picklistpickingsequenceid in number,
                                           fp_quantity                  in number,
                                           fp_systemuserid              in number,
                                           fp_messagenumber             out number) is

    lv_systemuser_id  number;
    lv_linenumber     number;
    lv_picklistnumber number;

    -- Determine the pick list number and line number for current picklistlineorigin
    procedure get_pl_info(fp_picklistpickingsequenceid in number,
                          fp_picklistnumber            out number,
                          fp_linenumber                out number) is
       cursor get_info is
         select pl.picklistnumber, pll.linenumber
           from picklistpickingsequence pps, picklistline pll, picklist pl
          where pll.picklistline_id = pps.picklistline_id
            and pl.picklist_id = pps.picklist_id
            and pps.picklistpickingsequence_id = fp_picklistpickingsequenceid;

    begin
      for pl_rec in get_info loop
        lv_picklistnumber := pl_rec.picklistnumber;
        lv_linenumber := pl_rec.linenumber;
      end loop;
      -- set return values
      fp_picklistnumber := lv_picklistnumber;
      fp_linenumber := lv_linenumber;
    end get_pl_info;

  begin
    -- init picklist, fill with default values
    gv_message := 'init picklistpickingsequence';
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_systemuser_id := fp_systemuserid;
    else
      lv_systemuser_id := gv_picking_userid;
    end if;
    -- update picklistpickingsequence
    gv_message := 'update picklistpickingsequence';
    -- Do the actual update
    update picklistpickingsequence pps
    set pps.qtytopick = pps.qtytopick + fp_quantity,
        pps.timestamp = sysdate,
        pps.systemuser_id = lv_systemuser_id
    where pps.picklistpickingsequence_id = fp_picklistpickingsequenceid;
    -- get picklistnumber, linenumber, area, row and location
    gv_message := 'get_pl_info';
    get_pl_info(fp_picklistpickingsequenceid,lv_picklistnumber,lv_linenumber);
    gv_message :=  'Qty Picked '||' updated for ';
    gv_message :=  gv_message ||'line number '||lv_linenumber||' from pick list ' ||lv_picklistnumber||'.';
    --commit
    write_log('Succesfully ran update_picklistpickingsequence.'|| gv_message, 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error update_picklistpickingsequence: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error update_picklistpickingsequence: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error update_update_picklistlineorigin: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end update_picklistpickingsequence;


  procedure create_picklist_lines(fp_picklistid     in number,
                                  fp_areacode       in stockroomlocation.areacode%type,
                                  fp_wo_id          in number,
                                  -- RVI 02-03-2015 Begin
                                  fp_reference_woid in number,
                                  -- RVI 02-03-2015 End
                                  fp_systemuserid   in number,
                                  -- RVI 15-01-2015 Begin
                                  fp_qty_to_add_max in number,
                                  -- RVI 15-01-2015 End
                                  -- RVI 01-05-2015 Begin
                                  fp_qty_added      out number,
                                  -- RVI 01-05-2015 End
                                  fp_messagenumber  out number) is

    cursor get_wolr_lines is
      -- RVI 06-03-2015 Begin
      select *
      from
      (
      select y.*,
      ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
         from picklistlineorigin plo, picklistline pll, picklist pl
        where pll.picklistline_id = plo.picklistline_id
          and pl.picklist_id = pll.picklist_id
          and plo.baselinetable_link_id = y.workorderline_id
          and plo.baselinetable = 'WORKORDERLINE'
          and pl.status_id in (select s.status_id
                                 from status s
                                where s.statustype = 'PL'
       -- RVI 17-04-2015 Begin
                                  --and s.code not in ('20','30','40','60'))) +
                                  and s.code in ('10'))) +
       (select nvl(sum(plo.qtypicked - plo.qtyissued),0)
          from picklistlineorigin plo, picklistline pll, picklist pl
         where pll.picklistline_id = plo.picklistline_id
           and pl.picklist_id = pll.picklist_id
           and plo.baselinetable_link_id = y.workorderline_id
           and plo.baselinetable = 'WORKORDERLINE'
           and pl.status_id in (select s.status_id
                                  from status s
                                 where s.statustype = 'PL'
                                   and s.code in ('50'))) +
       -- RVI 17-04-2015 End
       (select nvl(sum(plo.qtypicked),0)
          from picklistlineorigin plo, picklistline pll, picklist pl
         where pll.picklistline_id = plo.picklistline_id
           and pl.picklist_id = pll.picklist_id
           and plo.baselinetable_link_id = y.workorderline_id
           and plo.baselinetable = 'WORKORDERLINE'
           and pl.status_id in (select s.status_id
                                  from status s
                                 where s.statustype = 'PL'
                                   and s.code in ('20','30')))) quantity_picked,
      ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
          from picklist pl, picklistline pll, picklistlineorigin plo
         where pll.picklist_id = pl.picklist_id
           and plo.picklistline_id = pll.picklistline_id
           and plo.baselinetable = 'WORKORDERLINE'
           and plo.baselinetable_link_id != y.workorderline_id
           and pll.stockreservationpergrade_id = y.stockreservationpergrade_id
           and pll.stocktype = y.stocktype
           and pll.qtypicked = 0
           and pll.confirmedcompletely = 'N'
           and pl.status_id in (select s.status_id
                                  from status s
                                 where s.statustype = 'PL'
                                   and s.code in ('10','20'))) +
       (select nvl(sum(plo.qtypicked),0)
          from picklist pl, picklistline pll, picklistlineorigin plo
         where pll.picklist_id = pl.picklist_id
           and plo.picklistline_id = pll.picklistline_id
           and plo.baselinetable = 'WORKORDERLINE'
           and plo.baselinetable_link_id != y.workorderline_id
           and pll.stockreservationpergrade_id = y.stockreservationpergrade_id
           and pll.stocktype = y.stocktype
           and ((pll.confirmedcompletely = 'Y')
            or  (pll.confirmedcompletely = 'N' and pll.qtypicked > 0))
           and pl.status_id in (select s.status_id
                                  from status s
                                 where s.statustype = 'PL'
                                   and s.code in ('20')))) qty_picked_other_wo,
       -- RVI 01-05-2015 Begin
       case
         when (y.stocktype = 1) then
         (select nvl(sum(sq.qtynonunique),0)
            from stockquantity sq, stockroomlocation sl, locationtype lt
           where sl.stockroomlocation_id = sq.stockroomlocation_id
             and sq.stockreservationpergrade_id = y.stockreservationpergrade_id
             and lt.locationtype_id = sl.locationtype_id
             and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
             and sq.qtynonunique > 0
             and lt.pickinglocation = 'Y')
         when (y.stocktype = 2) then
         (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
            from stockquantity sq, stockroomlocation sl, locationtype lt
           where sl.stockroomlocation_id = sq.stockroomlocation_id
             and sq.stockreservationpergrade_id = y.stockreservationpergrade_id
             and lt.locationtype_id = sl.locationtype_id
             and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
             and (sq.qtyunique > 0 or sq.qtynonunique > 0)
             and lt.pickinglocation = 'Y')
         when (y.stocktype = 3) then
         (select nvl(sum(sq.qtyuniquewithmodifications),0)
            from stockquantity sq, stockroomlocation sl, locationtype lt
           where sl.stockroomlocation_id = sq.stockroomlocation_id
             and sq.stockreservationpergrade_id = y.stockreservationpergrade_id
             and lt.locationtype_id = sl.locationtype_id
             and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
             and sq.qtyuniquewithmodifications > 0
             and lt.pickinglocation = 'Y')
       end qty_on_stock
       -- RVI 01-05-2015 End
      from
      (
      select x.origin,x.workorderline_id, x.stockreservationpergrade_id, x.stocktype, sum(x.quantity) quantity
        from (
          select wolr.*, wo.origin
            from workorderline wol, workorderlinereservation wolr, workorder wo
           where wolr.workorderline_id = wol.workorderline_id
             and wo.workorder_id = wol.workorder_id
             and wol.workorder_id = fp_wo_id
             and exists (select 1
                           from stockquantity sq, stockroomlocation sl, locationtype lt
                          where sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                            and sl.stockroomlocation_id = sq.stockroomlocation_id
                            and lt.locationtype_id = sl.locationtype_id
                            and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                            and lt.pickinglocation = 'Y'
                            and (case
                                   when (wolr.stocktype = 1) then sq.qtynonunique
                                   when (wolr.stocktype = 2) then sq.qtyunique
                                   when (wolr.stocktype = 3) then sq.qtyuniquewithmodifications
                                 end > 0))
             -- RVI 03-04-2015 Begin
             /*
             and (((select count(*)
                     from workorderitemdistribution wid
                    where wid.workorder_id = wol.workorder_id
                      and wid.picklist_id = fp_picklistid
                      and wid.workorderline_id = wolr.workorderline_id
                      and wid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                      and wid.stocktype = wolr.stocktype ) > 0)
                      or fp_reference_woid is null)
             */
             -- RVI 03-04-2015 End
             ) x
         group by x.origin, x.workorderline_id, x.stockreservationpergrade_id, x.stocktype) y)
      -- RVI 03-04-2015 Begin
      --   where quantity - quantity_picked - qty_picked_other_wo > 0;
         where quantity - quantity_picked  > 0;
      -- RVI 03-04-2015 End
      -- RVI 06-03-2015 End

    lv_picklistline_id       number := -1;
    lv_picklistlineorigin_id number;
    lv_messagenumber         number := -1;
    lv_lines_selected        number := 0;
    -- RVI 15-01-2015 Begin
    lv_qty_to_add_max        number := 0;
    lv_qty_added             number := 0;
    lv_qty_to_add            number := 0;
    -- RVI 15-01-2015 End
    -- RVI 01-05-2015 Begin
    -- RVI 01-05-2015 End
  begin
    -- RVI 15-01-2015 Begin
    lv_qty_to_add_max := fp_qty_to_add_max;
    -- for each workorderline that matches the area code create picklist line + rows in underlying tables
    -- filter on areacode
    for wolr_rec in get_wolr_lines loop
       -- count lines selected
       lv_lines_selected := lv_lines_selected + 1;
       -- RVI 15-01-2015 Begin
       -- RVI 06-03-2015 Begin
       --if (wolr_rec.quantity <= lv_qty_to_add_max) then
       --  lv_qty_to_add := wolr_rec.quantity;
       --if (wolr_rec.quantity - wolr_rec.quantity_picked - wolr_rec.qty_picked_other_wo <= lv_qty_to_add_max) then
       --  lv_qty_to_add := wolr_rec.quantity - wolr_rec.quantity_picked - wolr_rec.qty_picked_other_wo;
       if (wolr_rec.quantity - wolr_rec.quantity_picked <= lv_qty_to_add_max) then
         lv_qty_to_add := wolr_rec.quantity - wolr_rec.quantity_picked;
       -- RVI 06-03-2015 End
       -- RVI 01-05-2015 Begin
       -- take into account any items that were already allocated for other wo on previous pick list(s)
       -- and therefore no longer available for current pick list. This implies that qty_to_add may have to be reduced
         if ((wolr_rec.qty_on_stock - wolr_rec.qty_picked_other_wo) <= lv_qty_to_add) then
           lv_qty_to_add := wolr_rec.qty_on_stock - wolr_rec.qty_picked_other_wo;
         end if;
       -- RVI 01-05-2015 End
         lv_qty_to_add_max := lv_qty_to_add_max - lv_qty_to_add;
       else
         lv_qty_to_add := lv_qty_to_add_max;
         lv_qty_to_add_max := 0;
       end if;
       if (lv_qty_to_add > 0) then
         begin
           -- RVI 01-05-2015 Begin
           lv_qty_added := lv_qty_added + lv_qty_to_add;
           -- RVI 01-05-2015 End
       -- RVI 15-01-2015 End
          -- start creation of pick list line for work order line reservation for reference work order
           if (f_picklistline_exists(fp_picklistid, wolr_rec.stockreservationpergrade_id,
                                     wolr_rec.stocktype, lv_picklistline_id)) then
             -- Update the existing picklistline record
             if (lv_picklistline_id > 0) then
               -- RVI 15-01-2015 Begin
               --update_picklistline(lv_picklistline_id, wolr_rec.quantity, fp_systemuserid, lv_messagenumber);
               update_picklistline(lv_picklistline_id, lv_qty_to_add, fp_systemuserid, lv_messagenumber);
               -- RVI 15-01-2015 End
             end if;
           else
             -- Create a picklistline record
             -- RVI 15-01-2015 Begin
             --create_picklistline(fp_picklistid, wolr_rec.stockreservationpergrade_id, wolr_rec.stocktype, wolr_rec.quantity,
             --                    fp_systemuserid, lv_picklistline_id, lv_messagenumber);
             create_picklistline(fp_picklistid, wolr_rec.stockreservationpergrade_id, wolr_rec.stocktype, lv_qty_to_add,
                                 fp_systemuserid, lv_picklistline_id, lv_messagenumber);
             -- RVI 15-01-2015 End
           end if;
           if (lv_picklistline_id > 0) then
             if (f_picklistlineorigin_exists(lv_picklistline_id, wolr_rec.origin, 'WORKORDERLINE', wolr_rec.workorderline_id,
                                           lv_picklistlineorigin_id)) then
               -- Update the existing picklistlineorigin record
               if (lv_picklistlineorigin_id > 0) then
                 -- RVI 15-01-2015 Begin
                 --update_picklistlineorigin(lv_picklistlineorigin_id,wolr_rec.quantity, fp_systemuserid, lv_messagenumber);
                 update_picklistlineorigin(lv_picklistlineorigin_id, lv_qty_to_add, fp_systemuserid, lv_messagenumber);
                -- RVI 15-01-2015 End
               end if;
             else
               -- create a picklistlineorigin record
               -- RVI 15-01-2015 Begin
               --create_picklistlineorigin (lv_picklistline_id, wolr_rec.workorderline_id, wolr_rec.quantity, fp_systemuserid,
               --                           lv_picklistlineorigin_id, lv_messagenumber);
               create_picklistlineorigin (lv_picklistline_id, wolr_rec.workorderline_id, lv_qty_to_add, fp_systemuserid,
                                          lv_picklistlineorigin_id, lv_messagenumber);
               -- RVI 15-01-2015 End
             end if;
           end if;
       -- RVI 15-01-2015 Begin
         end;
       end if;
       -- RVI 15-01-2015 End
    end loop;
    if (lv_lines_selected = 0) then
      gv_message := 'Pick list will be cancelled because no stock can be found for reference work order';
      write_log('Error create_picklist_lines: '|| gv_message, 3);
    end if;
    fp_messagenumber := lv_messagenumber;
    -- RVI 01-05-2015 Begin
    fp_qty_added := lv_qty_added;
    -- RVI 01-05-2015 End
  exception
    when no_data_found then
      begin
        write_log('Error ceate_picklist_lines: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
        -- RVI 01-05-2015 Begin
        fp_qty_added := 0;
        -- RVI 01-05-2015 End
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_picklist_lines: Others ' || gv_message, 3);
        fp_messagenumber := 113;
        -- RVI 01-05-2015 Begin
        fp_qty_added := 0;
        -- RVI 01-05-2015 End
      end;
  end create_picklist_lines;


  procedure update_workorder(fp_workorderid   in number,
                             fp_systemuserid  in number,
                             fp_messagenumber out number) is

    cursor get_wo(cp_workorder_id number) is
      select *
        from workorder w
       where w.workorder_id = cp_workorder_id
         for update;

    lv_systemuser_id   number;
    lv_workordernumber number;

  begin
    -- set systemuser
    if (fp_systemuserid is not null) then
      lv_systemuser_id := fp_systemuserid;
    else
      lv_systemuser_id := gv_picking_userid;
    end if;
    -- update workorder
    gv_message := 'update workorder';

    for wo_rec in get_wo(fp_workorderid) loop
      lv_workordernumber := wo_rec.workordernumber;
      -- Do the actual update
      update workorder wo
      set wo.systemuser_id = lv_systemuser_id,
          wo.timestamp = sysdate,
          wo.picklistprinted = 'Y'
       where current of get_wo;
    end loop;
    -- determine work order number
    gv_message := 'PickListPrinted flag updated for workorder ' || lv_workordernumber || '.';
    write_log('Succesfully ran update_workorder.'|| gv_message, 5);
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error update_workorder: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error update_workorder: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error update_workorder: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end update_workorder;


  procedure determine_item_distr_for_wo(fp_reference_wo_id in number,
                                        fp_picklist_id     in number,
                                        fp_stockroom_id    in number,
                                        fp_areacode        in stockroomlocation.areacode%type,
                                        -- RVI 15-01-2015 Begin
                                        fp_qty_to_add_max  in number,
                                        -- RVI 15-01-2015 End
                                        -- RVI 15-05-2015 Begin
                                        fp_qty_added_for_wo out number,
                                        -- RVI 15-05-2015 End
                                        fp_messagenumber   out number) is
  /* find all reservations for work order */
    cursor get_wolr_lines is
      -- RVI 05-03-2015 Begin
      select x.*
        from (
      select wolr.*,
             ((select nvl(sum(plo.qtytopick - plo.qtyissued -
                              plo.qtycancelled - plo.qtycancelledpl),
                          0)
                 from picklistlineorigin plo, picklistline pll, picklist pl
                where pll.picklistline_id = plo.picklistline_id
                  and pl.picklist_id = pll.picklist_id
                  and plo.baselinetable_link_id = wolr.workorderline_id
                  and plo.baselinetable = 'WORKORDERLINE'
                  and pl.picklist_id != fp_picklist_id
                  and pl.status_id in
                      (select s.status_id
                         from status s
                        where s.statustype = 'PL'
                          and s.code not in ('20', '30', '40', '60'))) +
             (select nvl(sum(plo.qtypicked), 0)
                 from picklistlineorigin plo, picklistline pll, picklist pl
                where pll.picklistline_id = plo.picklistline_id
                  and pl.picklist_id = pll.picklist_id
                  and plo.baselinetable_link_id = wolr.workorderline_id
                  and plo.baselinetable = 'WORKORDERLINE'
                  and pl.picklist_id != fp_picklist_id
                  and pl.status_id in
                      (select s.status_id
                         from status s
                        where s.statustype = 'PL'
                          and s.code in ('20', '30')))) quantity_picked,
             -- RVI 06-03-2015 Begin
             ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                  where pll.picklist_id = pl.picklist_id
                  and plo.picklistline_id = pll.picklistline_id
                  and plo.baselinetable = 'WORKORDERLINE'
                  and plo.baselinetable_link_id != wolr.workorderline_id
                  and pll.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                  and pll.stocktype = wolr.stocktype
                  and pll.qtypicked = 0
                  and pll.confirmedcompletely = 'N'
                  -- RVI 19-05-2015 Begin
                  and pl.picklist_id != fp_picklist_id
                  -- RVI 19-05-2015 End
                  and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
                                          and s.code in ('10','20')))
                  +
             (select nvl(sum(plo.qtypicked),0)
                  from picklist pl, picklistline pll, picklistlineorigin plo
                  where pll.picklist_id = pl.picklist_id
                  and plo.picklistline_id = pll.picklistline_id
                  and plo.baselinetable = 'WORKORDERLINE'
                  and plo.baselinetable_link_id != wolr.workorderline_id
                  and pll.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                  and pll.stocktype = wolr.stocktype
                  and ((pll.confirmedcompletely = 'Y')
                   or  (pll.confirmedcompletely = 'N' and pll.qtypicked > 0))
                  -- RVI 19-05-2015 Begin
                  and pl.picklist_id != fp_picklist_id
                  -- RVI 19-05-2015 End
                  and pl.status_id in (select s.status_id
                                         from status s
                                        where s.statustype = 'PL'
                                          and s.code in ('20')))) qty_picked_other_wo,
             -- RVI 06-03-2015 End
             -- RVI 24-03-2015 Begin
             (select sum(wolr2.quantity)
               from workorderlinereservation wolr2
              where wolr2.workorderline_id = wolr.workorderline_id
                and wolr2.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                and wolr2.stocktype = wolr.stocktype) quantity_reserved,
             -- RVI 24-03-2015 End
             -- RVI 02-04-2015 Begin
             (select nvl(sum(wolr3.quantity),0)
             from workorderlinereservation wolr3
            where wolr3.workorderline_id = wolr.workorderline_id
              and wolr3.stockreservationpergrade_id = wolr.stockreservationpergrade_id
              and wolr3.stocktype = wolr.stocktype
              and wolr3.sequencenumber < wolr.sequencenumber) qty_prev_sequence
             -- RVI 02-04-2015 End
        from workorderline wol, workorderlinereservation wolr
       where wolr.workorderline_id = wol.workorderline_id
         and wol.workorder_id = fp_reference_wo_id) x
       --where x.quantity - x.quantity_picked - x.qty_picked_other_wo > 0;
       --where x.quantity - x.quantity_picked > 0;
       where x.quantity_reserved - x.quantity_picked > 0;
      -- RVI 05-03-2015 End

  /* find all possible locations for product/size/grade sorted on priority in the following order
     1. standard location for specific product size
     2. standard location for product
     3. overflow locations */
    cursor get_locations(cp_stockreservationpergrade_id in number,
                         cp_stocktype                   in number) is
      select x.*
        from
          ((select sl.stockroomlocation_id, sl.rowcode, sl.locationcode, slp.priority,
                 sl.areacode, sl.pickingsequence,
                 case
                   when cp_stocktype = 1 then sq.qtynonunique
                 -- RVI 13-01-2014 Begin
                 --  when cp_stocktype = 2 then sq.qtyunique
                   when cp_stocktype = 2 then (sq.qtyunique + sq.qtynonunique)
                 -- RVI 13-01-2014 Begin
                   when cp_stocktype = 3 then sq.qtyuniquewithmodifications
                 end qty_on_stock

            from stockreservationpergrade   srg,
                 stockdefinitionperitem     sdi,
                 stockquantity              sq,
                 stockroomlocation          sl,
                 locationtype               lt,
                 standardlocationperproduct slp,
                 standardlocationpersize    sls

           where sdi.stockdefinitionperitem_id = srg.stockdefinitionperitem_id
             and sq.stockreservationpergrade_id = srg.stockreservationpergrade_id
             and sl.stockroomlocation_id = sq.stockroomlocation_id
             and lt.locationtype_id = sl.locationtype_id
             and slp.stockroomlocation_id = sl.stockroomlocation_id
             and sls.standardlocationperproduct_id = slp.standardlocationperproduct_id
             and slp.product_id = sdi.product_id
             and sls.sizedefinition_id = sdi.sizedefinition_id
             and srg.stockreservationpergrade_id = cp_stockreservationpergrade_id
             and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
             and slp.definepersize = 'Y'
             and lt.pickinglocation = 'Y')
          union
         (select sl.stockroomlocation_id, sl.rowcode, sl.locationcode, slp.priority,
                 sl.areacode, sl.pickingsequence,
                 case
                   when cp_stocktype = 1 then sq.qtynonunique
                 -- RVI 13-01-2014 Begin
                 --  when cp_stocktype = 2 then sq.qtyunique
                   when cp_stocktype = 2 then (sq.qtyunique + sq.qtynonunique)
                 -- RVI 13-01-2014 Begin
                   when cp_stocktype = 3 then sq.qtyuniquewithmodifications
                 end qty_on_stock
            from stockreservationpergrade   srg,
                 stockdefinitionperitem     sdi,
                 stockquantity              sq,
                 stockroomlocation          sl,
                 locationtype               lt,
                 standardlocationperproduct slp
           where sdi.stockdefinitionperitem_id = srg.stockdefinitionperitem_id
             and sq.stockreservationpergrade_id = srg.stockreservationpergrade_id
             and sl.stockroomlocation_id = sq.stockroomlocation_id
             and lt.locationtype_id = sl.locationtype_id
             and slp.stockroomlocation_id = sl.stockroomlocation_id
             and slp.product_id = sdi.product_id
             and srg.stockreservationpergrade_id = cp_stockreservationpergrade_id
             and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
             and slp.definepersize = 'N'
             and lt.pickinglocation = 'Y')
          union
         (select sl.stockroomlocation_id, sl.rowcode, sl.locationcode, 999 priority,
                 sl.areacode, sl.pickingsequence,
                 case
                   when cp_stocktype = 1 then sq.qtynonunique
                 -- RVI 13-01-2014 Begin
                 --  when cp_stocktype = 2 then sq.qtyunique
                   when cp_stocktype = 2 then (sq.qtyunique + sq.qtynonunique)
                 -- RVI 13-01-2014 End
                   when cp_stocktype = 3 then sq.qtyuniquewithmodifications
                 end qty_on_stock
            from stockquantity     sq,
                 stockroomlocation sl,
                 locationtype      lt
           where sl.stockroomlocation_id = sq.stockroomlocation_id
             and lt.locationtype_id = sl.locationtype_id
             and sq.stockreservationpergrade_id = cp_stockreservationpergrade_id
             and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
             and sl.overflowlocation = 'Y'
             and lt.pickinglocation = 'Y')) x
           order by x.priority;


    lv_to_pick         number := 0;
    lv_picked          number := 0;
    lv_remainder       number := 0;
    lv_reserved        number := 0;
    location_rec       get_locations%rowtype;
    lv_workordernumber number;
    lv_prev_location_id number;
    -- RVI 15-01-2015 Begin
    lv_to_pick_max     number := 0;
    -- RVI 15-01-2015 End
    -- RVI 01-05-2015 Begin
    lv_qty_picked_other_wo number := 0;
    -- RVI 01-05-2015 End
    -- RVI 15-05-2015 Begin
    lv_qty_added_for_wo number := 0;
    -- RVI 15-05-2015 End
    -- RVI 02-04-2015 Begin
    lv_to_pick_wolr     number := 0;
    lv_to_pick_wolr_seq number := 0;
    lv_prev_wolr_seq    number := 0;

    -- get items reserved on current pick list for WOLR in case of multiple occurrences
    function get_reserved_for_wolr(fp_picklist_id                 in number,
                                   fp_workorderline_id            in number,
                                   fp_stockreservationpergrade_id in number,
                                   fp_stocktype                   in number,
                                   fp_sequencenumber              in number) return number is
      cursor get_res is
        select sum(woid.qty_to_pick) reserved
         from workorderitemdistribution woid
        where woid.picklist_id = fp_picklist_id
          and woid.workorderline_id = fp_workorderline_id
          and woid.stockreservationpergrade_id = fp_stockreservationpergrade_id
          and woid.stocktype = fp_stocktype
          and woid.sequencenumber < fp_sequencenumber;

      lv_result number := 0;
    begin
      for res_rec in get_res loop
        lv_result := res_rec.reserved;
      end loop;
      return nvl(lv_result,0);
    end get_reserved_for_wolr;
    -- RVI 02-04-2015 End

  begin
    gv_message := 'find workorderlinereservations';
    -- RVI 15-01-2015 Begin
    lv_to_pick_max := fp_qty_to_add_max;
    -- RVI 15-01-2015 End
    -- process all reservations for workorder in a loop
    for wolr_rec in get_wolr_lines loop
       gv_message := 'find stockroomlocations for workorderlinereservation';
       -- open cursor to find all possible locations
       open get_locations(wolr_rec.stockreservationpergrade_id, wolr_rec.stocktype);
       -- set number of items still to be picked
       -- RVI 05-01-2015 Begin
       --lv_remainder := wolr_rec.quantity;
       -- RVI 02-04-2015 Begin
       -- if (wolr_rec.quantity <= lv_to_pick_max) then
         --lv_remainder := wolr_rec.quantity;
         --lv_to_pick_max := lv_to_pick_max - lv_remainder;
       -- determine number of items still to pick for workorderline_id, stockreservationpergrade_id, stocktype
       lv_to_pick_wolr := wolr_rec.quantity_reserved - wolr_rec.quantity_picked;
       -- determine number of items reserved for workorderline_id, stockreservationpergrade_id, stocktype, < sequence
       lv_prev_wolr_seq := get_reserved_for_wolr(fp_picklist_id, wolr_rec.workorderline_id, wolr_rec.stockreservationpergrade_id,
                                                 wolr_rec.stocktype, wolr_rec.sequencenumber);
       -- determine number of items still to pick for workorderline_id, stockreservationpergrade_id, stocktype, sequence
       lv_to_pick_wolr_seq := wolr_rec.quantity + wolr_rec.qty_prev_sequence - lv_prev_wolr_seq - wolr_rec.quantity_picked;
       -- RVI 01-05-2015 Begin
       -- determine number of items picked on previous pick lists for other wo
       lv_qty_picked_other_wo := wolr_rec.qty_picked_other_wo;
       -- RVI 01-05-2015 End
       -- check if items picked on previous pick lists WOLR then skip line
       if ((wolr_rec.quantity + wolr_rec.qty_prev_sequence - wolr_rec.quantity_picked) <= 0) then
         begin
           -- skip WOLR since there is nothing to pick
           null;
         end;
       else
         begin
           -- determine number of items to pick for current WOLR on pick list line
           if (lv_to_pick_wolr <= lv_to_pick_max) then
             if (lv_to_pick_wolr_seq <= lv_to_pick_wolr) then
               lv_remainder := lv_to_pick_wolr_seq;
               lv_to_pick_max := lv_to_pick_max - lv_remainder;
             else
               lv_remainder := lv_to_pick_wolr;
               lv_to_pick_max := lv_to_pick_max - lv_remainder;
             end if;
-- RVI 02-04-2015 End
           else
             lv_remainder := lv_to_pick_max;
             lv_to_pick_max := 0;
           end if;
           -- RVI 15-01-2015 End
           -- initialize previous location
           lv_prev_location_id := -1;
           -- process all possible locations
           while (lv_remainder > 0) loop
             -- fetch next possible location
             fetch get_locations into location_rec;
             -- verify if location was found
             if get_locations%notfound then
               -- RVI 06-03-2015 Begin
               lv_to_pick_max := lv_to_pick_max + lv_remainder;
               -- RVI 06-03-2015 End
               lv_remainder := 0;
             else
               begin
                 -- determine items already reserved on location for other work order from current pick list
                 lv_reserved := get_reserved_from_location(fp_picklist_id, location_rec.stockroomlocation_id, wolr_rec.stockreservationpergrade_id,
                                                           wolr_rec.stocktype);
                 -- RVI 01-05-2015 Begin
                 -- take into account any items that were already allocated for other workorder on previous pick list
                 -- and therefore no longer available for current pick list.
                 lv_reserved := lv_reserved + lv_qty_picked_other_wo;
                 -- RVI 01-05-2015 End
                 -- check if sufficient on stock left to fulfil demand
                 if (lv_remainder <= (location_rec.qty_on_stock - lv_reserved)) then
                   lv_to_pick := lv_remainder;
                   -- set remainder to 0
                   lv_remainder := 0;
                 else
                   -- RVI 18-05-2014 Begin
                   if (location_rec.qty_on_stock - lv_reserved > 0) then
                   -- RVI 18-05-2014 End
                     lv_to_pick := location_rec.qty_on_stock - lv_reserved;
                     -- set remainder to number of items short
                     lv_remainder := lv_remainder - lv_to_pick;
                   -- RVI 18-05-2014 Begin
                   else
                     lv_to_pick := 0;
                   end if;
                   -- RVI 18-05-2014 End
                 end if;
                 -- if nothing left to pick and same location found then set remainder to 0
                 -- to avoid running into an endless loop
                 if (lv_to_pick = 0) and (location_rec.stockroomlocation_id = lv_prev_location_id) then
                   lv_remainder := 0;
                 end if;
                 -- store current location when different from previous location
                 if (location_rec.stockroomlocation_id != lv_prev_location_id) then
                   lv_prev_location_id := location_rec.stockroomlocation_id;
                 end if;
                 if (lv_to_pick > 0) then
                   gv_message := 'insert in new table WORKORDERITEMDISTRIBUTION';
                   -- insert in new table WORKORDERITEMDISTRIBUTION
                   insert into workorderitemdistribution (workorder_id, picklist_id, workorderline_id,
                                                          stockreservationpergrade_id, stocktype, sequencenumber,
                                                          stockroomlocation_id, pickingsequence, qty_to_pick, qty_picked)
                   values (fp_reference_wo_id, fp_picklist_id, wolr_rec.workorderline_id,
                                                          wolr_rec.stockreservationpergrade_id, wolr_rec.stocktype,
                                                          wolr_rec.sequencenumber, location_rec.stockroomlocation_id,
                                                          location_rec.pickingsequence, lv_to_pick, lv_picked);
                   -- RVI 15-05-2015 Begin
                   lv_qty_added_for_wo := lv_qty_added_for_wo + lv_to_pick;
                   -- RVI 15-05-2015 End
                 end if;
               end;
             end if;
           end loop;
       -- RVI 02-04-2015 Begin
         end;
       end if;
       -- RVI 02-04-2015 End
       close get_locations;
    end loop;
    -- determine work order number
    get_workordernumber(fp_reference_wo_id, lv_workordernumber);
    write_log('Succesfully ran determine_item_distr_for_wo for workorder ' || lv_workordernumber, 5);
    -- all ok return 0
    fp_messagenumber := 0;
    -- RVI 15-05-2015 Begin
    fp_qty_added_for_wo := lv_qty_added_for_wo;
    -- RVI 15-05-2015 End
  exception
    when no_data_found then
      begin
        write_log('Error determine_item_distr_for_wo: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
        if get_locations%isopen then
          close get_locations;
        end if;
      end;
    when dup_val_on_index then
      begin
        write_log('Error determine_item_distr_for_wo: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
        if get_locations%isopen then
          close get_locations;
        end if;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error determine_item_distr_for_wo: Others ' || gv_message, 3);
        fp_messagenumber := 113;
        if get_locations%isopen then
          close get_locations;
        end if;
      end;
  end determine_item_distr_for_wo;


  procedure determine_awopc_for_wo(fp_reference_wo_id in number,
                                   fp_picklist_id     in number,
                                   fp_messagenumber   out number) is
    lv_workordernumber number;
    lv_awopc_string    varchar2(2048);
  begin
    gv_message := 'insert into workorderpicksequence';
    insert into workorderpicksequence (workorder_id,
                                       picklist_id,
                                       pickingsequence)
    select distinct woid.workorder_id, woid.picklist_id, woid.pickingsequence
      from workorderitemdistribution woid
     where woid.workorder_id = fp_reference_wo_id
       and woid.picklist_id = fp_picklist_id;
    -- determine work order number
    get_workordernumber(fp_reference_wo_id, lv_workordernumber);
    write_log('Succesfully ran determine_awopc_for_wo for workorder ' || lv_workordernumber, 5);
    -- determine AWOPC string for reference workorder so it can be added to log
    lv_awopc_string := f_determine_awopc_string(fp_reference_wo_id, fp_picklist_id);
    write_log('AWOPC for reference workorder '|| lv_workordernumber || ' = ' || lv_awopc_string, 5);
    -- all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error determine_awopc_for_wo: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error determine_awopc_for_wo: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error determine_awopc_for_wo: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end determine_awopc_for_wo;


  procedure determine_not_contains_cand(fp_reference_wo_id in number,
                                        fp_picklist_id     in number,
                                        fp_messagenumber   out number) is

    cursor get_cand_wo is
      select wps.workorder_id
        from workorderpicksequence wps
       where wps.workorder_id != fp_reference_wo_id
         and wps.picklist_id = fp_picklist_id
         --
         and not exists (select 1
                           from workorderncpicksequence wnps
                          where wnps.workorder_id = wps.workorder_id
                            and wnps.picklist_id = fp_picklist_id
                            and wnps.nc_pickingsequence = wps.pickingsequence)
         --
      group by wps.workorder_id;

    cursor get_cand_awopc(cp_workorder_id number) is
      select wps.pickingsequence
        from workorderpicksequence wps
       where wps.workorder_id = cp_workorder_id
         and wps.picklist_id = fp_picklist_id
         --
         and not exists (select 1
                           from workorderncpicksequence wnps
                          where wnps.workorder_id = cp_workorder_id
                            and wnps.picklist_id = fp_picklist_id
                            and wnps.nc_pickingsequence = wps.pickingsequence)
         --
       order by wps.workorder_id, wps.pickingsequence;

    cursor exists_ref_awopc(cp_picksequence in number) is
      select 1 cv_result
        from workorderpicksequence wps
       where wps.workorder_id = fp_reference_wo_id
         and wps.picklist_id = fp_picklist_id
         and wps.pickingsequence = cp_picksequence;

    lv_result           number := -1;
    lv_workordernumber  number;
    lv_nc_created_wo    number;


    procedure set_min_distance(fp_reference_wo_id in number,
                               fp_candidate_wo_id in number,
                               fp_picklist_id     in number) is
      cursor get_awopc is
        select wps.pickingsequence
          from workorderpicksequence wps
         where wps.workorder_id = fp_reference_wo_id
           and wps.picklist_id = fp_picklist_id;

      cursor get_nc_cand is
        select wpncs.nc_pickingsequence
          from workorderncpicksequence wpncs
         where wpncs.workorder_id = fp_candidate_wo_id
           and wpncs.picklist_id = fp_picklist_id;

      lv_min_distance number;
      lv_distance     number;

    begin
      -- process all nc for candidate work order
      for cand_rec in get_nc_cand loop
        -- initalize per nc
        lv_min_distance := 9999;
        lv_distance := 0;
        -- process all awopc for reference work order
        for awopc_rec in get_awopc loop
          -- determine dstance between nc and awopc
          lv_distance := abs(cand_rec.nc_pickingsequence - awopc_rec.pickingsequence);
          -- check if distance for current nc is smaller
          if (lv_distance < lv_min_distance) then
            lv_min_distance := lv_distance;
          end if;
        end loop;
        -- set min_distance for current nc
        update workorderncpicksequence wpncs
        set wpncs.nc_min_distance = lv_min_distance
        where wpncs.workorder_id = fp_candidate_wo_id
          and wpncs.picklist_id = fp_picklist_id
          and wpncs.nc_pickingsequence = cand_rec.nc_pickingsequence;
      end loop;
    end set_min_distance;

  begin
    -- process all candidate work orders in a loop
    for cand_wo_rec in get_cand_wo loop
      lv_nc_created_wo := 0;
      -- process all picking sequences for a candidate work order in a loop
      for cand_rec in get_cand_awopc(cand_wo_rec.workorder_id) loop
        lv_result := -1;
        -- check if picking sequence exists for awopc of reference workorder
        for ref_rec in exists_ref_awopc(cand_rec.pickingsequence) loop
          -- picking sequence exists for awopc so result will be set to 1
          lv_result := ref_rec.cv_result;
        end loop;
        -- if picking sequence does not exist for awopc, then add to table workorderncpickingsequence
        if (lv_result = -1) then
          -- add to table workorderncpickingsequence
          insert into workorderncpicksequence (workorder_id,
                                               picklist_id,
                                               nc_pickingsequence,
                                               nc_min_distance)
          values(cand_wo_rec.workorder_id,fp_picklist_id,cand_rec.pickingsequence,0);
          -- increase counter for created nc records of candaidate work order
          lv_nc_created_wo := lv_nc_created_wo + 1;
        end if;
      end loop;
      -- after wo has been processed, determine distance to awopc for each nc
      if (lv_nc_created_wo > 1) then
        -- set minimum distance to awopc for each nc
        set_min_distance(fp_reference_wo_id,cand_wo_rec.workorder_id,fp_picklist_id);
      end if;
    end loop;
    -- determine work order number
    get_workordernumber(fp_reference_wo_id, lv_workordernumber);
    write_log('Succesfully ran determine_not_contains_cand for workorder ' || lv_workordernumber, 5);
    -- all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error determine_not_contains_cand: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error determine_not_contains_cand: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error determine_not_contains_cand: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end determine_not_contains_cand;


  procedure determine_item_distr_for_cand(fp_reference_wo_id     in number,
                                          fp_picklist_id         in number,
                                          fp_stockroom_id        in number,
                                          fp_areacode            in stockroomlocation.areacode%type,
                                          fp_qty_possible_to_add in number,
                                          fp_messagenumber       out number) is
    cursor get_cand_wo is
      select x.*
        from
         (select wo.workorder_id, wo.workordernumber, wo.allowphasedelivery, op.sequencenumber orderpriority, wo.neededdate,
                 nvl((select cr.priority
                        from customer c, customerranking cr
                       where cr.customerranking_id = c.customerranking_id
                         and c.customer_id = wo.customer_link_id),9999) customerpriority,
                 (select sum(wolr.quantity)
                    from workorderline wol, workorderlinereservation wolr
                   where wolr.workorderline_id = wol.workorderline_id
                     and wol.workorder_id = wo.workorder_id) quantity_wo,
                 ((select nvl(sum(plo.qtytopick - plo.qtyissued - plo.qtycancelled - plo.qtycancelledpl),0)
                     from picklist pl, picklistline pll, picklistlineorigin plo, workorderline wol
                    where pll.picklist_id = pl.picklist_id
                      and plo.picklistline_id = pll.picklistline_id
                      and plo.baselinetype = wo.origin
                      and plo.baselinetable = 'WORKORDERLINE'
                      and plo.baselinetable_link_id = wol.workorderline_id
                      -- RVI 05-03-2015 Begin
                      --and plo.qtyissued > 0
                      -- RVI 05-03-2015 End
                      and pl.status_id in (select s.status_id
                                             from status s
                                            where s.statustype = 'PL'
                                              --and s.code not in ('40','60'))
                                              and s.code not in ('20','30','40','60'))
                      and wol.workorder_id = wo.workorder_id)
                  -- RVI 05-03-2015 Begin
                  +
                  (select nvl(sum(plo.qtypicked),0)
                     from picklist pl, picklistline pll, picklistlineorigin plo, workorderline wol
                    where pll.picklist_id = pl.picklist_id
                      and plo.picklistline_id = pll.picklistline_id
                      and plo.baselinetype = wo.origin
                      and plo.baselinetable = 'WORKORDERLINE'
                      and plo.baselinetable_link_id = wol.workorderline_id
                      and wol.workorder_id = wo.workorder_id
                      --and plo.qtyissued = 0
                      and pl.status_id in (select s.status_id
                                             from status s
                                            where s.statustype = 'PL'
                                              --and s.code not in ('40','60')))
                                              and s.code in ('20','30')))
                   -- RVI 05-03-2015 End
                   ) quantity_prev_picklists
          from workorder wo, orderpriority op
          where op.orderpriority_id = wo.orderpriority_id
            and wo.processingstockroom_id = fp_stockroom_id
            and wo.addedtoitempickingpool = gv_addedtoitempickingpool
            and wo.deliverfrom = 2
            --
            and not_confirmed_picklists_exists(wo.workorder_id, fp_stockroom_id, null) = 0
            and wo.origin in (1,2,3,4,5,6,8,9)
            and wo.status_id in (select s.status_id
                                   from status s
                                  where s.statustype = 'WO'
                                    and s.code in ('10','15', '20', '25'))
            -- Ignore WO that has to be delivered as a whole for which not sufficient stock is available
            and ((wo.allowphasedelivery = 'Y')
              or (wo.allowphasedelivery = 'N')
                and not exists
                   (select 1
                      from
                         (select wol.workorder_id, wol.workorderline_id, wolr.stocktype, wolr.quantity,
                                 -- RVI 06-03-2015 Begin
                                 (select sum(wolr2.quantity)
                                    from workorderlinereservation wolr2
                                   where wolr2.workorderline_id = wolr.workorderline_id
                                     and wolr2.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                     and wolr2.stocktype = wolr.stocktype) total_quantity,
                                 -- End
                                 case
                                   -- physically on stock for product/size/grade
                                   when ((wol.codeuniquely = 'N') and (wolr.stocktype = 1)) then
                                   (select nvl(sum(sq.qtynonunique),0)
                                      from stockquantity sq, stockroomlocation sl, locationtype lt
                                     where sl.stockroomlocation_id = sq.stockroomlocation_id
                                       and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                       and lt.locationtype_id = sl.locationtype_id
                                       and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                       and sq.qtynonunique > 0
                                       and lt.pickinglocation = 'Y')
                                   when ((wol.codeuniquely = 'Y') and (wolr.stocktype = 1)) then
                                   (select nvl(sum(sq.qtynonunique),0) + nvl(sum(sq.qtyunique),0)
                                      from stockquantity sq, stockroomlocation sl, locationtype lt
                                     where sl.stockroomlocation_id = sq.stockroomlocation_id
                                       and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                       and lt.locationtype_id = sl.locationtype_id
                                       and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                       and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                                       and lt.pickinglocation = 'Y')
                                   when (wolr.stocktype = 2) then
                                   -- RVI 13-01-2014 Begin
                                   --(select nvl(sum(sq.qtyunique),0)
                                   (select nvl(sum(sq.qtyunique),0) + nvl(sum(sq.qtynonunique),0)
                                   -- RVI 13-01-2013 End
                                      from stockquantity sq, stockroomlocation sl, locationtype lt
                                     where sl.stockroomlocation_id = sq.stockroomlocation_id
                                       and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                       and lt.locationtype_id = sl.locationtype_id
                                       and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                   -- RVI 13-01-2014 Begin
                                   --    and sq.qtyunique > 0
                                       and (sq.qtynonunique > 0 or sq.qtyunique > 0)
                                   -- RVI 13-01-2014 End
                                       and lt.pickinglocation = 'Y')
                                   when (wolr.stocktype = 3) then
                                   (select nvl(sum(sq.qtyuniquewithmodifications),0)
                                      from stockquantity sq, stockroomlocation sl, locationtype lt
                                     where sl.stockroomlocation_id = sq.stockroomlocation_id
                                       and sq.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                       and lt.locationtype_id = sl.locationtype_id
                                       and ((trim(upper(sl.areacode)) = trim(upper(fp_areacode))) or (fp_areacode is null))
                                       and sq.qtyuniquewithmodifications > 0
                                       and lt.pickinglocation = 'Y')
                                 end on_stock,
                                 -- reserved on pick list for other wo
                                 (select nvl(sum(woid.qty_to_pick),0)
                                    from workorderitemdistribution woid
                                   where woid.picklist_id = fp_picklist_id
                                     and woid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                                     and woid.stocktype = wolr.stocktype) reserved
                             from workorderline wol, workorderlinereservation wolr
                            where wolr.workorderline_id = wol.workorderline_id) w
                     where w.workorder_id = wo.workorder_id
                       and (w.quantity > (on_stock - reserved))))
            and wo.workorder_id != fp_reference_wo_id
            -- RVI 15-05-2015 Begin
            order by op.sequencenumber, wo.neededdate, customerpriority, quantity_wo desc, wo.workordernumber
            -- RVI 15-05-2015 End
            ) x
          where ((x.quantity_wo - x.quantity_prev_picklists) > 0)
            -- RVI 15-01-2015 Begin
            -- and ((x.quantity_wo - x.quantity_prev_picklists) <= fp_qty_possible_to_add)
            and ((x.allowphasedelivery = 'Y')
                  or ((x.quantity_wo - x.quantity_prev_picklists) <= fp_qty_possible_to_add))
            -- RVI 15-01-2015 End
         -- RVI 12-05-2015 Begin
         --order by x.orderpriority, x.neededdate, x.customerpriority, x.workordernumber;
         order by x.orderpriority, x.neededdate, x.customerpriority, x.quantity_wo desc, x.workordernumber;
         -- RVI 12-05-2015 End

    lv_stock_error number := 0;
    lv_candidates  number := 0;
    le_no_cand_wo_found exception;
    le_no_stock_found   exception;
    -- RVI 04-03-2015 Begin
    lv_ref_workordernumber number := -1;
    lv_pick_error number := 0;
    le_nothing_to_pick  exception;
    -- RVI 04-03-2015 End
    -- RVI 15-05-2015 Begin
    lv_qty_possible_to_add number := 0;
    lv_qty_added_for_wo    number := 0;
    -- RVI 15-05-2015 End
  begin
   -- insert in new table WOLITEMDISTRIB
/* make a loop on workorders
   where workder is selected for picking
    and workorder total qty to pick < lv_qty_possible_to_add
    and workorderline in areacode
    and not the reference wo
  order by neededdate, customer prio, order prio, wo#
  reason for loop: steeds meenemen dat vorige workorders al iets van een lokatie gealloceerd kunnen hebben
*/
    -- RVI 15-05-2015 Begin
    lv_qty_possible_to_add := fp_qty_possible_to_add;
    -- RVI 15-05-2015 End
    gv_message := 'find candidate work orders';
    -- process all candidate work orders in a loop
    for cand_rec in get_cand_wo loop
      --
      lv_candidates := lv_candidates + 1;
      -- RVI 04-03-2015 Begin
      if (f_wo_has_items_to_pick(cand_rec.workorder_id, fp_picklist_id, fp_areacode, cand_rec.allowphasedelivery)) then
        begin
      -- RVI 04-03-2015 End
          -- check if still enough available on stock for candidate work order
          if (f_wo_has_sufficient_stock(cand_rec.workorder_id, fp_picklist_id, fp_areacode, cand_rec.allowphasedelivery)) then
            -- RVI 15-01-2015 Begin
            --determine_item_distr_for_wo(cand_rec.workorder_id, fp_picklist_id, fp_stockroom_id, fp_areacode, fp_messagenumber);
            --determine_item_distr_for_wo(cand_rec.workorder_id, fp_picklist_id, fp_stockroom_id, fp_areacode,
            --                            fp_qty_possible_to_add,fp_messagenumber);
            -- RVI 15-01-2015 End
            -- RVI 15-05-2015 Begin
            if (lv_qty_possible_to_add > 0) then
              determine_item_distr_for_wo(cand_rec.workorder_id, fp_picklist_id, fp_stockroom_id, fp_areacode,
                                          lv_qty_possible_to_add, lv_qty_added_for_wo, fp_messagenumber);
              -- reduce number of items that can be added to batch because work order will be added to pick list
              lv_qty_possible_to_add := lv_qty_possible_to_add - lv_qty_added_for_wo;
            end if;
            -- RVI 15-05-2015 End
          else
            -- not sufficient stock for candidate wo
            lv_stock_error := lv_stock_error + 1;
            -- RVI 04-03-2015 Begin
            -- add message to log
            get_workordernumber(cand_rec.workorder_id,lv_ref_workordernumber);
            gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
            write_log('Determine_item_distr_for_cand: '|| gv_message, 5);
            gv_message := 'not enough items on stock for any order line!';
            write_log('Determine_item_distr_for_cand: '|| gv_message, 5);
            -- RVI 04-03-2015 End
          end if;
      -- RVI 04-03-2015 Begin
        end;
      else
        begin
          lv_pick_error := lv_pick_error + 1;
          -- add message to log
          get_workordernumber(cand_rec.workorder_id,lv_ref_workordernumber);
          gv_message := 'workorder '|| to_char(lv_ref_workordernumber) || ' skipped';
          write_log('Determine_item_distr_for_cand: '|| gv_message, 5);
          gv_message := 'no items to be picked for any order line!';
          write_log('Determine_item_distr_for_cand: '|| gv_message, 5);
        end;
      end if;
      -- RVI 04-03-2015 End
    end loop;
    if (lv_candidates = 0) then
      gv_message := 'no candidate work order found';
      raise le_no_cand_wo_found;
    end if;
    -- RVI 04-03-2015 Begin
    if ((lv_candidates > 0) and (lv_candidates = lv_pick_error)) then
      -- there is nothing to pick for all candidate work orders
      gv_message := 'no items to be picked for any candidate work order';
      raise le_nothing_to_pick;
    end if;
    -- RVI 04-03-2015 End
    if ((lv_candidates > 0) and (lv_candidates = lv_stock_error)) then
      -- no sufficient stock for all candidate work orders
      gv_message := 'not enough stock found for any candidate work order';
      raise le_no_stock_found;
    end if;
    -- all ok return 0
    fp_messagenumber := 0;
  exception
    when le_no_cand_wo_found then
      begin
        write_log('Determine_item_distr_for_cand: ' || gv_message, 5);
        fp_messagenumber := -1;
      end;
    when le_no_stock_found then
      begin
        write_log('Determine_item_distr_for_cand: ' || gv_message, 5);
        fp_messagenumber := -1;
      end;
    -- RVI 04-03-2015 Begin
    when le_nothing_to_pick then
      begin
        write_log('Determine_item_distr_for_cand: ' || gv_message, 5);
        fp_messagenumber := -1;
      end;
    -- RVI 04-03-2015 End
    when no_data_found then
      begin
        write_log('Error determine_item_distr_for_cand: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error determine_item_distr_for_cand: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error determine_item_distr_for_cand: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end determine_item_distr_for_cand;


  function f_determine_awopc_string(fp_workorder_id in number,
                                    fp_picklist_id  in number) return varchar2 is
    cursor get_sequences is
      select wps.pickingsequence
        from workorderpicksequence wps
       where wps.workorder_id = fp_workorder_id
         and wps.picklist_id = fp_picklist_id
       order by wps.pickingsequence;

    lv_sequence_string varchar2(2048) := null;
  begin
   -- select op workorderpicksequence order by sequence# met '-' ertussen cursor definieren
   for seq_rec in get_sequences loop
     if (lv_sequence_string is null) then
       lv_sequence_string := seq_rec.pickingsequence;
     else
       lv_sequence_string := lv_sequence_string ||'-'|| seq_rec.pickingsequence;
     end if;
   end loop;
   return lv_sequence_string;
  end f_determine_awopc_string;


  function f_partial_awopc_match(fp_reference_wo_id in number,
                                 fp_candidate_wo_id in number,
                                 fp_picklist_id     in number) return number is
    cursor get_cand_awopc is
      select wps.pickingsequence
        from workorderpicksequence wps
       where wps.workorder_id = fp_candidate_wo_id
         and wps.picklist_id = fp_picklist_id
       order by wps.pickingsequence;

    cursor exists_ref_awopc(cp_picksequence in number) is
      select 1 cv_result
        from workorderpicksequence wps
       where wps.workorder_id = fp_reference_wo_id
         and wps.picklist_id = fp_picklist_id
         and wps.pickingsequence = cp_picksequence;

    lv_awopc_not_exists number := 0;
    lv_awopc_exists number := 0;
    lv_result       number := -1;
  begin
    -- process all picking sequence for candiate work order in a loop
    for cand_rec in get_cand_awopc loop
      -- check if awopc exists for reference workorder
      for ref_rec in exists_ref_awopc(cand_rec.pickingsequence) loop
        -- awopc exists so result will be set to 1
        lv_result := ref_rec.cv_result;
      end loop;
      if (lv_result = 1) Then
        lv_awopc_exists :=  lv_awopc_exists + lv_result;
      else
        lv_awopc_not_exists := lv_awopc_not_exists + 1;
      end if;
    end loop;
    -- return appropriate value
    -- there is only a partial match when at least one picking sequence
    -- for candidate work order exist already in awopc (and no picking sequence is missing)
    if (lv_awopc_exists > 0) and (lv_awopc_not_exists = 0) then
      -- there is at least one match, so return 1
      return 1;
    else
      return 0;
    end if;
  end f_partial_awopc_match;


  function f_partial_awopc_match_and_new(fp_reference_wo_id in number,
                                         fp_candidate_wo_id in number,
                                         fp_picklist_id     in number) return number is
    cursor get_cand_awopc is
      select wps.pickingsequence
        from workorderpicksequence wps
       where wps.workorder_id = fp_candidate_wo_id
         and wps.picklist_id = fp_picklist_id
       order by wps.pickingsequence;

    cursor exists_ref_awopc(cp_picksequence in number) is
      select 1 cv_result
        from workorderpicksequence wps
       where wps.workorder_id = fp_reference_wo_id
         and wps.picklist_id = fp_picklist_id
         and wps.pickingsequence = cp_picksequence;

    lv_awopc_exists     number := 0;
    lv_awopc_not_exists number := 0;
    lv_result           number := -1;
  begin
    -- process all picking sequence for candiate work order in a loop
    for cand_rec in get_cand_awopc loop
      lv_result := -1;
      -- check if current picking sequnce exists in awopc for reference workorder
      for ref_rec in exists_ref_awopc(cand_rec.pickingsequence) loop
        -- picking sequence exists in awopc so result will be set to 1
        lv_result := ref_rec.cv_result;
      end loop;
      -- if picking sequence does not exist in awopc, then it might be added to awopc later on
      if (lv_result = 1) then
        lv_awopc_exists := lv_awopc_exists + lv_result;
      else
        lv_awopc_not_exists := lv_awopc_not_exists + 1;
      end if;
    end loop;
    -- return appropriate value: awopc may only be extended when at least one picking sequence
    -- for candidate work order exist already in awopc and at least one is missing
    if (lv_awopc_not_exists > 0) and (lv_awopc_exists > 0) then
      -- awopc might have to be extended, so return 1
      return 1;
    else
      if (lv_awopc_not_exists > 0) and (lv_awopc_exists = 0) then
         return 0;
      end if;
      if (lv_awopc_not_exists = 0) and (lv_awopc_exists = 0) then
         return -1;
      end if;
      -- RVI 15-01-2015 Begin
      if (lv_awopc_not_exists = 0) and (lv_awopc_exists = 1) then
         return -2;
      end if;
      -- RVI 15-01-2015 End
    end if;
  end f_partial_awopc_match_and_new;


  procedure find_prio1_same_awopc(fp_reference_wo_id     in number,
                                  fp_picklistid          in number,
                                  fp_qty_possible_to_add in number,
                                  fp_reference_priority  in number,
                                  fp_found_wo_id         out number,
                                  fp_qty_this_wo         out number,
                                  fp_messagenumber       out number) is

    cursor get_first_wo (cp_reference_awopc_string in varchar2,
                         cp_qty_possible_to_add    in number) is
    -- RVI 23-04-2015 Begin
    select *
      from (
    -- RVI 23-04-2015 End
      select *
        from
          (select wo.workorder_id, wo.workordernumber, wo.origin, wo.neededdate, op.sequencenumber orderpriority,
                 -- RVI 15-01-2015 Begin
                  wo.allowphasedelivery,
                 -- RVI 15-01-2015 End
                 nvl((select cr.priority
                        from customer c, customerranking cr
                       where cr.customerranking_id = c.customerranking_id
                         and c.customer_id = wo.customer_link_id),9999) customerpriority,
                 (select sum(wolr.quantity)
                    from workorderline wol, workorderlinereservation wolr
                   where wolr.workorderline_id = wol.workorderline_id
                     and wol.workorder_id = wo.workorder_id
                     -- RVI 02-03-2015 Begin
                     and ((select count(*)
                            from workorderitemdistribution wid
                           where wid.workorder_id = wol.workorder_id
                             and wid.picklist_id = fp_picklistid
                             and wid.workorderline_id = wolr.workorderline_id
                             and wid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                             and wid.stocktype = wolr.stocktype) > 0)
                     -- RVI 02-03-2015 End;
                     ) quantity_wo -- to do sum

           from
             (select distinct w.workorder_id
               from workorderpicksequence w
              where w.picklist_id = fp_picklistid
                and w.workorder_id != fp_reference_wo_id
                -- make sure that workorder was not added to current pick list yet
                and not exists (select 1
                                  from picklistline pll, picklistlineorigin pllo, workorderline wol
                                 where pllo.picklistline_id = pll.picklistline_id
                                   and pll.picklist_id =  fp_picklistid
                                   and pllo.baselinetable = 'WORKORDERLINE'
                                   and wol.workorderline_id = pllo.baselinetable_link_id
                                   and wol.workorder_id = w.workorder_id)) x,
              workorder wo, orderpriority op
          where wo.workorder_id = x.workorder_id
            and op.orderpriority_id = wo.orderpriority_id
            and f_determine_awopc_string(wo.workorder_id, fp_picklistid) = cp_reference_awopc_string) y
    -- RVI 23-04-2015 Begin
    --   where rownum = 1
    --     and y.orderpriority = fp_reference_priority
    --     and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
	  --order by y.quantity_wo desc, y.orderpriority, y.neededdate, y.customerpriority, y.workordernumber;
       where y.orderpriority = fp_reference_priority
         and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
         order by y.orderpriority, y.neededdate, y.customerpriority, y.quantity_wo desc, y.workordernumber) z
       where rownum = 1
	  order by z.orderpriority, z.neededdate, z.customerpriority, z.quantity_wo desc, z.workordernumber;
    -- RVI 23-04-2015 End

    lv_reference_awopc_string  varchar2(100);
    lv_next_workorder_id       number := -1;
    lv_qty_next_workorder      number := 0;
    lv_workordernumber         number := null;
    le_no_next_wo_found        exception;
  begin
    -- determine awopc for reference work order
    lv_reference_awopc_string := f_determine_awopc_string(fp_reference_wo_id, fp_picklistid);
    /*select
      from workorder w
      where f_determine_awopc_string(w.workorder_id) = reference_awopc_string
      order by orderqty  desc -- grootste eerst
        neededdate, prio, etc  */
    for wo_rec in get_first_wo(lv_reference_awopc_string,fp_qty_possible_to_add) loop
      lv_next_workorder_id := wo_rec.workorder_id;
      lv_qty_next_workorder := wo_rec.quantity_wo;
    end loop;
    fp_found_wo_id := lv_next_workorder_id;
    fp_qty_this_wo := lv_qty_next_workorder;
    if (lv_next_workorder_id = -1 or lv_next_workorder_id is null) then
      gv_message := 'no next workorder found';
      raise le_no_next_wo_found;
    end if;
    -- all ok return 0
    fp_messagenumber := 0;
    -- determine work order number for candidate wo
    get_workordernumber(lv_next_workorder_id, lv_workordernumber);
    write_log('Succesfully ran find_prio1_same_awopc, candidate workorder found = ' || lv_workordernumber, 5);
  exception
    when le_no_next_wo_found then
      begin
        write_log('Successfully ran find_prio1_same_awopc: ' || gv_message, 5);
        fp_messagenumber := 0;
      end;
    when no_data_found then
      begin
        write_log('Error find_prio1_same_awopc: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error find_prio1_same_awopc: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error find_prio1_same_awopc: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end find_prio1_same_awopc;


  procedure find_prio2_contains_part_awopc(fp_reference_wo_id     in number,
                                           fp_picklistid          in number,
                                           fp_qty_possible_to_add in number,
                                           fp_reference_priority  in number,
                                           fp_found_wo_id         out number,
                                           fp_qty_this_wo         out number,
                                           fp_messagenumber       out number) is

    cursor get_first_wo (cp_reference_awopc_string in varchar2,
                         cp_qty_possible_to_add    in number) is
    -- RVI 23-04-2015 Begin
    select *
      from (
    -- RVI 23-04-2015 End
      select *
        from
          (select wo.workorder_id, wo.workordernumber, wo.origin, wo.neededdate, op.sequencenumber orderpriority,
                 -- RVI 15-01-2015 Begin
                  wo.allowphasedelivery,
                 -- RVI 15-01-2015 End
                 nvl((select cr.priority
                        from customer c, customerranking cr
                       where cr.customerranking_id = c.customerranking_id
                         and c.customer_id = wo.customer_link_id),9999) customerpriority,
                 (select sum(wolr.quantity)
                    from workorderline wol, workorderlinereservation wolr
                   where wolr.workorderline_id = wol.workorderline_id
                     and wol.workorder_id = wo.workorder_id
                     -- RVI 02-03-2015 Begin
                     and ((select count(*)
                            from workorderitemdistribution wid
                           where wid.workorder_id = wol.workorder_id
                             and wid.picklist_id = fp_picklistid
                             and wid.workorderline_id = wolr.workorderline_id
                             and wid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                             and wid.stocktype = wolr.stocktype) > 0)
                     -- RVI 02-03-2015 End;
                     ) quantity_wo -- to do sum

           from
             (select distinct w.workorder_id
               from workorderpicksequence w
              where w.picklist_id = fp_picklistid
                and w.workorder_id != fp_reference_wo_id
                -- make sure that workorder was not added to current pick list yet
                and not exists (select 1
                                  from picklistline pll, picklistlineorigin pllo, workorderline wol
                                 where pllo.picklistline_id = pll.picklistline_id
                                   and pll.picklist_id =  fp_picklistid
                                   and pllo.baselinetable = 'WORKORDERLINE'
                                   and wol.workorderline_id = pllo.baselinetable_link_id
                                   and wol.workorder_id = w.workorder_id)) x,
              workorder wo, orderpriority op
          where wo.workorder_id = x.workorder_id
            and op.orderpriority_id = wo.orderpriority_id
            and f_determine_awopc_string(wo.workorder_id, fp_picklistid) != cp_reference_awopc_string
            and f_partial_awopc_match(fp_reference_wo_id,wo.workorder_id,fp_picklistid) = 1) y
    -- RVI 23-04-2015 Begin
    --   where rownum = 1
    --     and y.orderpriority = fp_reference_priority
    --     and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
    --  order by y.quantity_wo desc, y.orderpriority, y.neededdate, y.customerpriority, y.workordernumber;
       where y.orderpriority = fp_reference_priority
         and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
         order by y.orderpriority, y.neededdate, y.customerpriority, y.quantity_wo desc, y.workordernumber) z
       where rownum = 1
	  order by z.orderpriority, z.neededdate, z.customerpriority, z.quantity_wo desc, z.workordernumber;
    -- RVI 23-04-2015 End

    lv_reference_awopc_string  varchar2(100);
    lv_next_workorder_id       number := -1;
    lv_qty_next_workorder      number := 0;
    lv_workordernumber         number := null;
    le_no_next_wo_found        exception;
  begin
    -- determine awopc for reference work order
    lv_reference_awopc_string := f_determine_awopc_string(fp_reference_wo_id, fp_picklistid);
    /*select
      from workorder w
      where f_determine_awopc_string(w.workorder_id) != reference_awopc_string
      order by orderqty  desc -- largest first
        neededdate, prio, etc  */
    for wo_rec in get_first_wo(lv_reference_awopc_string,fp_qty_possible_to_add) loop
      lv_next_workorder_id := wo_rec.workorder_id;
      lv_qty_next_workorder := wo_rec.quantity_wo;
    end loop;
    fp_found_wo_id := lv_next_workorder_id;
    fp_qty_this_wo := lv_qty_next_workorder;
    if (lv_next_workorder_id = -1 or lv_next_workorder_id is null) then
      gv_message := 'no next workorder found, continue with next step';
      raise le_no_next_wo_found;
    end if;
    -- all ok return 0
    fp_messagenumber := 0;
    -- determine work order number for candidate wo
    get_workordernumber(lv_next_workorder_id, lv_workordernumber);
    write_log('Succesfully ran find_prio2_contains_part_awopc, candidate workorder found = ' || lv_workordernumber, 5);
  exception
    when le_no_next_wo_found then
      begin
        write_log('Successfully ran find_prio2_contains_part_awopc: ' || gv_message, 5);
        fp_messagenumber := 0;
      end;
    when no_data_found then
      begin
        write_log('Error find_prio2_contains_part_awopc: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error find_prio2_contains_part_awopc: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error find_prio2_contains_part_awopc: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end find_prio2_contains_part_awopc;


  procedure find_prio3_part_awopc_and_new(fp_reference_wo_id     in number,
                                          fp_picklistid          in number,
                                          fp_qty_possible_to_add in number,
                                          fp_reference_priority  in number,
                                          fp_found_wo_id         out number,
                                          fp_qty_this_wo         out number,
                                          fp_add_to_awopc        out number,
                                          fp_messagenumber       out number) is

    cursor get_first_wo (cp_reference_awopc_string in varchar2,
                         cp_qty_possible_to_add    in number) is
    -- RVI 23-04-2015 Begin
    select *
      from (
    -- RVI 23-04-2015 End
      select *
        from
          (select wo.workorder_id, wo.workordernumber, wo.origin, wo.neededdate, op.sequencenumber orderpriority,
                 -- RVI 15-01-2015 Begin
                  wo.allowphasedelivery,
                 -- RVI 15-01-2015 End
                 nvl((select cr.priority
                        from customer c, customerranking cr
                       where cr.customerranking_id = c.customerranking_id
                         and c.customer_id = wo.customer_link_id),9999) customerpriority,
                 (select sum(wolr.quantity)
                    from workorderline wol, workorderlinereservation wolr
                   where wolr.workorderline_id = wol.workorderline_id
                     and wol.workorder_id = wo.workorder_id
                     -- RVI 02-03-2015 Begin
                     and ((select count(*)
                            from workorderitemdistribution wid
                           where wid.workorder_id = wol.workorder_id
                             and wid.picklist_id = fp_picklistid
                             and wid.workorderline_id = wolr.workorderline_id
                             and wid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                             and wid.stocktype = wolr.stocktype) > 0)
                     -- RVI 02-03-2015 End;
                     ) quantity_wo,
                 (select sum(woncps.nc_min_distance)
                    from workorderncpicksequence woncps
                   where woncps.picklist_id = fp_picklistid
                     and woncps.workorder_id = wo.workorder_id) min_distance_wo

           from
             (select distinct w.workorder_id
               from workorderpicksequence w
              where w.picklist_id = fp_picklistid
                and w.workorder_id != fp_reference_wo_id
                -- make sure that workorder was not added to current pick list yet
                and not exists (select 1
                                  from picklistline pll, picklistlineorigin pllo, workorderline wol
                                 where pllo.picklistline_id = pll.picklistline_id
                                   and pll.picklist_id =  fp_picklistid
                                   and pllo.baselinetable = 'WORKORDERLINE'
                                   and wol.workorderline_id = pllo.baselinetable_link_id
                                   and wol.workorder_id = w.workorder_id)) x,
              workorder wo, orderpriority op
          where wo.workorder_id = x.workorder_id
            and op.orderpriority_id = wo.orderpriority_id
            and f_determine_awopc_string(wo.workorder_id, fp_picklistid) != cp_reference_awopc_string
            and f_partial_awopc_match_and_new(fp_reference_wo_id,wo.workorder_id,fp_picklistid) = 1) y
    -- RVI 23-04-2015 Begin
    --   where rownum = 1
    --     and y.orderpriority = fp_reference_priority
    --     and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
	  --order by y.min_distance_wo, y.quantity_wo desc, y.orderpriority, y.neededdate, y.customerpriority, y.workordernumber;
       where y.orderpriority = fp_reference_priority
         and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
         order by y.min_distance_wo, y.orderpriority, y.neededdate, y.customerpriority, y.quantity_wo desc, y.workordernumber) z
       where rownum = 1
	  order by z.min_distance_wo, z.orderpriority, z.neededdate, z.customerpriority, z.quantity_wo desc, z.workordernumber;
    -- RVI 23-04-2015 End

    cursor get_first_nc(cp_reference_wo_id in number,
                        cp_workorder_id    in number,
                        cp_picklist_id     in number) is

      select x.nc_pickingsequence
        from
        (select wnc.nc_pickingsequence
          from workorderncpicksequence wnc
          where wnc.workorder_id = cp_workorder_id
            and wnc.picklist_id = cp_picklist_id
            and wnc.nc_min_distance = (select min(wncs.nc_min_distance)
                                      from workorderncpicksequence wncs
                                      where wncs.workorder_id = cp_workorder_id
                                        and wncs.picklist_id = cp_picklist_id)
            and not exists (select 1
                              from workorderpicksequence wpc
                              where wpc.workorder_id = cp_reference_wo_id
                                and wpc.picklist_id = cp_picklist_id
                                and wpc.pickingsequence = wnc.nc_pickingsequence)) x
         where rownum = 1;

    lv_reference_awopc_string  varchar2(100);
    lv_next_workorder_id       number := -1;
    lv_qty_next_workorder      number := 0;
    lv_workordernumber         number := null;
    lv_add_to_awopc            number := -1;
    le_no_next_wo_found        exception;
  begin
    -- determine awopc for reference work order
    lv_reference_awopc_string := f_determine_awopc_string(fp_reference_wo_id, fp_picklistid);
    /*select
      from workorder w
      where f_determine_awopc_string(w.workorder_id) != reference_awopc_string
      order by orderqty  desc -- largest first
        neededdate, prio, etc  */
    for wo_rec in get_first_wo(lv_reference_awopc_string,fp_qty_possible_to_add) loop
      lv_next_workorder_id := wo_rec.workorder_id;
      lv_qty_next_workorder := wo_rec.quantity_wo;
    end loop;
    fp_found_wo_id := lv_next_workorder_id;
    fp_qty_this_wo := lv_qty_next_workorder;
    if (lv_next_workorder_id = -1 or lv_next_workorder_id is null) then
      gv_message := 'no next workorder found, continue with next step';
      raise le_no_next_wo_found;
    else
      gv_message := 'determine first nc to be added';
      -- determine first nc to be added
      for nc_rec in get_first_nc(fp_reference_wo_id,lv_next_workorder_id,fp_picklistid) loop
        lv_add_to_awopc := nc_rec.nc_pickingsequence;
      end loop;
      if (lv_add_to_awopc = -1 or lv_add_to_awopc is null) then
        gv_message := 'no not contained picking sequence found';
        write_log('Succesfully ran find_prio3_part_awopc_and_newc: ' || gv_message, 5);
      else
        fp_add_to_awopc := lv_add_to_awopc;
      end if;
    end if;
    -- all ok return 0
    fp_messagenumber := 0;
    -- determine work order number for candidate wo
    get_workordernumber(lv_next_workorder_id, lv_workordernumber);
    write_log('Succesfully ran find_prio3_part_awopc_and_newc, candidate workorder found = ' || lv_workordernumber, 5);
  exception
    when le_no_next_wo_found then
      begin
        write_log('Succesfully ran find_prio3_part_awopc_and_newc: ' || gv_message, 5);
        fp_messagenumber := 0;
      end;
    when no_data_found then
      begin
        write_log('Error find_prio3_part_awopc_and_new: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error find_prio3_part_awopc_and_new: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error find_prio3_part_awopc_and_new: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end find_prio3_part_awopc_and_new;


  procedure find_prio4_no_part_awopc(fp_reference_wo_id     in number,
                                     fp_picklistid          in number,
                                     fp_qty_possible_to_add in number,
                                     fp_reference_priority  in number,
                                     fp_found_wo_id         out number,
                                     fp_qty_this_wo         out number,
                                     fp_add_to_awopc        out number,
                                     fp_messagenumber       out number) is

    cursor get_first_wo (cp_reference_awopc_string in varchar2,
                         cp_qty_possible_to_add    in number) is
    -- RVI 23-04-2015 Begin
    select *
      from (
    -- RVI 23-04-2015 End
      select *
        from
          (select wo.workorder_id, wo.workordernumber, wo.origin, wo.neededdate, op.sequencenumber orderpriority,
                 -- RVI 15-01-2015 Begin
                  wo.allowphasedelivery,
                 -- RVI 15-01-2015 End
                 nvl((select cr.priority
                        from customer c, customerranking cr
                       where cr.customerranking_id = c.customerranking_id
                         and c.customer_id = wo.customer_link_id),9999) customerpriority,
                 (select sum(wolr.quantity)
                    from workorderline wol, workorderlinereservation wolr
                   where wolr.workorderline_id = wol.workorderline_id
                     and wol.workorder_id = wo.workorder_id
                     -- RVI 02-03-2015 Begin
                     and ((select count(*)
                            from workorderitemdistribution wid
                           where wid.workorder_id = wol.workorder_id
                             and wid.picklist_id = fp_picklistid
                             and wid.workorderline_id = wolr.workorderline_id
                             and wid.stockreservationpergrade_id = wolr.stockreservationpergrade_id
                             and wid.stocktype = wolr.stocktype) > 0)
                     -- RVI 02-03-2015 End;
                     ) quantity_wo,
                 (select sum(woncps.nc_min_distance)
                    from workorderncpicksequence woncps
                   where woncps.picklist_id = fp_picklistid
                     and woncps.workorder_id = wo.workorder_id) min_distance_wo

           from
             (select distinct w.workorder_id
               from workorderpicksequence w
              where w.picklist_id = fp_picklistid
                and w.workorder_id != fp_reference_wo_id
                -- make sure that workorder was not added to current pick list yet
                and not exists (select 1
                                  from picklistline pll, picklistlineorigin pllo, workorderline wol
                                 where pllo.picklistline_id = pll.picklistline_id
                                   and pll.picklist_id =  fp_picklistid
                                   and pllo.baselinetable = 'WORKORDERLINE'
                                   and wol.workorderline_id = pllo.baselinetable_link_id
                                   and wol.workorder_id = w.workorder_id)) x,
              workorder wo, orderpriority op
          where wo.workorder_id = x.workorder_id
            and op.orderpriority_id = wo.orderpriority_id
            and f_determine_awopc_string(wo.workorder_id, fp_picklistid) != cp_reference_awopc_string
            and f_partial_awopc_match_and_new(fp_reference_wo_id,wo.workorder_id,fp_picklistid) = 0) y
    -- RVI 23-04-2015 Begin
    --   where rownum = 1
    --     and y.orderpriority = fp_reference_priority
    --     and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
    --  order by y.min_distance_wo, y.quantity_wo desc, y.orderpriority, y.neededdate, y.customerpriority, y.workordernumber;
       where y.orderpriority = fp_reference_priority
         and ((y.quantity_wo <= cp_qty_possible_to_add) or (y.allowphasedelivery = 'Y'))
         order by y.min_distance_wo, y.orderpriority, y.neededdate, y.customerpriority, y.quantity_wo desc, y.workordernumber) z
       where rownum = 1
	  order by z.min_distance_wo, z.orderpriority, z.neededdate, z.customerpriority, z.quantity_wo desc, z.workordernumber;
    -- RVI 23-04-2015 End

    cursor get_first_nc(cp_reference_wo_id in number,
                        cp_workorder_id    in number,
                        cp_picklist_id     in number) is

      select x.nc_pickingsequence
        from
        (select wnc.nc_pickingsequence
          from workorderncpicksequence wnc
          where wnc.workorder_id = cp_workorder_id
            and wnc.picklist_id = cp_picklist_id
            and wnc.nc_min_distance = (select min(wncs.nc_min_distance)
                                      from workorderncpicksequence wncs
                                      where wncs.workorder_id = cp_workorder_id
                                        and wncs.picklist_id = cp_picklist_id
                                        --
                                        and not exists (select 1
                                                          from workorderpicksequence wpc
                                                         where wpc.workorder_id = cp_reference_wo_id
                                                           and wpc.picklist_id = cp_picklist_id
                                                           and wpc.pickingsequence = wnc.nc_pickingsequence))
            and not exists (select 1
                              from workorderpicksequence wpc
                              where wpc.workorder_id = cp_reference_wo_id
                                and wpc.picklist_id = cp_picklist_id
                                and wpc.pickingsequence = wnc.nc_pickingsequence)) x
         where rownum = 1;

    lv_reference_awopc_string  varchar2(100);
    lv_next_workorder_id       number := -1;
    lv_qty_next_workorder      number := 0;
    lv_workordernumber         number := null;
    lv_add_to_awopc            number := -1;
    le_no_next_wo_found        exception;
  begin
    -- determine awopc for reference work order
    lv_reference_awopc_string := f_determine_awopc_string(fp_reference_wo_id, fp_picklistid);
    /*select
      from workorder w
      where f_determine_awopc_string(w.workorder_id) = reference_awopc_string
      order by orderqty  desc -- largest first
        neededdate, prio, etc  */
    for wo_rec in get_first_wo(lv_reference_awopc_string,fp_qty_possible_to_add) loop
      lv_next_workorder_id := wo_rec.workorder_id;
      lv_qty_next_workorder := wo_rec.quantity_wo;
    end loop;
    fp_found_wo_id := lv_next_workorder_id;
    fp_qty_this_wo := lv_qty_next_workorder;
    if (lv_next_workorder_id = -1 or lv_next_workorder_id is null) then
      gv_message := 'no next workorder found';
      raise le_no_next_wo_found;
    else
      gv_message := 'determine first nc to be added';
      -- determine first nc to be added
      for nc_rec in get_first_nc(fp_reference_wo_id,lv_next_workorder_id,fp_picklistid) loop
        lv_add_to_awopc := nc_rec.nc_pickingsequence;
      end loop;
      if (lv_add_to_awopc = -1 or lv_add_to_awopc is null) then
        gv_message := 'no not contained picking sequence found';
        write_log('Succesfully ran find_prio4_no_part_awopc: ' || gv_message, 5);
      else
        fp_add_to_awopc := lv_add_to_awopc;
      end if;
    end if;
    -- all ok return 0
    fp_messagenumber := 0;
    -- determine work order number for candidate wo
    get_workordernumber(lv_next_workorder_id, lv_workordernumber);
    write_log('Succesfully ran find_prio4_no_part_awopc, candidate workorder found = ' || lv_workordernumber, 5);
  exception
    when le_no_next_wo_found then
      begin
        write_log('Succesfully ran find_prio4_no_part_awopc: ' || gv_message, 5);
        fp_messagenumber := 0;
      end;
    when no_data_found then
      begin
        write_log('Error find_prio4_no_part_awopc: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error find_prio4_no_part_awopc: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error find_prio4_no_part_awopc: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end find_prio4_no_part_awopc;


  procedure extend_awopc_for_reference_wo(fp_reference_wo_id in number,
                                          fp_picklist_id     in number,
                                          fp_candidate_wo_id in number,
                                          fp_pickingsequence in number,
                                          fp_messagenumber   out number) is

    cursor get_not_contained(cp_reference_wo_id in number,
                             cp_workorder_id    in number,
                             cp_picklist_id     in number) is

      select wnc.nc_pickingsequence
        from workorderncpicksequence wnc
       where wnc.workorder_id = cp_workorder_id
         and wnc.picklist_id = cp_picklist_id
         and not exists (select 1
                           from workorderpicksequence wpc
                          where wpc.workorder_id = cp_reference_wo_id
                            and wpc.picklist_id = cp_picklist_id
                            and wpc.pickingsequence = wnc.nc_pickingsequence);

    lv_workordernumber number;
    lv_awopc_string    varchar2(2048);
  begin
    -- for all picking sequences of candiate wo not existing for reference wo
    for nc_rec in get_not_contained(fp_reference_wo_id,fp_candidate_wo_id,fp_picklist_id) loop
      begin
        -- no loop needed , one insert statement.
        gv_message := 'insert into workorderpicksequence';
        insert into workorderpicksequence (workorder_id,
                                           picklist_id,
                                           pickingsequence)
        values(fp_reference_wo_id,fp_picklist_id,nc_rec.nc_pickingsequence);
      end;
    end loop;
    -- determine work order number for candidate wo
    get_workordernumber(fp_candidate_wo_id, lv_workordernumber);
    write_log('Added picking sequences from candidate work order ' || lv_workordernumber, 5);
    -- determine work order number for reference wo
    get_workordernumber(fp_reference_wo_id, lv_workordernumber);
    -- determine AWOPC string for reference wo so it can be added to log
    lv_awopc_string := f_determine_awopc_string(fp_reference_wo_id, fp_picklist_id);
    write_log('new AWOPC for reference workorder '|| lv_workordernumber || ' = ' || lv_awopc_string, 5);
    -- all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error extend_awopc_for_reference_wo: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error extend_awopc_for_reference_wo: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
        --fp_messagenumber := 0;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error extend_awopc_for_reference_wo: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end extend_awopc_for_reference_wo;


  procedure find_next_wo(fp_reference_wo_id     in number,
                         fp_picklistid          in number,
                         fp_qty_possible_to_add in number,
                         fp_qty_already_added   in number,
                         fp_reference_priority  in number,
                         fp_min_batch_size      in number,
                         fp_max_batch_size      in number,
                         fp_next_wo_id          out number,
                         fp_qty_next_wo         out number,
                         fp_next_priority       out number,
                         fp_messagenumber       out number) is

    le_no_next_wo_found exception;
    le_no_next_wo_prio  exception;
    le_next_wo_found   exception;
    le_min_batch_exc   exception;
    lv_next_priority   number := -1;
    lv_next_wo_id      number := -1;
    lv_qty_next_wo     number := 0;
    lv_add_to_awopc    number := -1;
    lv_check_min_batch boolean := fp_min_batch_size > 0;
  begin
  /*
  found:= find_prio1_same_awopc;
  if not found then
  found:= find_prio2_contains_part_awopc;
  if not found then
  found:= find_prio3_contains_part_awopc_and_new;
  if found then extend_awopc_of_reference_wo;
  if not found then
  found:= find_prio4_contains_no_part_awopc;
  if found then extend_awopc_of_reference_wo;
  */
    -- find_prio1_same_awopc
    find_prio1_same_awopc(fp_reference_wo_id,fp_picklistid,fp_qty_possible_to_add,fp_reference_priority,
                          lv_next_wo_id,lv_qty_next_wo,fp_messagenumber);
    -- when found at prio 1, then raise execption and set return values
    if ((lv_next_wo_id > 0) and (fp_messagenumber = 0)) then
      gv_message := 'find_prio1_same_awopc';
      raise le_next_wo_found;
    end if;
    -- when not found at prio 1
    if ((lv_next_wo_id < 0) and (fp_messagenumber = 0)) then
      -- find_prio2_contains_part_awopc
      find_prio2_contains_part_awopc(fp_reference_wo_id,fp_picklistid,fp_qty_possible_to_add,fp_reference_priority,
                                     lv_next_wo_id,lv_qty_next_wo,fp_messagenumber);
    end if;
    -- when found at prio 2, then set return values
    if ((lv_next_wo_id > 0) and (fp_messagenumber = 0)) then
      gv_message := 'find_prio2_contains_part_awopc';
      raise le_next_wo_found;
    end if;
    -- when not found at prio 2
    if ((lv_next_wo_id < 0) and (fp_messagenumber = 0)) then
      -- check if min_batch_size was reached
      if lv_check_min_batch then
        if (fp_qty_already_added  >= fp_min_batch_size) then
          gv_message := fp_min_batch_size;
          raise le_min_batch_exc;
        end if;
      end if;
      -- determine_not_contains_for_candidates
      determine_not_contains_cand(fp_reference_wo_id,fp_picklistid,fp_messagenumber);
      -- find_prio3_contains_part_awopc_and_new
      find_prio3_part_awopc_and_new(fp_reference_wo_id,fp_picklistid,fp_qty_possible_to_add,fp_reference_priority,
                                    lv_next_wo_id,lv_qty_next_wo,lv_add_to_awopc,fp_messagenumber);
      if ((lv_next_wo_id > 0) and (lv_add_to_awopc is not null) and (fp_messagenumber = 0)) then
        extend_awopc_for_reference_wo(fp_reference_wo_id,fp_picklistid,lv_next_wo_id,lv_add_to_awopc,fp_messagenumber);
      end if;
    end if;
    -- when found at prio 3, then set return values
    if ((lv_next_wo_id > 0) and (fp_messagenumber = 0)) then
      gv_message := 'find_prio3_part_awopc_and_new';
      raise le_next_wo_found;
    end if;
    -- when not found at prio 3
    if ((lv_next_wo_id < 0) and (fp_messagenumber = 0)) then
      -- find_prio4_contains_no_part_awopc
      find_prio4_no_part_awopc(fp_reference_wo_id,fp_picklistid,fp_qty_possible_to_add,fp_reference_priority,
                               lv_next_wo_id,lv_qty_next_wo,lv_add_to_awopc,fp_messagenumber);
      if ((lv_next_wo_id > 0) and (lv_add_to_awopc is not null) and (fp_messagenumber = 0)) then
        extend_awopc_for_reference_wo(fp_reference_wo_id,fp_picklistid,lv_next_wo_id,lv_add_to_awopc,fp_messagenumber);
      end if;
    end if;
    -- when found at prio 4, then set return values
    if ((lv_next_wo_id > 0) and (fp_messagenumber = 0)) then
      gv_message := 'find_prio4_no_part_awopc';
      raise le_next_wo_found;
    end if;
    -- when not found at prio 4, then check for new priority
    determine_next_priority(fp_reference_wo_id,fp_picklistid,fp_qty_possible_to_add,fp_reference_priority,
                            lv_next_priority,fp_messagenumber);
    -- when no next priority found then return -1
    if (lv_next_priority = -1) or (lv_next_priority is null) then
      fp_next_priority := -1;
    end if;
    if (lv_next_priority > fp_reference_priority) then
      gv_message := 'no next workorder found yet, but start with next priority ';
      fp_next_priority := lv_next_priority;
      raise le_no_next_wo_prio;
    end if;
    -- when not found at prio 4, then set appropriate return value to end loop
    if (lv_next_wo_id = -1 or lv_next_wo_id is null) then
      gv_message := 'no next workorder found';
      raise le_no_next_wo_found;
    end if;
  exception
    when le_no_next_wo_prio then
      begin
        write_log('Successfully ran find_next_wo: ' || gv_message, 5);
        fp_next_wo_id := lv_next_wo_id;
        fp_qty_next_wo := lv_qty_next_wo;
        fp_messagenumber := 0;
      end;
    when le_no_next_wo_found then
      begin
        write_log('Unsuccessfully ran find_next_wo: ' || gv_message, 5);
        fp_next_wo_id := lv_next_wo_id;
        fp_qty_next_wo := lv_qty_next_wo;
        fp_messagenumber := 0;
      end;
    when le_next_wo_found then
      begin
        write_log('Successfully ran find_next_wo: next work order found ' || gv_message, 5);
        fp_next_priority := fp_reference_priority;
        fp_next_wo_id := lv_next_wo_id;
        fp_qty_next_wo := lv_qty_next_wo;
        fp_messagenumber := 0;
      end;
    when le_min_batch_exc then
      begin
        write_log('Successfully ran find_next_wo: no next work order found, but min batch size was reached: ' || gv_message, 5);
        fp_next_priority := -1;
        fp_next_wo_id := lv_next_wo_id;
        fp_qty_next_wo := lv_qty_next_wo;
        fp_messagenumber := 0;
      end;
    when no_data_found then
      begin
        write_log('Error find_next_wo: No_Data_Found ' || gv_message, 3);
        fp_next_priority := -1;
        fp_next_wo_id := -1;
        fp_qty_next_wo := 0;
        fp_messagenumber := 111;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error find_next_wo: Others ' || gv_message, 3);
        fp_next_priority := -1;
        fp_next_wo_id := -1;
        fp_qty_next_wo := 0;
        fp_messagenumber := 113;
      end;
  end find_next_wo;


  procedure determine_awopc_for_candidates(fp_reference_wo_id in number,
                                           fp_picklist_id     in number ,
                                           fp_messagenumber   out number) is
    lv_workordernumber number;
    lv_awopc_string    varchar2(2048);

    cursor get_cand_wo is
      select wps.workorder_id
        from workorderpicksequence wps
       where wps.picklist_id = fp_picklist_id
         and wps.workorder_id != fp_reference_wo_id
       group by wps.picklist_id, wps.workorder_id;
  begin
    -- no loop needed , one insert statement.
    gv_message := 'insert into workorderpicksequence';
    insert into workorderpicksequence (workorder_id,
                                       picklist_id,
                                       pickingsequence)
    select woid.workorder_id, woid.picklist_id, woid.pickingsequence
      from workorderitemdistribution woid
     where woid.picklist_id = fp_picklist_id
       and woid.workorder_id != fp_reference_wo_id
     group by woid.picklist_id, woid.workorder_id, woid.pickingsequence;
    -- where not the reference wo
    -- determine workorder number for reference wo
    get_workordernumber(fp_reference_wo_id, lv_workordernumber);
    write_log('Succesfully ran determine_awopc_for_candidates for workorder ' || lv_workordernumber, 5);
    -- all ok return 0
    fp_messagenumber := 0;
    -- add AWOPC strings for candidate work orders to log
    for t in get_cand_wo loop
       -- determine workorder number for candidate wo
       get_workordernumber(t.workorder_id, lv_workordernumber);
       -- determine lv_awopc_string
       lv_awopc_string := f_determine_awopc_string(t.workorder_id, fp_picklist_id);
       write_log('AWOPC for candidate workorder '||lv_workordernumber||' = '||lv_awopc_string,5);
    end loop;
    --
  exception
    when no_data_found then
      begin
        write_log('Error determine_awopc_for_candidates: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error determine_awopc_for_candidates: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error determine_awopc_for_candidates: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end determine_awopc_for_candidates;


  procedure renumber_lines_for_picklist(fp_picklist_id   in number,
                                        fp_messagenumber out number) is
    -- variable declaration
    lv_new_linenumber       number := 0;
    lv_max_linenumber       number := -1;
    lv_prev_picklistline_id number := -1;
    lv_picklistnumber       number := -1;
    -- cursors
    cursor get_picklist_picking_lines(lv_picklist_id number) is
      select pps.*, pl.picklistnumber
        from picklistpickingsequence pps, picklist pl
       where pl.picklist_id = pps.picklist_id
         and pps.picklist_id = lv_picklist_id
       order by pps.pickinglinenumber;

    cursor get_picklist_lines(lv_picklist_id number) is
      select pll.picklistline_id
        from picklistline pll
       where pll.picklist_id = lv_picklist_id
       order by pll.linenumber;

    -- Determine the last used linenumber for this picklist + 1
    function get_max_linenumber(cp_picklistid in number) return number is
      lv_linenumber number;
    begin
       select nvl(max(pl.linenumber),0)
         into lv_linenumber
         from picklistline pl
        where pl.picklist_id = cp_picklistid;
        return lv_linenumber;
    end get_max_linenumber;

  begin
    -- Fill initial message
    gv_message := '';
    -- Determine maximum used line number (before renumber)
    lv_max_linenumber := get_max_linenumber(fp_picklist_id);
    -- Renumbering starts with maximum existing line number to avoid index violation
    lv_new_linenumber := lv_max_linenumber;
    -- Loop to select lines per pick list
    for pps_rec in get_picklist_picking_lines(fp_picklist_id) loop
      -- If new picklistline, then renumber
      if (pps_rec.picklistline_id != lv_prev_picklistline_id) then
        lv_picklistnumber := pps_rec.picklistnumber;
        lv_prev_picklistline_id := pps_rec.picklistline_id;
        -- Increase line number
        lv_new_linenumber := lv_new_linenumber + 1;
        -- Actually update line number
        update picklistline pll
           set pll.linenumber = lv_new_linenumber
         where pll.picklistline_id = pps_rec.picklistline_id;
      end if;
    end loop;
    -- Now renumber the lines once more, starting with 0
    lv_new_linenumber := 0;
    -- Loop to select lines per pick list
    for pll_rec in get_picklist_lines(fp_picklist_id) loop
      -- Increase line number
      lv_new_linenumber := lv_new_linenumber + 1;
      -- Actually update line number
      update picklistline pll
         set pll.linenumber = lv_new_linenumber
       where pll.picklistline_id = pll_rec.picklistline_id;
    end loop; -- inner loop
    write_log('Succesfully ran renumber_lines_for_picklist for picklist ' || lv_picklistnumber, 5);
    -- all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error renumber_lines_for_picklist: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error renumber_lines_for_picklist: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error renumber_lines_for_picklist: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end renumber_lines_for_picklist;


  procedure recalc_lines_for_picklist(fp_picklist_id   in number,
                                            fp_messagenumber out number) is
    -- variable declaration
    lv_linenumber     number := -1;
    lv_picklistnumber number := -1;
    -- cursors
    cursor get_picklistline_origin_lines(lv_picklistline_id number) is
      select plo.picklistlineorigin_id
        from picklistlineorigin plo
       where plo.picklistline_id = lv_picklistline_id
       order by plo.picklistlineorigin_id;

    cursor get_picklist_lines(lv_picklist_id number) is
      select pll.picklistline_id, pl.picklistnumber, pll.linenumber
        from picklist pl, picklistline pll
       where pll.picklist_id = pl.picklist_id
         and pl.picklist_id = lv_picklist_id
       order by pll.linenumber;

  begin
    -- Fill initial message
    gv_message := '';
    -- Loop to select lines per pick list
    for pll_rec in get_picklist_lines(fp_picklist_id) loop
      --
      lv_picklistnumber := pll_rec.picklistnumber;
      lv_linenumber := pll_rec.linenumber;
      -- Loop to select pick list line origin lines per pick list line
      for plo_rec in get_picklistline_origin_lines(pll_rec.picklistline_id) loop
        -- Update QtyToPick for PickListLineOrigin (work order level)
        update picklistlineorigin plo
           set plo.qtytopick = nvl((select sum(plps.qtytopick)
                                  from picklistpickingsequence plps
                                 where plps.picklistline_id = pll_rec.picklistline_id
                                   and plps.picklistlineorigin_id = plo_rec.picklistlineorigin_id),0)
         -- RVI 02-03-2015 Begin
         --where plo.picklistline_id = pll_rec.picklistline_id;
         where plo.picklistlineorigin_id = plo_rec.picklistlineorigin_id;
         -- RVI 02-03-2015 End
      end loop; -- inner loop
      -- Update QtyToPick for PickListLine (total level)
      update picklistline pll
         set pll.qtytopick = (select sum(plo.qtytopick)
                               from picklistlineorigin plo
                              where plo.picklistline_id = pll_rec.picklistline_id),
             pll.qtyrequired = (select sum(plo.qtytopick)
                                 from picklistlineorigin plo
                                where plo.picklistline_id = pll_rec.picklistline_id)
       where pll.picklistline_id = pll_rec.picklistline_id;
    end loop;
    write_log('Succesfully ran recalc_lines_for_picklist for picklist ' || lv_picklistnumber, 5);
    -- all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error recalc_lines_for_picklist: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
      end;
    when dup_val_on_index then
      begin
        write_log('Error recalc_lines_for_picklist: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error recalc_lines_for_picklist: Others ' || gv_message, 3);
        fp_messagenumber := 113;
      end;
  end recalc_lines_for_picklist;


  procedure get_stockcount_parameters (fp_stockroom_id  in number,
                                       fp_pdaforcestockcntlocations out number,
                                       fp_pdaforcestockcntminqty    out number,
                                       fp_pdaforcestockcntminmonths out number,
                                       fp_pdanostockcountlastmonths out number) is
    -- variable declaration
    lv_pdaforcestockcntlocations number := -1;
    lv_pdaforcestockcntminqty    number := -1;
    lv_pdaforcestockcntminmonths number := -1;
    lv_pdanostockcountlastmonths number := -1;
  begin
    -- Determine value for system setting PDAFORCESTOCKCNTLOCATIONS
    begin
      lv_pdaforcestockcntlocations := get_systemsetting(fp_stockroom_id, 'PDAFORCESTOCKCNTLOCATIONS');
    exception
      when others then
        begin
          write_log('No value found for system setting PDAFORCESTOCKCNTLOCATIONS', 5);
        end;
    end;
    if (lv_pdaforcestockcntlocations = -1) then
      fp_pdaforcestockcntlocations := 0;
    else
      fp_pdaforcestockcntlocations := lv_pdaforcestockcntlocations;
    end if;
    -- Determine value for system setting PDAFORCESTOCKCNTMINQTY
    begin
      lv_pdaforcestockcntminqty := get_systemsetting(fp_stockroom_id, 'PDAFORCESTOCKCNTMINQTY');
    exception
      when others then
        begin
          write_log('No value found for system setting PDAFORCESTOCKCNTMINQTY', 5);
        end;
    end;
    if (lv_pdaforcestockcntminqty = -1) then
      fp_pdaforcestockcntminqty := 0;
    else
      fp_pdaforcestockcntminqty := lv_pdaforcestockcntminqty;
    end if;
    -- Determine value for system setting PDAFORCESTOCKCNTMINMONTHS
    begin
      lv_pdaforcestockcntminmonths := get_systemsetting(fp_stockroom_id, 'PDAFORCESTOCKCNTMINMONTHS');
    exception
      when others then
        begin
          write_log('No value found for system setting PDAFORCESTOCKCNTMINMONTHS', 5);
        end;
    end;
    if (lv_pdaforcestockcntminmonths = -1) then
      fp_pdaforcestockcntminmonths := 0;
    else
      fp_pdaforcestockcntminmonths := lv_pdaforcestockcntminmonths;
    end if;
    -- Determine value for system setting PDANOSTOCKCOUNTLASTMONTHS
    begin
      lv_pdanostockcountlastmonths := get_systemsetting(fp_stockroom_id, 'PDANOSTOCKCOUNTLASTMONTHS');
    exception
      when others then
        begin
          write_log('No value found for system setting PDANOSTOCKCOUNTLASTMONTHS', 5);
        end;
    end;
    if (lv_pdanostockcountlastmonths = -1) then
      fp_pdanostockcountlastmonths := 0;
    else
      fp_pdanostockcountlastmonths := lv_pdanostockcountlastmonths;
    end if;
  end get_stockcount_parameters;


  procedure mark_forced_stockcountlocation (fp_stockroom_id  in number,
                                            fp_picklist_id   in number) is
    -- variable declaration
    lv_pdaforcestockcntlocations number := -1;
    lv_pdaforcestockcntminqty    number := -1;
    lv_pdaforcestockcntminmonths number := -1;
    lv_pdanostockcountlastmonths number := -1;
    lv_locations_marked          number := 0;
    lv_picklistline_id           number := -1;
    lv_picklistlocation_id       number := -1;
    lv_pickinglinenumber         number := -1;
    plsql_block                  varchar2(1000) := null;
    -- cursors
    cursor get_pl_lines is
      select y.*
        from (select x.*
                from (select pll.linenumber,
                             plll.*,
                             srl.areacode,
                             srl.rowcode,
                             srl.locationcode,
                             srl.datelastinvcheck,
                             (select (sq.qtyunique + sq.qtyuniquewithmodifications +
                                     sq.qtynonunique)
                                from stockquantity sq
                               where sq.stockroomlocation_id =
                                     srl.stockroomlocation_id
                                 and sq.stockreservationpergrade_id =
                                     pll.stockreservationpergrade_id) qty_on_stock
                        from picklistline         pll,
                             picklistlinelocation plll,
                             stockroomlocation    srl
                       where plll.picklistline_id = pll.picklistline_id
                         and srl.stockroomlocation_id = plll.stockroomlocation_id
                         and pll.picklist_id = fp_picklist_id) x
               where (((x.datelastinvcheck is null) or
                     (x.datelastinvcheck < add_months(sysdate, -lv_pdanostockcountlastmonths)))
                  or ((x.datelastinvcheck is null) or
                     (x.datelastinvcheck < add_months(sysdate, -lv_pdaforcestockcntminmonths)) and
                     (x.qty_on_stock < lv_pdaforcestockcntminqty)))
               order by x.linenumber) y
       where rownum <= lv_pdaforcestockcntlocations;
    -- functions
    function column_exists(table_name_ in varchar2, column_name_ in varchar2) return boolean is
      dummy_ number := 0;
      cursor check_column is
        select 1
        from   user_tab_columns
        where  table_name = upper(table_name_)
        and    column_name = upper(column_name_);
    begin
      open check_column;
      fetch check_column
        into dummy_;
      if (check_column%found) then
        close check_column;
        return true;
      else
        close check_column;
        return false;
      end if;
    end column_exists;

  begin
    -- Determine system settings concerning PDA stockcount
    get_stockcount_parameters(fp_stockroom_id, lv_pdaforcestockcntlocations, lv_pdaforcestockcntminqty,
                                               lv_pdaforcestockcntminmonths, lv_pdanostockcountlastmonths);
    -- Process all potential pick locations that might have to be counted in a loop
    for pl_rec in get_pl_lines loop
      begin
        gv_message := 'area/row/location '|| pl_rec.areacode||'/'||pl_rec.rowcode||'/'||pl_rec.locationcode;
        lv_picklistline_id := pl_rec.picklistline_id;
        lv_picklistlocation_id := pl_rec.picklistlocation_id;
        begin
          -- First check if the ForceStockCount column exist in table PICKLISTLINELOCATION
          if (column_exists('PICKLISTLINELOCATION', 'FORCESTOCKCOUNT')) then
            -- Do the actual update for PICKLISTLINELOCATION
            plsql_block :=
            'update picklistlinelocation plll
                set plll.forcestockcount = 1
              where plll.picklistlocation_id = :lv_picklistlocation_id';
            -- execute dynamic update statement
            execute immediate plsql_block using lv_picklistlocation_id;
            -- Increase number of marked locations
            if sql%rowcount > 0 then
              lv_locations_marked := lv_locations_marked + 1;
            end if;
          end if;
          -- First check if the ForceStockCount column exist in table PICKLISTPICKINGSEQUENCE
          if (column_exists('PICKLISTPICKINGSEQUENCE', 'FORCESTOCKCOUNT')) then
            -- Do the actual update for PICKLISTPICKINGSEQUENCE
            plsql_block :=
            'update picklistpickingsequence plps
                set plps.forcestockcount = 1
              where plps.picklist_id = :fp_picklist_id
                and plps.picklistline_id = :lv_picklistline_id
                and plps.picklistlocation_id = :lv_picklistlocation_id
                and plps.pickinglinenumber =
                    (select min(plps2.pickinglinenumber)
                       from picklistpickingsequence plps2
                      where plps2.picklist_id = :fp_picklist_id
                        and plps2.picklistline_id = :lv_picklistline_id
                        and plps2.picklistlocation_id = :lv_picklistlocation_id)';
            -- execute dynamic update statement
            execute immediate plsql_block using fp_picklist_id,lv_picklistline_id,lv_picklistlocation_id,
                                                fp_picklist_id,lv_picklistline_id,lv_picklistlocation_id;
          end if;
        exception
          when no_data_found then
            begin
              write_log('Error mark_forced_stockcountlocation: No_Data_Found ' || gv_message, 3);
            end;
          when dup_val_on_index then
            begin
              write_log('Error mark_forced_stockcountlocation: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
            end;
          when others then
            begin
              write_log(sqlerrm, 5);
              write_log('Error mark_forced_stockcountlocation: Others ' || gv_message, 3);
            end;
         end;
       end;
    end loop;
    write_log('Succesfully ran mark_forced_stockcountlocation for picklist.', 5);
    if (lv_locations_marked = 1) then
      write_log(lv_locations_marked || ' location has been marked to be counted.',5);
    else
      write_log(lv_locations_marked || ' locations have been marked to be counted.',5);
    end if;
  end mark_forced_stockcountlocation;


  ----- External procedures/functions ------------------------------------
  procedure create_optimized_picklist(fp_stockroomid    in stockroom.stockroom_id%type,
                                      fp_areacode       in stockroomlocation.areacode%type,
                                      fp_mobiledeviceid in mobiledevice.mobiledevice_id%type,
                                      fp_systemuserid   in systemuser.systemuser_id%type,
                                      fp_picklistid     out picklist.picklist_id%type,
                                      fp_picklistnumber out picklist.picklistnumber%type,
                                      fp_messagenumber  out number)is

    cursor get_woid is
      select x.*
       from(
         select woid.*, wo.origin, wo.neededdate, wo.workordernumber, op.sequencenumber orderpriority,
                nvl((select cr.priority
                       from customer c, customerranking cr
                      where cr.customerranking_id = c.customerranking_id
                        and c.customer_id = wo.customer_link_id),9999) customerpriority,
                sl.areacode, sl.rowcode, sl.locationcode, pr.code productcode, sd.code sizecode, qg.priority grade

           from workorderitemdistribution woid, workorder wo, orderpriority op, stockroomlocation sl,
                workorderline wol, product pr, sizedefinition sd, qualitygrade qg
          where woid.workorder_id in
                                    (select wol.workorder_id
                                    from  picklistline pl, picklistlineorigin plo, workorderline wol
                                   where plo.picklistline_id = pl.picklistline_id
                                     and wol.workorderline_id = plo.baselinetable_link_id
                                     and  plo.baselinetable = 'WORKORDERLINE'
                                     and pl.picklist_id = fp_picklistid
                                   group by wol.workorder_id)
           and wo.workorder_id = woid.workorder_id
           and op.orderpriority_id = wo.orderpriority_id
           and sl.stockroomlocation_id = woid.stockroomlocation_id
           and wol.workorderline_id = woid.workorderline_id
           and pr.product_id = wol.product_link_id
           and sd.sizedefinition_id = wol.sizedefinition_link_id
           and qg.qualitygrade_id = wol.requestedgrade_id
           and woid.picklist_id = fp_picklistid) x
        order by x.pickingsequence, x.areacode, x.rowcode, x.locationcode,
                 x.productcode, x.sizecode, x.grade,
                 x.orderpriority, x.neededdate, x.customerpriority, x.workordernumber;

    lv_reference_wo_id           number;
    lv_min_batch_size            number;
    lv_max_batch_size            number;
    lv_qty_possible_to_add       number;
    lv_qty_this_wo               number;
    lv_next_wo_id                number;
    lv_qty_next_wo               number;
    lv_qty_already_added         number;
    lv_picklistline_id           number;
    lv_picklistlocation_id       number;
    lv_picklistlineorigin_id     number;
    lv_picklistpickingsequenceid number;
    lv_reference_priority        number;
    lv_next_priority             number;
    lv_prioritycode              orderpriority.prioritycode%type;
    -- RVI 14-01-2015 Begin
    lv_allowphasedelivery        workorder.allowphasedelivery%type;
    lv_workordernumber           number;
    lv_qty_to_add_ref_wo         number;
    -- RVI 14-01-2015 End
    -- RVI 01-05-2015 Begin
    lv_qty_added_this_wo         number;
    -- RVI 01-05-2015 End
    -- RVI 15-05-2015 Begin
    lv_qty_added_ref_wo          number;
    lv_dummy_qty                 number;
    -- RVI 15-05-2015 End
    le_no_picklistline_found       exception;
    le_no_picklistlineorigin_found exception;
    le_picklistlinelocation_failed exception;
    le_picklistpicksequence_failed exception;
    le_createoptimapicklist_failed exception;
    --
    le_invalid_parameters          exception;
    le_empty_pickingpool           exception;
    le_no_picklistlines_created    exception;

  begin
    -- Initialization
    fp_picklistid := null;
    fp_picklistnumber := null;
    fp_messagenumber := 0;
    -- Determine plant info
    get_plant_info(fp_stockroomid,gv_plantid, gv_plantcode);
    -- Check parameters, if not correct then abort procedure
    validate_parameters(fp_stockroomid, fp_areacode, fp_mobiledeviceid, fp_systemuserid, fp_messagenumber);
    if (fp_messagenumber != 0) then
      raise le_invalid_parameters;
    end if;
    -- Lock stockroom for pick list generation
    lock_for_picklist_generation(fp_stockroomid, fp_messagenumber);
    if (fp_messagenumber = 0) then
      -- Determine debug level
      gv_debuglevel := get_systemsetting(fp_stockroomid, 'DEBUG_LEVEL');
      -- Determine min/max batch size
      determine_batchsizes(fp_stockroomid, lv_min_batch_size, lv_max_batch_size);
      -- Determine maximum number of items to pick (0 = no maximum)
      if (lv_max_batch_size > 0) then
        lv_qty_possible_to_add := lv_max_batch_size;
      else
        lv_qty_possible_to_add := gv_maximum_items_to_pick;
      end if;
      -- Verify if there are any work orders in picking pool
      validate_pickingpool(fp_stockroomid, fp_messagenumber);
      if (fp_messagenumber != 0) then
        raise le_empty_pickingpool;
      end if;
      -- Determine first (reference) WO
      fp_messagenumber := select_first_WO(fp_stockroomid, fp_areacode, lv_max_batch_size, lv_reference_wo_id, lv_qty_this_wo, lv_reference_priority);
      -- Only start creation of pick list in case a reference work order was found
      if (fp_messagenumber = 0) then
        -- Determine priority code for order priority of reference work order
        get_prioritycode(lv_reference_priority, lv_prioritycode);
        write_log('Order priority of reference work order = ' || lv_prioritycode, 5);
        -- Decrease lv_qty_possible_to_add
        lv_qty_possible_to_add := lv_qty_possible_to_add - lv_qty_this_wo;
        -- Increase lv_qty_already_added
        lv_qty_already_added := lv_qty_this_wo;
        -- Create pick list
        create_picklist(fp_stockroomid,fp_areacode,fp_mobiledeviceid,fp_systemuserid,fp_picklistid,fp_picklistnumber,fp_messagenumber);
        -- Only continue when pick list was succesfully created
        if (fp_messagenumber = 0) then
          -- Create pick list lines for reference work order
          get_allowphasedelivery(lv_reference_wo_id, lv_allowphasedelivery);
          if (lv_allowphasedelivery = 'N') then
            if (lv_qty_this_wo > (lv_qty_possible_to_add + lv_qty_already_added)) then
              lv_qty_to_add_ref_wo := lv_qty_this_wo;
            else
              lv_qty_to_add_ref_wo := lv_qty_possible_to_add + lv_qty_already_added;
            end if;
          else
            lv_qty_to_add_ref_wo := lv_qty_possible_to_add + lv_qty_already_added;
          end if;
          -- RVI 03-03-2015 Begin
          --create_picklist_lines(fp_picklistid,fp_areacode,lv_reference_wo_id,fp_systemuserid,
          --create_picklist_lines(fp_picklistid,fp_areacode,lv_reference_wo_id,null,fp_systemuserid,
          --                      lv_qty_to_add_ref_wo,fp_messagenumber);
          -- RVI 03-03-2015 End
          -- RVI 01-05-2015 Begin
          create_picklist_lines(fp_picklistid,fp_areacode,lv_reference_wo_id,null,fp_systemuserid,
                                lv_qty_to_add_ref_wo,lv_qty_added_this_wo,fp_messagenumber);
          if (lv_qty_added_this_wo > 0) then
            -- take into account possibility that less items could be picked than requested
            if (lv_qty_added_this_wo < lv_qty_this_wo) then
              lv_qty_already_added := lv_qty_added_this_wo;
              lv_qty_possible_to_add := lv_qty_possible_to_add + (lv_qty_this_wo - lv_qty_added_this_wo);
              lv_qty_to_add_ref_wo := lv_qty_added_this_wo;
            end if;
          end if;
          -- RVI 01-05-2015 End
          -- If no pick list line created for reference work order, then abort procedure
          if (fp_messagenumber = -1) then
            raise le_no_picklistlines_created;
          end if;
          -- Determine item distribution for reference work order
          if (fp_messagenumber = 0) then
            -- RVI 15-01-2015 Begin
            --determine_item_distr_for_wo(lv_reference_wo_id,fp_picklistid,fp_stockroomid,fp_areacode,fp_messagenumber);
            --determine_item_distr_for_wo(lv_reference_wo_id,fp_picklistid,fp_stockroomid,fp_areacode,
            --                            lv_qty_to_add_ref_wo,fp_messagenumber);
            -- RVI 15-01-2015 End
            -- RVI 15-05-2015 Begin
            determine_item_distr_for_wo(lv_reference_wo_id,fp_picklistid,fp_stockroomid,fp_areacode,
                                        lv_qty_to_add_ref_wo,lv_qty_added_ref_wo,fp_messagenumber);
            -- RVI 15-05-2015 Begin
          end if;
          -- Determine picking sequences of stockroom locations to visit for reference work order
          if (fp_messagenumber = 0) then
            determine_awopc_for_wo(lv_reference_wo_id,fp_picklistid,fp_messagenumber);
          end if;
          -- Set PickListPrinted flag for reference work order
          if (fp_messagenumber = 0) then
            update_workorder(lv_reference_wo_id,fp_systemuserid,fp_messagenumber);
          end if;
          -- Determine item distribution for potential candidate work orders
          if (fp_messagenumber = 0) then
            determine_item_distr_for_cand(lv_reference_wo_id,fp_picklistid,fp_stockroomid,fp_areacode,
                                          lv_qty_possible_to_add,fp_messagenumber);
          end if;
          -- Determine picking sequences of stockroom locations to visit for potential candidate work orders
          if (fp_messagenumber = 0) then
            determine_awopc_for_candidates(lv_reference_wo_id,fp_picklistid,fp_messagenumber);
          end if;
          -- Start while loop to find additional work orders
          while (fp_messagenumber = 0 and lv_qty_possible_to_add > 0) loop
            -- Search for next candidate work order for current priority
            find_next_wo(lv_reference_wo_id, fp_picklistid,lv_qty_possible_to_add,lv_qty_already_added,lv_reference_priority,
                         lv_min_batch_size,lv_max_batch_size,lv_next_wo_id,lv_qty_next_wo,lv_next_priority,fp_messagenumber);
            -- If no next work order found and no next priority found then loop should be ended
            if ((lv_next_wo_id = -1) and (lv_next_priority = -1)) then
              lv_qty_possible_to_add := 0;
            end if;
            -- RVI 15-01-2015 Begin
            -- If next work order found and allow phased delivery = 'Y' and surplus determined for available
            -- items on stock then work order should be added to next pick list, but loop should not be ended
            if ((lv_next_wo_id > 0) and (fp_messagenumber = 0)) then
              get_allowphasedelivery(lv_next_wo_id, lv_allowphasedelivery);
              if ((lv_allowphasedelivery = 'Y')
               and (lv_qty_next_wo > lv_qty_possible_to_add)) then
                if (f_wo_has_surplus_stock(lv_next_wo_id, fp_picklistid, fp_areacode)) then
                  get_workordernumber(lv_next_wo_id, lv_workordernumber);
                  -- add message to log to show info why work order was not added to current pick list
                  gv_message := 'candidate workorder '|| to_char(lv_workordernumber) || ' skipped';
                  write_log('create_optimized_picklists: '|| gv_message, 5);
                  gv_message := 'Number of requested items '|| to_char(lv_qty_next_wo);
                  gv_message := gv_message || ' exceeds remaining batch size ' || to_char(lv_qty_possible_to_add);
                  write_log('create_optimized_picklists: '|| gv_message, 5);
                  gv_message := 'work order '|| to_char(lv_workordernumber) || ' will be added to next pick list ';
                  gv_message := gv_message || ' although it may be delivered partially due to a surplus stock';
                  write_log('create_optimized_picklists: '|| gv_message, 5);
                  -- reset counter to end loop
                  lv_qty_possible_to_add := 0;
                  lv_next_priority := -1;
                  lv_next_wo_id := -1;
                end if;
              end if;
            end if;
            -- RVI 15-01-2015 End
            -- If next priority found, then set current priority to new (lower) priority
            if (lv_next_priority > lv_reference_priority) then
              lv_reference_priority := lv_next_priority;
            end if;
            -- If next workorder found, then add work order to pick list
            if ((lv_next_wo_id > 0) and (fp_messagenumber = 0)) then
              -- create pick list list lines for next found work order
              -- RVI 03-03-2015 Begin
              --create_picklist_lines(fp_picklistid,fp_areacode,lv_next_wo_id,fp_systemuserid,
              --create_picklist_lines(fp_picklistid,fp_areacode,lv_next_wo_id,lv_reference_wo_id,fp_systemuserid,
              --                      lv_qty_possible_to_add,fp_messagenumber);
              -- RVI 03-03-2015 End
              -- RVI 15-05-2015 Begin
              -- if more requested than can be added due to max batch size, take this into account when creating pick list lines
              if (lv_qty_next_wo > lv_qty_possible_to_add) then
                lv_qty_next_wo := lv_qty_possible_to_add;
              end if;
              --
              create_picklist_lines(fp_picklistid,fp_areacode,lv_next_wo_id,lv_reference_wo_id,fp_systemuserid,
                                    lv_qty_possible_to_add,lv_qty_added_this_wo,fp_messagenumber);
              -- RVI 15-05-2015 End
              if (fp_messagenumber = 0) then
                -- RVI 01-05-2015 Begin
                -- take into account possibility that less items could be picked than requested
                if (lv_qty_added_this_wo > 0) then
                  lv_qty_next_wo := lv_qty_added_this_wo;
                end if;
                -- RVI 01-05-2015 End
                -- decrease lv_qty_possible_to_add
                lv_qty_possible_to_add := lv_qty_possible_to_add - lv_qty_next_wo;
                -- increase lv_qty_already_added
                lv_qty_already_added := lv_qty_already_added + lv_qty_next_wo;
                -- set PickListPrinted flag for candidate work order
                update_workorder(lv_next_wo_id,fp_systemuserid,fp_messagenumber);
              end if;
            end if;
          end loop;
        end if;
        -- Create PickListPickingSequence records as needed on the PDA
        -- determine distinct wo numbers via PickListLineOrigin table
        -- determine WorkOrderItemDistribution records for selected wo numbers
        -- sort WorkOrderItemDistribution on PickingSequence, arecode, rowcode, locationcode, product, size, grade,
        --                                   neededdate, customerprio, orderprio, order#
        if (fp_messagenumber <= 0) then
        -- For each selected WOID record
          for woid_rec in get_woid loop
            -- Determine PickListLine, if no record found then raise error-message
            if (f_picklistline_exists(woid_rec.picklist_id,woid_rec.stockreservationpergrade_id,
                                    woid_rec.stocktype,lv_picklistline_id))
              then
                -- Determine PickListLineLocation record, create new record in case it does not exist yet, or update it
                if (f_picklistlinelocation_exists(lv_picklistline_id,woid_rec.stockroomlocation_id,lv_picklistlocation_id))
                  then
                    update_picklistlinelocation(lv_picklistlocation_id,woid_rec.qty_to_pick,fp_systemuserid,fp_messagenumber);
                else
                    create_picklistlinelocation(lv_picklistline_id,woid_rec.stockroomlocation_id,woid_rec.qty_to_pick,fp_systemuserid,
                                              lv_picklistlocation_id,fp_messagenumber);
                end if;
                -- no picklistlinelocastion found and/or creation or update failed then raise error-message
                if (lv_picklistlocation_id is null) or (fp_messagenumber != 0) then
                   gv_message := 'determine/create/update picklistlineolocation';
                   raise le_picklistlinelocation_failed;
                end if;
                -- determine PickListLineOrigin, if no record found then raise error-message
                if (f_picklistlineorigin_exists(lv_picklistline_id,woid_rec.origin,'WORKORDERLINE',woid_rec.workorderline_id,
                                                lv_picklistlineorigin_id))
                   then
                      -- no picklistlineorigin found then raise error-message
                      if (lv_picklistlineorigin_id is not null) then
                        if (f_picklistpicksequence_exists(fp_picklistid,lv_picklistline_id,lv_picklistlineorigin_id,
                                                          lv_picklistlocation_id, lv_picklistpickingsequenceid))
                          then
                            update_picklistpickingsequence(lv_picklistpickingsequenceid,woid_rec.qty_to_pick,fp_systemuserid,fp_messagenumber);
                        else
                          -- create picklistpickingsequence record
                          create_picklistpickingsequence(fp_picklistid,lv_picklistline_id,lv_picklistlineorigin_id, lv_picklistlocation_id,
                                                         woid_rec.qty_to_pick,fp_systemuserid,lv_picklistpickingsequenceid,fp_messagenumber);
                        end if;
                        -- if creation failed then raise error-message
                        if (lv_picklistpickingsequenceid is null) or (fp_messagenumber != 0) then
                          gv_message := 'create/update picklistpickingsequence';
                          raise le_picklistpicksequence_failed;
                        end if;
                      else
                         gv_message := 'determine picklistlineorigin';
                         raise le_no_picklistlineorigin_found;
                      end if;
                end if;
            else
               gv_message := 'determine picklistline';
               raise le_no_picklistline_found;
            end if;
          end loop; -- processing candiate workorder item distribution
        end if; -- candidate work order(s) found

        -- renumber picklistlines based upon picklistpickingsequence
        if ((fp_messagenumber <= 0) and (fp_picklistid is not null)) then
          renumber_lines_for_picklist(fp_picklistid,fp_messagenumber);
        end if;
        -- correct qty to pick for pick list lines
        if ((fp_messagenumber <= 0) and (fp_picklistid is not null)) then
          recalc_lines_for_picklist(fp_picklistid,fp_messagenumber);
        end if;
        -- mark picking locations for a forced stock count when applicable
        if ((fp_messagenumber <= 0) and (fp_picklistid is not null)) then
          mark_forced_stockcountlocation(fp_stockroomid,fp_picklistid);
        end if;
      end if; -- wo found

      if (fp_messagenumber <= 0) then
        -- clean temporary tables. delete from workorderpicksequence, workorderitemdistribution for fp_picklistid
        clean_temp_tables(fp_picklistid);
        -- unlock picklist
        unlock_for_picklist_generation(fp_stockroomid);
        -- commit
        commit;
      else
        gv_message := 'stumbled upon something. No final pick list created, process aborted';
        raise le_createoptimapicklist_failed;
      end if;
    end if; -- lock possible
  exception
    when le_invalid_parameters then
      begin
        write_log('Error create_optimized_picklists: ' || gv_message, 3);
        rollback;
      end;
    when le_empty_pickingpool then
      begin
        write_log('Error create_optimized_picklists: ' || gv_message, 3);
        rollback;
      end;
    when le_createoptimapicklist_failed then
      begin
        write_log('Error create_optimized_picklists: ' || gv_message, 3);
        rollback;
      end;
    when le_no_picklistline_found then
      begin
        write_log('Error create_optimized_picklists: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 114;
        rollback;
      end;
    when le_picklistlinelocation_failed then
      begin
        write_log('Error create_optimized_picklists: Update/Create failed ' || gv_message, 3);
        if (fp_messagenumber = 0) then
          fp_messagenumber := 115;
        end if;
        rollback;
      end;
    when le_picklistpicksequence_failed then
      begin
        write_log('Error create_optimized_picklists: Create failed ' || gv_message, 3);
        fp_messagenumber := 116;
        rollback;
      end;
    when le_no_picklistlineorigin_found then
      begin
        write_log('Error create_optimized_picklists: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 117;
        rollback;
      end;
    when le_no_picklistlines_created then
      begin
        gv_message := 'No pick list lines created for reference workorder';
        write_log('Error create_optimized_picklists: ' || gv_message, 3);
        fp_messagenumber := 118;
        rollback;
      end;
    when no_data_found then
      begin
        write_log('Error create_optimized_picklists: No_Data_Found ' || gv_message, 3);
        fp_messagenumber := 111;
        rollback;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create_optimized_picklist: Dup_Val_On_Index ' || gv_message || ' ' || sqlerrm, 3);
        fp_messagenumber := 112;
        rollback;
     end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create_optimized_picklist: Others ' || gv_message, 3);
        fp_messagenumber := 113;
        rollback;
    end;
  end create_optimized_picklist;

  ------------------------------------------------------------------------
begin
  -- Initialization
  gv_message := 'Initalization - Determine picking_user_id';
  -- get default user
  select s.systemuser_id into gv_picking_userid from systemuser s where s.username = 'APU';
exception
  when no_data_found then
    begin
      write_log('Error PACK_ADVANCEDPICKING: No_Data_Found '|| gv_message, 2);
    end;
END PACK_ADVANCEDPICKING;
/
create or replace package PACK_AFTER_UPDATE is
  /****************************************************************************************\
  *  Author  : ABS                                                                         *
  *  Purpose : This package will be used for any data manipulation or configurations needed*
  *            after completing an application update                                      *
  *  Version : 0.2                                                                         *
  *  Created : 01.02.2024 ABS-161456                                                       *
  *  Updated : 02.04.2024 ABS-153450 Audit functionality was updated                       *
  \****************************************************************************************/
  procedure UPDATE_FINISHED(errCode out NUMBER);
end PACK_AFTER_UPDATE;
/
create or replace package body PACK_AFTER_UPDATE is
  gv_errCode number;

  -- define error codes to be returned to java
  c_no_error                       number := 0;
  c_error_import_fixed_info        number := 30;
  c_error_fill_dateyearweek        number := 40;
  c_error_erp_transaction_log      number := 50;
  c_error_audit_check              number := 60;

  procedure writelog(fp_message  in abslog.message%type,
                     fp_priority in abslog.priority%type,
                     fp_source   in abslog.logsource%type default 'PACK_AFTER_UPDATE') is
  begin
    abslogwrite.abslog_write(5, fp_source, null, fp_priority, fp_message);
    begin
      dbms_output.put_line(fp_message);
    exception
      when others then
        null;
    end;
  end writelog;

  procedure add_audit_tables is
  begin
    -- activate audit for default a_tables DATABASESETTINGS and SYSTEMSETTING
    insert into a_tablelist
      (a_tablelist_id, tablename, processed, a_tablename)
      select seq_a_tablelist.nextval, t.table_name, 0, 'A_' || t.table_name
        from user_tables t
       where t.table_name in ('DATABASESETTINGS', 'SYSTEMSETTING')
         and not exists
       (select 1 from a_tablelist a where a.tablename = t.table_name);
    commit;
    pack_auditfunctionality.install_audit_functionality;
  end add_audit_tables;

  procedure create_erp_transaction_log is
    lv_createview clob;
  begin
    --select all log tables
    for x in (select 'select ''' || t.table_name || ''' erp_tablename, transfer_id, transfer_status, text, process_status, timestamp from ' ||
                      t.table_name || ' union all ' createview
                from user_tables t
               where substr(t.table_name, 1, 4) = 'ERP_'
                 and substr(t.table_name, -3) = 'LOG'
                 and t.table_name not in ('ERP_TRANSACTION_LOG')
               order by t.table_name)
    loop
      begin
        lv_createview := lv_createview || x.createview;
      end;
    end loop; --x
    lv_createview := 'CREATE OR REPLACE VIEW ERP_TRANSACTION_LOG AS ' || upper(lv_createview) ||
                      q'{ SELECT 'ABSLOG' ERP_TABLENAME,
                             L.ABSLOG_ID TRANSFER_ID,
                             0 TRANSFER_STATUS,
                             L.MESSAGE TEXT,
                             CASE
                               WHEN L.PRIORITY > 1 THEN
                                1
                               ELSE
                                0
                             END PROCESS_STATUS,
                             L.TIMESTAMP
                        FROM ABSLOG L
                       WHERE L.LOGTYPE = 5
                         AND L.LOGSOURCE = 'ERP_Interface'}';
    --create a_table based on fp_tablename with name fp_audit_tablename
    execute immediate lv_createview;
  end create_erp_transaction_log;

  procedure UPDATE_FINISHED(errCode out NUMBER) is
    temp number;
    logStr varchar2(1500);

  begin
    gv_errCode := c_no_error;

    -- fill table DATE_YEARWEEKDAY
    begin
      fill_date_yearweek;
      select year into temp from date_yearweekday where rownum = 1;
      writelog('Fill table date_yearweekday OK', 1);
    exception
      when others then
        logStr := 'Error in fill_date_yearweek: ' || sqlcode || ' - ' || sqlerrm;
        errCode := c_error_fill_dateyearweek;
        writelog(logStr, 3);
        return;
    end;

    -- create erp_transaction_log
    begin
      create_erp_transaction_log;
      writelog('Create ERP transaction log OK', 1);
    exception
      when others then
        logStr := 'Error in create_erp_transaction_log: ' || sqlcode || ' - ' || sqlerrm;
        errCode := c_error_erp_transaction_log;
        writelog(logStr, 3);
        return;
    end;

    -- update audit tables
    begin
      --install missing audit tables
      add_audit_tables;

      --check&update already installed audit tables
      pack_auditfunctionality.check_audit_functionality(gv_errcode);
      if (gv_errCode = 0) then
        writelog('Audit functionality check OK', 1);
      end if;
    exception
      when others then
        logStr := 'Error in check_audit_functionality: ' || sqlcode || ' - ' || sqlerrm;
        errCode := c_error_audit_check;
        writelog(logStr, 3);
        return;
    end;

    -- import fixed info
    begin
      pack_utilities.importfixedinfo(null, 1, gv_errcode);
      if (gv_errCode != 0) then
        raise_application_error(-20000, 'Check abslog for pack_utilities for details.');
      else
        writelog('Import fixed info OK', 1);
      end if;
    exception
      when others then
        logStr := 'Error in import_fixed_info: ' || sqlcode || ' - ' || sqlerrm;
        errCode := c_error_import_fixed_info;
        writelog(logStr, 3);
        return;
    end;
  end UPDATE_FINISHED;
end PACK_AFTER_UPDATE;
/
create or replace package pack_auditfunctionality is
  ------------------------------------------------------------------------------------------------
  /*pack_auditfunctionality version 0.34*/
  --14-04-2022 ABS-126149 Research reporting audit tool, requires Script_09.06.01.25.sql
  --16-06-2022 ABS-126149 Research reporting audit tool, requires Script_09.06.02.01.sql
  --07-03-2023 ABS-147855 A_TABLELIST cleanup, requires script_09.07.01.20.sql
  --09-03-2023 ABS-148050 A_TABLELIST cleanup, turn off option, put processed=2 to remove trigger
  --22-01-2024 ABS-153450 Dialogs for AUDIT functionality
  --31-05-2024 ABS-164939 Enhance audit trail dialog II
  --21-01-2025 ABSN-1732 Extend Audit Trail dialog
  ------------------------------------------------------------------------------------------------
  --Internal functions
  function f_chk_days_to_keep(fp_a_tablename in varchar2) return number;

  --Procedure for installing setup from table A_TABLELIST
  procedure install_audit_functionality(fp_a_tablename in varchar2 default null);

  procedure install_audit_table(fp_errorcode out number, fp_a_tablename in varchar2 default null);

  --Run this procedure after an database update to update the audit functionality as well
  procedure check_audit_functionality(fp_errorcode   out number,
                                      fp_a_tablename in varchar2 default null);

  --Schedule this procedure once a day for example to clean audit table data
  --In order for the cleanup to work, you need to fill the new field DAYS_TO_KEEP with a value
  procedure cleanup_audit_tables;

  --Schedule this procedure once a day for example to clean audit table data
  --So it also uses cleanup_audit_tables, but also starts and stops fact. audit sessions
  procedure monitor_audit_tables;

  --Drop audit tables
  procedure remove_audit_table(fp_errorcode out number, fp_a_tablename in varchar2);

end pack_auditfunctionality;
/
create or replace package body pack_auditfunctionality is
  ---internal procedure(s)
  procedure write_log(fp_message in varchar2, fp_priority in number) is
    gv_systemuserid systemuser.systemuser_id%type := null;
    gv_plantid      plant.plant_id%type := null;
  begin
    /* Logging: write message in ABSLOG with these priorities for fp_priority:
    1 = Message
    2 = Warning
    3 = Error */
    abslogwrite.abslog_write(5, 'pack_auditfunctionality', gv_plantid, fp_priority, fp_message,
                             gv_systemuserid);
    begin
      dbms_output.put_line(fp_message);
    exception
      when others then
        null;
    end;
  end write_log;

  procedure create_a_table(fp_tablename in varchar2, fp_audit_tablename in varchar2) is
  begin
    --create a_table based on fp_tablename with name fp_audit_tablename NO DATA
    execute immediate 'CREATE TABLE ' || fp_audit_tablename || ' AS SELECT * FROM ' || fp_tablename ||
                      ' WHERE 0 = 1';
    --add columns to the a-table
    execute immediate 'ALTER TABLE ' || fp_audit_tablename ||
                      ' ADD A_ACTION VARCHAR2(1) DEFAULT ''I'' NOT NULL';
    execute immediate 'ALTER TABLE ' || fp_audit_tablename ||
                      ' ADD A_TIMESTAMP DATE DEFAULT SYSDATE NOT NULL';
    execute immediate 'ALTER TABLE ' || fp_audit_tablename ||
                      ' ADD A_CLIENT_IDENTIFIER VARCHAR2(64)';
    --write log
    write_log('Created A_' || substr(fp_tablename, 1, 24) || ' For ' || fp_tablename, 1);
  exception
    --exception handling
    when no_data_found then
      begin
        write_log('Error no data found; ' || fp_tablename || ' create_a_table', 3);
        raise;
      end;
    when others then
      begin
        if sqlcode = -955 then
          null; -- suppresses ORA-00955 exception, table does already exist
        else
          write_log('Error others; ' || sqlerrm || ' ' || fp_tablename || ' create_a_table', 3);
          raise;
        end if;
      end;
  end create_a_table;

  procedure generate_a_trigger(fp_tablename            in varchar2,
                               fp_audit_tablename      in varchar2,
                               fp_exclude_a_client_idt in varchar2,
                               fp_audit_insert         in varchar2,
                               fp_audit_update         in varchar2,
                               fp_audit_delete         in varchar2) is
    ---internal variables
    gv_columnlist   clob;
    gv_newlist      clob;
    gv_oldlist      clob;
    gv_counter      number := 0;
    gv_createscript clob;
    gv_copyold      clob;
  begin
    --generate_a_trigger on fp_tablename to fill fp_audit_tablename
    --loop columns for the table
    for x in (select t.column_name
              from   user_tab_columns t
              where  t.table_name = fp_tablename
              order  by t.column_id) loop
      begin
        --build colrecent objects umn list
        gv_columnlist := gv_columnlist || ',' || x.column_name;
        gv_newlist    := gv_newlist || ',:NEW.' || x.column_name;
        gv_oldlist    := gv_oldlist || ',:OLD.' || x.column_name;
        gv_counter    := gv_counter + 1;
      end;
    end loop;
    if gv_counter = 0 then
      begin
        --wrong table name
        write_log('create a-trigger for table name ' || fp_tablename || ' no columns found!?', 2);
      end;
    else
      begin
        --remove first comma
        gv_columnlist := ltrim(gv_columnlist, ',');
        gv_newlist    := ltrim(gv_newlist, ',');
        gv_oldlist    := ltrim(gv_oldlist, ',');
        gv_copyold    := 'INSERT INTO ' || fp_audit_tablename || ' (' || gv_columnlist ||
                         ', A_ACTION, A_CLIENT_IDENTIFIER, A_TIMESTAMP)
      VALUES (' || gv_oldlist || ', ''U'', ''OLDVALUE'',SYSDATE-0.00001);';
        --build create trigger script
        gv_createscript := 'CREATE OR REPLACE TRIGGER TRG_A_' || substr(fp_tablename, 1, 24) || '
  AFTER INSERT OR UPDATE OR DELETE ON ' || fp_tablename || '
  FOR EACH ROW
DECLARE
  LV_A_CLIENT_IDT VARCHAR2(64);
BEGIN
  SELECT NVL(SYS_CONTEXT(''USERENV'', ''CLIENT_IDENTIFIER''),SYS_CONTEXT(''USERENV'', ''HOST'')) INTO LV_A_CLIENT_IDT FROM DUAL;
  IF LV_A_CLIENT_IDT NOT LIKE (''' || fp_exclude_a_client_idt ||
                           ''') THEN ' || chr(10);
        if nvl(fp_audit_update, 'Y') <> 'N' then
          gv_createscript := gv_createscript || '  IF UPDATING THEN
    BEGIN
      ' || gv_copyold || '
      INSERT INTO ' || fp_audit_tablename || ' (' || gv_columnlist ||
                             ', A_ACTION, A_CLIENT_IDENTIFIER)
      VALUES (' || gv_newlist || ', ''U'', LV_A_CLIENT_IDT);
    END;
  END IF;' || chr(10);
        end if;
        if nvl(fp_audit_insert, 'Y') <> 'N' then
          gv_createscript := gv_createscript || '  IF INSERTING THEN
    BEGIN
      INSERT INTO ' || fp_audit_tablename || ' (' || gv_columnlist ||
                             ', A_ACTION, A_CLIENT_IDENTIFIER)
      VALUES (' || gv_newlist || ', ''I'', LV_A_CLIENT_IDT);
    END;
  END IF;' || chr(10);
        end if;
        if nvl(fp_audit_delete, 'Y') <> 'N' then
          gv_createscript := gv_createscript || '  IF DELETING THEN
    BEGIN
      INSERT INTO ' || fp_audit_tablename || ' (' || gv_columnlist ||
                             ', A_ACTION, A_CLIENT_IDENTIFIER)
      VALUES (' || gv_oldlist || ', ''D'', LV_A_CLIENT_IDT);
    END;
  END IF;' || chr(10);
        end if;
        gv_createscript := gv_createscript || ' END IF;
END TRG_A_' || substr(fp_tablename, 1, 24) || ';';
        --create trigger
        execute immediate gv_createscript;
        --write log
        write_log('Created/updated TRG_A_' || substr(fp_tablename, 1, 24) || ' for ' ||
                  fp_tablename, 1);
      end;
    end if;
  exception
    --exception handling
    when no_data_found then
      begin
        write_log('Error No Data Found fp_tablename ' || fp_tablename ||
                  ' generate_a_trigger TRG_A_' || substr(fp_tablename, 1, 24), 3);
        raise;
      end;
    when others then
      begin
        write_log('Error Others ' || sqlerrm || ' fp_tablename ' || fp_tablename ||
                  ' generate_a_trigger TRG_A_' || substr(fp_tablename, 1, 24), 3);
        raise;
      end;
  end generate_a_trigger;

  procedure drop_trigger(fp_tablename in varchar2) is
  begin
    --drop_trigger
    execute immediate 'DROP TRIGGER TRG_A_' || substr(fp_tablename, 1, 24);
    write_log('Trigger TRG_A_' || substr(fp_tablename, 1, 24) || ' has been dropped', 1);
  exception
    when others then
      if sqlcode = -4080 then
        null; -- suppresses ORA-04080 exception
      else
        raise;
      end if;
  end drop_trigger;

  procedure remove_old_triggers is
    procedure check_inactive is
    begin
      --check_inactive
      update a_tablelist a
      set    a.processed = 0
      where  nvl(a.audit_startdate, to_date('31-12-2099', 'DD-MM-YYYY')) <>
             to_date('31-12-2099', 'DD-MM-YYYY')
      and    a.processed = 1
      and    a.audit_startdate > trunc(sysdate);
      --check empty a_tablename, its inactive read not installed
      update a_tablelist a
      set    a.processed = 0
      where  (a.a_tablename is null or not exists
              (select 1 from user_tables ut where ut.table_name = a.a_tablename))
      and    a.processed <> 0;
      --
      commit;
    end check_inactive;
  begin
    --check_inactive
    check_inactive;
    --remove_old_triggers
    for x in (select tr.table_name, tr.trigger_name
              from   user_triggers tr
              join   a_tablelist_tableinfo ati
              on     ati.tablename = tr.table_name
              where  substr(tr.trigger_name, 1, 6) = 'TRG_A_'
              and    (exists (select 1
                       from   a_tablelist at
                       where  at.a_tablename = substr('A_' || tr.table_name, 1, 30)
                       and    at.processed <> 1) or not exists
                      (select 1
                       from   user_tables ut
                       where  ut.table_name = substr('A_' || tr.table_name, 1, 30)))) loop
      begin
        drop_trigger(x.table_name);
      end;
    end loop;
  end remove_old_triggers;

  function f_chk_days_to_keep(fp_a_tablename in varchar2) return number is
    lv_daystokeep number;
  begin
    --f_chk_days_to_keep
    for x in (select a.days_to_keep, b.dimension_table, a.audit_startdate, a.audit_enddate,
                     a.tablename
              from   a_tablelist a
              join   a_tablelist_tableinfo b
              on     a.tablename = b.tablename
              where  a.a_tablename = fp_a_tablename) loop
      begin
        if fp_a_tablename = 'A_SYSTEMSETTING' and x.days_to_keep < 128 then
          begin
            lv_daystokeep := 128;
          end;
        elsif (x.dimension_table = 'N' and (nvl(x.audit_enddate, to_date('31-12-2099', 'dd-mm-yyyy')) -
              nvl(x.audit_startdate, trunc(sysdate)) <= 7)) then
          begin
            lv_daystokeep := 0;
          end;
        elsif (x.dimension_table = 'N' and x.days_to_keep > 7 or x.days_to_keep = 0) then
          begin
            lv_daystokeep := 7;
          end;
        else
          begin
            lv_daystokeep := x.days_to_keep;
          end;
        end if;
      end;
    end loop; --x
    return lv_daystokeep;
  end f_chk_days_to_keep;

  procedure fill_view_txt_field(fp_tablename in varchar2, fp_audit_tablename in varchar2) is
    lv_col_count number;
    lv_c1        varchar2(100);
    lv_c2        varchar2(100);
    lv_c3        varchar2(100);
    lv_ckey1     varchar2(100);
    lv_ckey2     varchar2(100);
    lv_ckey3     varchar2(100);
    lv_joins     varchar2(1000);

    procedure get_unique_columns is
    begin
      --get_unique_columns
      for x in (select y.table_name, y.index_name, y.column_name1, y.column_name2, y.column_name3,
                       y.columncount
                from   (select t.table_name, t.index_name,
                                max(case
                                      when c.column_position = 1 then
                                       c.column_name
                                      else
                                       null
                                    end) column_name1,
                                max(case
                                      when c.column_position = 2 then
                                       c.column_name
                                      else
                                       null
                                    end) column_name2,
                                max(case
                                      when c.column_position = 3 then
                                       c.column_name
                                      else
                                       null
                                    end) column_name3, count(1) columncount,
                                max(case
                                      when t.index_name in
                                           ('PK2_CONTAINER_DELIVERYSCAN', 'PK_ERP_CLEANUP_SELECTION',
                                            'PK_ERP_O_ARTRANSACTION') then
                                       2
                                      when replace(t.index_name, 'XP') <> t.index_name then
                                       2
                                      else
                                       1
                                    end) orderby
                         from   user_indexes t
                         join   user_ind_columns c
                         on     c.index_name = t.index_name
                         and    c.table_name = t.table_name
                         where  t.uniqueness = 'UNIQUE' --must be an unique index
                         and    c.column_name not like 'SYS_NC000%' --not from child tables as columns
                         and    t.table_name = fp_tablename
                         group  by t.table_name, t.index_name
                         having count(1) <= 3) y
                order  by y.orderby asc) loop
        begin
          lv_col_count := x.columncount;
          lv_c1        := x.column_name1;
          lv_c2        := x.column_name2;
          lv_c3        := x.column_name3;
          exit;
        end;
      end loop;
    end get_unique_columns;

    function get_char_key(fp_column_name in varchar2) return varchar2 is
      lv_key1 varchar2(100);
    begin
      case fp_column_name
        when 'PRODUCT_ID' then
          begin
            lv_key1  := 'p.code';
            lv_joins := lv_joins || ' join product p on p.product_id = a.product_id';
          end;
        when 'CUSTOMER_ID' then
          begin
            lv_key1  := 'c.customernumber';
            lv_joins := lv_joins || ' join customer c on c.customer_id = a.customer_id';
          end;
        when 'CUSTOMER_LINK_ID' then
          begin
            lv_key1  := 'cl.customernumber';
            lv_joins := lv_joins || ' join customer cl on cl.customer_id = a.customer_link_id';
          end;
        when 'SIZEDEFINITION_ID' then
          begin
            lv_key1  := 's.code';
            lv_joins := lv_joins ||
                        ' join sizedefinition s on s.sizedefinition_id = a.sizedefinition_id';
          end;
        when 'FINISHINGMETHOD_ID' then
          begin
            lv_key1  := 'f.code';
            lv_joins := lv_joins ||
                        ' join finishingmethod f on f.finishingmethod_id = a.finishingmethod_id';
          end;
        when 'BUSINESSUNIT_ID' then
          begin
            lv_key1  := 'bu.code';
            lv_joins := lv_joins ||
                        ' join businessunit bu on bu.businessunit_id = a.businessunit_id';
          end;
        when 'PLANT_ID' then
          begin
            lv_key1  := 'pt.code';
            lv_joins := lv_joins || ' join plant pt on pt.plant_id = a.plant_id';
          end;
        when 'CONTRACT_ID' then
          begin
            lv_key1  := 'ct.code';
            lv_joins := lv_joins || ' join contract ct on ct.contract_id = a.contract_id';
          end;
        when 'CURRENCY_ID' then
          begin
            lv_key1  := 'cur.code';
            lv_joins := lv_joins || ' join currency cur on cur.currency_id = a.currency_id';
          end;
        when 'LANGUAGE_ID' then
          begin
            lv_key1  := 'l.code';
            lv_joins := lv_joins || ' join language l on l.language_id = a.language_id';
          end;
        when 'WORKSTATION_ID' then
          begin
            lv_key1  := 'wk.code';
            lv_joins := lv_joins || ' join workstation wk on wk.workstation_id = a.workstation_id';
          end;
        when 'PRODUCTGROUP_ID' then
          begin
            lv_key1  := 'pg.code';
            lv_joins := lv_joins ||
                        ' join productgroup pg on pg.productgroup_id = a.productgroup_id';
          end;
        when 'CLIENT_ID' then
          begin
            lv_key1  := 'clt.clientnumber';
            lv_joins := lv_joins || ' join client clt on clt.client_id = a.client_id';
          end;
        else
          begin
            --get_char_key
            select case t.data_type
                     when 'NUMBER' then
                      'to_char(a.' || fp_column_name || ')'
                     when 'DATE' then
                      'to_char(a.' || fp_column_name || ',''YYYYMMDDHH24MISS'')'
                     else
                      'a.' || fp_column_name
                   end
            into   lv_key1
            from   user_tab_columns t
            where  t.table_name = fp_tablename
            and    t.column_name = fp_column_name;
          end;
      end case;
      return lv_key1;
    end get_char_key;

    procedure build_with_one_column is
    begin
      lv_ckey1 := get_char_key(lv_c1);
      --build_with_one_column
      update a_tablelist a
      set    a.history_days = nvl(a.history_days, 7),
             a.view_txt = 'select a.*, ' || lv_ckey1 || ' entity_id, to_char(a.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm, b.*,
       b.' || lv_c1 || ' entity_id, to_char(b.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm
from   (select row_number() over(partition by x.' || lv_c1 || ' order by x.a_timestamp asc) row_num, x.*
        from ' || fp_audit_tablename ||
                           ' x) a
left   join (select row_number() over(partition by y.' || lv_c1 ||
                           ' order by y.a_timestamp asc) row_num, y.*
             from   ' || fp_audit_tablename || ' y) b
on     b.' || lv_c1 || ' = a.' || lv_c1 || '
and    b.row_num = a.row_num-1' || lv_joins
      where  a.view_txt is null
      and    a.tablename = fp_tablename;
    end build_with_one_column;

    procedure build_with_two_columns is
    begin
      lv_ckey1 := get_char_key(lv_c1);
      lv_ckey2 := get_char_key(lv_c2);
      --build_with_two_columns
      update a_tablelist a
      set    a.history_days = nvl(a.history_days, 7),
             a.view_txt = 'select a.*, ' || lv_ckey1 || '||''/''||' || lv_ckey2 || ' entity_id, to_char(a.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm, b.*,
       b.' || lv_c1 || ' entity_id, to_char(b.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm
from   (select row_number() over(partition by x.' || lv_c1 || ', x.' ||
                           lv_c2 || ' order by x.a_timestamp asc) row_num, x.*
        from ' || fp_audit_tablename ||
                           ' x) a
left   join (select row_number() over(partition by y.' || lv_c1 || ', y.' ||
                           lv_c2 || ' order by y.a_timestamp asc) row_num, y.*
             from   ' || fp_audit_tablename || ' y) b
on     b.' || lv_c1 || ' = a.' || lv_c1 || '
and    b.' || lv_c2 || ' = a.' || lv_c2 || '
and    b.row_num = a.row_num-1' || lv_joins
      where  a.view_txt is null
      and    a.tablename = fp_tablename;
    end build_with_two_columns;

    procedure build_with_three_columns is
    begin
      --build_with_three_columns
      lv_ckey1 := get_char_key(lv_c1);
      lv_ckey2 := get_char_key(lv_c2);
      lv_ckey3 := get_char_key(lv_c3);
      --build_with_two_columns
      update a_tablelist a
      set    a.history_days = nvl(a.history_days, 7),
             a.view_txt = 'select a.*, ' || lv_ckey1 || '||''/''||' || lv_ckey2 || '||''/''||' ||
                           lv_ckey3 || ' entity_id, to_char(a.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm, b.*,
       b.' || lv_c1 || ' entity_id, to_char(b.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm
from   (select row_number() over(partition by x.' || lv_c1 || ', x.' ||
                           lv_c2 || ', x.' || lv_c3 || ' order by x.a_timestamp asc) row_num, x.*
        from ' || fp_audit_tablename ||
                           ' x) a
left   join (select row_number() over(partition by y.' || lv_c1 || ', y.' ||
                           lv_c2 || ', y.' || lv_c3 || ' order by y.a_timestamp asc) row_num, y.*
             from   ' || fp_audit_tablename || ' y) b
on     b.' || lv_c1 || ' = a.' || lv_c1 || '
and    b.' || lv_c2 || ' = a.' || lv_c2 || '
and    b.' || lv_c3 || ' = a.' || lv_c3 || '
and    b.row_num = a.row_num-1' || lv_joins
      where  a.view_txt is null
      and    a.tablename = fp_tablename;
    end build_with_three_columns;
  begin
    lv_joins := ' ';
    case fp_tablename
      when 'DATABASESETTINGS' then
        begin
          update a_tablelist a
          set    a.history_days = nvl(a.history_days, 365),
                 a.view_txt = 'select a.*, a.code entity_id, to_char(a.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm, b.*,
       b.code entity_id, to_char(b.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm
from   (select row_number() over(partition by x.code order by x.a_timestamp asc) row_num, x.*
        from   a_databasesettings x) a
left   join (select row_number() over(partition by y.code order by y.a_timestamp asc) row_num, y.*
             from   a_databasesettings y) b
on     b.code = a.code
and    b.row_num = a.row_num-1'
          where  a.view_txt is null
          and    a.tablename = fp_tablename;
        end;
      when 'SYSTEMSETTING' then
        begin
          update a_tablelist a
          set    a.history_days = nvl(a.history_days, 32),
                 a.view_txt = 'select a.*, a.name entity_id, to_char(a.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm, b.*,
       b.name entity_id, to_char(b.a_timestamp, ''yyyymmddhh24miss'') a_timestampfm
from   (select row_number() over(partition by x.name order by x.a_timestamp asc) row_num, x.*
        from   a_systemsetting x) a
left   join (select row_number() over(partition by y.name order by y.a_timestamp asc) row_num, y.*
             from   a_systemsetting y) b
on     b.name = a.name
and    b.row_num = a.row_num-1'
          where  a.view_txt is null
          and    a.tablename = fp_tablename;
        end;
      else
        begin
          --get_unique_columns
          get_unique_columns;
          case lv_col_count
            when 1 then
              build_with_one_column;
            when 2 then
              build_with_two_columns;
            when 3 then
              build_with_three_columns;
            else
              null; -- we will not fill view txt field
          end case;
        end;
    end case;
    commit;
  end fill_view_txt_field;

  ---external procedure(s)
  procedure install_audit_table(fp_errorcode out number, fp_a_tablename in varchar2 default null) is
    lv_daystokeep number;
  begin
    --remove old triggers
    remove_old_triggers;
    --install_audit_functionality
    fp_errorcode := 0;
    for x in (select upper(a.tablename) tablename, upper(a.a_tablename) a_tablename,
                     a.audit_startdate, a.audit_enddate,
                     nvl(a.exclude_a_client_idt, 'NULL') exclude_a_client_idt, a.view_txt,
                     at.dimension_table, a.days_to_keep, a.audit_insert, a.audit_update,
                     a.audit_delete
              from   a_tablelist a
              join   a_tablelist_tableinfo at
              on     at.tablename = a.tablename
              where  a.processed = 0
              and    nvl(a.audit_startdate, trunc(sysdate)) <= trunc(sysdate)
              and    ((a.a_tablename is not null and fp_a_tablename is null) or
                    (a.a_tablename = fp_a_tablename))) loop
      begin
        --create_a_table
        pack_auditfunctionality.create_a_table(x.tablename, x.a_tablename);
        --generate_a_trigger
        pack_auditfunctionality.generate_a_trigger(x.tablename, x.a_tablename,
                                                   x.exclude_a_client_idt, x.audit_insert,
                                                   x.audit_update, x.audit_delete);
        --fill_view_txt_field
        fill_view_txt_field(x.tablename, x.a_tablename);
        lv_daystokeep := f_chk_days_to_keep(x.a_tablename);
        --update a_tablelist
        update a_tablelist a
        set    a.processed = 1,
               a.days_to_keep = case
                                  when x.dimension_table = 'N' then
                                   lv_daystokeep
                                  else
                                   a.days_to_keep
                                end
        where  a.tablename = x.tablename;
        --commit
        commit;
      exception
        when others then
          begin
            fp_errorcode := 1;
            write_log('Table ' || x.tablename || ' Audit table ' || x.a_tablename || ' got error ' ||
                      sqlerrm || ' install_audit_functionality', 3);
          end;
      end;
    end loop; --x
    commit;
    write_log('Ready', 1);
  exception
    --exception handling
    when others then
      begin
        fp_errorcode := 1;
        rollback;
        write_log('Error Others ' || sqlerrm || ' install_audit_functionality', 3);
      end;
  end install_audit_table;

  procedure install_audit_functionality(fp_a_tablename in varchar2 default null) is
    lv_errorcode number;
  begin
    --install_audit_functionality
    install_audit_table(lv_errorcode, fp_a_tablename);
  end install_audit_functionality;

  procedure check_audit_functionality(fp_errorcode   out number,
                                      fp_a_tablename in varchar2 default null) is
    lv_a_table_updated number;
    lv_errorcount      number := 0;
    lv_daystokeep      number;
    lv_not_active      exception;

    procedure columns_added(fp_tablename in varchar2, fp_audit_tablename in varchar2) is
      procedure add_column(fp_tablename      in varchar2,
                           fp_column_name    in varchar2,
                           fp_data_type      in varchar2,
                           fp_data_length    in number,
                           fp_data_precision in number,
                           fp_data_scale     in number) is
      begin
        --add missing column fp_column_name to the table fp_tablename
        case fp_data_type
          when 'NUMBER' then
            begin
              if fp_data_precision is null and fp_data_scale is null then
                execute immediate 'ALTER TABLE ' || fp_tablename || ' ADD ' || fp_column_name ||
                                  ' NUMBER';
              else
                if fp_data_scale is null then
                  execute immediate 'ALTER TABLE ' || fp_tablename || ' ADD ' || fp_column_name ||
                                    ' NUMBER(' || fp_data_precision || ')';
                else
                  execute immediate 'ALTER TABLE ' || fp_tablename || ' ADD ' || fp_column_name ||
                                    ' NUMBER(' || fp_data_precision || ',' || fp_data_scale || ')';
                end if;
              end if;
            end;
          when 'DATE' then
            begin
              execute immediate 'ALTER TABLE ' || fp_tablename || ' ADD ' || fp_column_name ||
                                ' DATE';
            end;
          else
            begin
              if instr(fp_data_type, 'CHAR') > 0 then
                execute immediate 'ALTER TABLE ' || fp_tablename || ' ADD ' || fp_column_name || ' ' ||
                                  fp_data_type || '(' || fp_data_length / 4 || ')';
              else
                execute immediate 'ALTER TABLE ' || fp_tablename || ' ADD ' || fp_column_name || ' ' ||
                                  fp_data_type;
              end if;
            end;
        end case;
        lv_a_table_updated := lv_a_table_updated + 1;
        --write log that column is added
        write_log('Missing column ' || fp_column_name || ' type ' || fp_data_type ||
                  ' added to table ' || fp_tablename, 1);
      exception
        when others then
          begin
            --count errors
            lv_errorcount := lv_errorcount + 1;
            --Write in log the missing column or difference
            write_log('Error adding column ' || fp_column_name || ' to ' || fp_tablename || ' ' ||
                      sqlerrm, 3);
          end;
      end add_column;
    begin
      if fp_audit_tablename is not null then
        begin
          --columns_added
          for z in (select ut.column_name
                    from   user_tab_columns ut
                    where  ut.table_name = fp_tablename
                    minus
                    select uta.column_name
                    from   user_tab_columns uta
                    where  uta.table_name = fp_audit_tablename) loop
            begin
              for y in (select ut.column_name, ut.data_type, ut.data_length, ut.data_precision,
                               ut.data_scale
                        from   user_tab_columns ut
                        where  ut.table_name = fp_tablename
                        and    ut.column_name = z.column_name) loop
                begin
                  --add column to table
                  add_column(fp_audit_tablename, y.column_name, y.data_type, y.data_length,
                             y.data_precision, y.data_scale);
                end;
              end loop;
            end;
          end loop; --y
        end;
      end if;
    end columns_added;

    procedure columns_lengths(fp_tablename in varchar2, fp_audit_tablename in varchar2) is
      procedure length_column(fp_tablename      in varchar2,
                              fp_column_name    in varchar2,
                              fp_data_type      in varchar2,
                              fp_data_length    in number,
                              fp_data_precision in number,
                              fp_data_scale     in number) is
      begin
        --add missing column fp_column_name to the table fp_tablename
        case fp_data_type
          when 'NUMBER' then
            begin
              if fp_data_precision is null and fp_data_scale is null then
                execute immediate 'ALTER TABLE ' || fp_tablename || ' MODIFY ' || fp_column_name ||
                                  ' NUMBER';
              else
                if fp_data_scale is null then
                  execute immediate 'ALTER TABLE ' || fp_tablename || ' MODIFY ' || fp_column_name ||
                                    ' NUMBER(' || fp_data_precision || ')';
                else
                  execute immediate 'ALTER TABLE ' || fp_tablename || ' MODIFY ' || fp_column_name ||
                                    ' NUMBER(' || fp_data_precision || ',' || fp_data_scale || ')';
                end if;
              end if;
            end;
          when 'DATE' then
            begin
              execute immediate 'ALTER TABLE ' || fp_tablename || ' MODIFY ' || fp_column_name ||
                                ' DATE';
            end;
          else
            begin
              if instr(fp_data_type, 'CHAR') > 0 then
                execute immediate 'ALTER TABLE ' || fp_tablename || ' MODIFY ' || fp_column_name || ' ' ||
                                  fp_data_type || '(' || fp_data_length / 4 || ')';
              else
                execute immediate 'ALTER TABLE ' || fp_tablename || ' MODIFY ' || fp_column_name || ' ' ||
                                  fp_data_type;
              end if;
            end;
        end case;
        --write log that column is modified
        if instr(fp_data_type, 'CHAR') > 0 then
          write_log('Different column length ' || fp_column_name || ' type ' || fp_data_type || '(' ||
                    fp_data_length / 4 || ') for table ' || fp_tablename, 1);
        else
          write_log('Different column length ' || fp_column_name || ' type ' || fp_data_type || '(' ||
                    fp_data_length || ') for table ' || fp_tablename, 1);
        end if;
      exception
        when others then
          begin
            --count errors
            lv_errorcount := lv_errorcount + 1;
            --Write in log the missing column or difference
            write_log('Error changing column length ' || fp_column_name || ' to ' || fp_tablename || ' ' ||
                      sqlerrm, 3);
          end;
      end length_column;
    begin
      if fp_audit_tablename is not null then
        begin
          --columns_lengths
          for y in (select ut.column_name, ut.data_type, ut.data_length, ut.data_precision,
                           ut.data_scale
                    from   user_tab_columns ut
                    where  ut.table_name = fp_tablename
                    minus
                    select uta.column_name, uta.data_type, uta.data_length, uta.data_precision,
                           uta.data_scale
                    from   user_tab_columns uta
                    where  uta.table_name = fp_audit_tablename) loop
            begin
              --change length column
              length_column(fp_audit_tablename, y.column_name, y.data_type, y.data_length,
                            y.data_precision, y.data_scale);
            end;
          end loop; --y
        end;
      end if;
    end columns_lengths;

    procedure columns_dropped(fp_tablename in varchar2, fp_audit_tablename in varchar2) is
      lv_difference number := 0;

      procedure make_null_allowed(fp_audit_tablename in varchar2) is
      begin
        for x in (select ut.column_name
                  from   user_tab_columns ut
                  where  ut.table_name = fp_audit_tablename
                  and    ut.column_name not in ('A_ACTION', 'A_CLIENT_IDENTIFIER', 'A_TIMESTAMP')
                  and    ut.nullable = 'N'
                  minus
                  select uta.column_name
                  from   user_tab_columns uta
                  where  uta.table_name = fp_tablename
                  and    uta.nullable = 'N') loop
          begin
            lv_a_table_updated := lv_a_table_updated + 1;
            execute immediate 'ALTER TABLE ' || fp_audit_tablename || ' MODIFY ' || x.column_name ||
                              ' NULL';
          end;
        end loop;
      end make_null_allowed;

    begin
      if fp_audit_tablename is not null then
        begin
          --columns_dropped
          for z in (select ut.column_name, ut.data_type, ut.data_length, ut.data_precision,
                           ut.data_scale
                    from   user_tab_columns ut
                    where  ut.table_name = fp_audit_tablename
                    and    ut.column_name not in ('A_ACTION', 'A_CLIENT_IDENTIFIER', 'A_TIMESTAMP')
                    minus
                    select uta.column_name, uta.data_type, uta.data_length, uta.data_precision,
                           uta.data_scale
                    from   user_tab_columns uta
                    where  uta.table_name = fp_tablename) loop
            begin
              lv_difference := lv_difference + 1;
              exit;
            end;
          end loop;
          if lv_difference > 0 then
            begin
              --Set null allowed for dropped columns in real table
              make_null_allowed(fp_audit_tablename);
            end;
          end if;
        end;
      end if;
    end columns_dropped;

    procedure check_trigger(fp_tablename            in varchar2,
                            fp_audit_tablename      in varchar2,
                            fp_exclude_a_client_idt in varchar2,
                            fp_audit_insert         in varchar2,
                            fp_audit_update         in varchar2,
                            fp_audit_delete         in varchar2) is
      lv_recordcnt number;
      lv_disabled  number;
    begin
      --check_trigger
      select count(1),
             sum(case
                   when tr.status = 'DISABLED' then
                    1
                   else
                    0
                 end) disabled
      into   lv_recordcnt, lv_disabled
      from   user_triggers tr
      where  tr.trigger_name = 'TRG_A_' || substr(fp_tablename, 1, 24);
      if lv_disabled = 1 then
        begin
          execute immediate 'ALTER TRIGGER TRG_A_' || substr(fp_tablename, 1, 24) || ' ENABLE';
          --write log
          write_log('Trigger TRG_A_' || substr(fp_tablename, 1, 24) || ' has been enabled', 1);
        end;
      end if;
      if (lv_a_table_updated > 0 or lv_recordcnt = 0) then
        begin
          pack_auditfunctionality.generate_a_trigger(fp_tablename, fp_audit_tablename,
                                                     fp_exclude_a_client_idt, fp_audit_insert,
                                                     fp_audit_update, fp_audit_delete);
        end;
      else
        begin
          --check if trigger is valid
          select count(1)
          into   lv_recordcnt
          from   sys.user_errors ur
          where  ur.name = 'TRG_A_' || substr(fp_tablename, 1, 24);
          if lv_recordcnt > 0 then
            begin
              --create trigger again, because it has errors
              pack_auditfunctionality.generate_a_trigger(fp_tablename, fp_audit_tablename,
                                                         fp_exclude_a_client_idt, fp_audit_insert,
                                                         fp_audit_update, fp_audit_delete);
            end;
          end if;
        end;
      end if;
    end check_trigger;

    procedure finalize is
    begin
      --finalize
      commit;
      if lv_errorcount = 0 then
        begin
          write_log('All Ok', 1);
        end;
      else
        begin
          fp_errorcode := 1;
          write_log(lv_errorcount || ' errors, please check log!', 2);
        end;
      end if;
    end finalize;
  begin
    fp_errorcode := 0;
    --remove old triggers
    remove_old_triggers;
    --check_audit_functionality
    for x in (select upper(a.tablename) tablename, a.audit_startdate, a.audit_enddate, a.days_to_keep,
                     (select t.table_name
                       from   user_tables t
                       where  t.table_name = upper(a.a_tablename)) a_tablename,
                     nvl(a.exclude_a_client_idt, 'NULL') exclude_a_client_idt, at.dimension_table,
                     a.audit_insert, a.audit_update, a.audit_delete
              from   a_tablelist a
              join   a_tablelist_tableinfo at
              on     at.tablename = a.tablename
              where  a.processed = 1
              and    exists (select 1 from user_tables ut where ut.table_name = a.a_tablename)
              and    ((a.a_tablename is not null and fp_a_tablename is null) or
                    (a.a_tablename = fp_a_tablename))) loop
      begin
        lv_a_table_updated := 0;
        if x.a_tablename is not null then
          begin
            --columns_added
            columns_added(x.tablename, x.a_tablename);
            --columns_lengths
            columns_lengths(x.tablename, x.a_tablename);
            --columns_dropped
            columns_dropped(x.tablename, x.a_tablename);
          end;
        end if;
        --check_trigger
        check_trigger(x.tablename, x.a_tablename, x.exclude_a_client_idt, x.audit_insert,
                      x.audit_update, x.audit_update);
        --fill_view_txt_field
        fill_view_txt_field(x.tablename, x.a_tablename);
        --check if it is NOT a dimenstional table, to make sure it does not grow.
        if ((x.dimension_table = 'N' and x.days_to_keep <> f_chk_days_to_keep(x.a_tablename)) or
           x.tablename = 'SYSTEMSETTING') then
          begin
            lv_daystokeep := f_chk_days_to_keep(x.a_tablename);
            update a_tablelist a
            set    a.days_to_keep = lv_daystokeep
            where  a.tablename = x.tablename;
            commit;
          end;
        end if;
        if x.audit_enddate <= trunc(sysdate) then
          begin
            --we are going to stop the process
            update a_tablelist a set a.processed = 2 where a.tablename = x.tablename;
            commit;
          end;
        end if;
      end;
    end loop; --x
    for y in (select a.tablename from a_tablelist a where a.processed = 2) loop
      begin
        --drop trigger
        drop_trigger(y.tablename);
        --set status to 3
        update a_tablelist a set a.processed = 3 where a.tablename = y.tablename;
        commit;
      end;
    end loop;
    finalize;
  exception
    --exception handling
    when lv_not_active then
      begin
        rollback;
        fp_errorcode := 1;
        write_log('Table ' || fp_a_tablename || ' is not active!', 3);
      end;
    when others then
      begin
        rollback;
        fp_errorcode := 1;
        write_log('Error Others ' || sqlerrm || ' check_audit_functionality', 3);
      end;
  end check_audit_functionality;

  procedure cleanup_audit_tables is
    ----------locale variables
    lv_cursornum    integer;
    lv_cursor_count integer;
    lv_count        number;
    i               integer;
    lv_sql_stmnt    varchar2(4000);
    lv_message      varchar2(1000);

    procedure finalize(fp_days in number, fp_rowcount in number, fp_a_tablename in varchar2) is
    begin
      --finalize
      commit;
      if fp_rowcount = 0 then
        write_log('Successfull cleanup of ' || fp_a_tablename || ' data older then ' ||
                  to_char(fp_days) || ' days, nothing deleted', 1);
      else
        write_log('Successfull cleanup of ' || fp_a_tablename || ' data older then ' ||
                  to_char(fp_days) || ' days ' || to_char(fp_rowcount) || ' rows deleted', 1);
      end if;
    end finalize;
  begin
    --remove old triggers
    remove_old_triggers;
    --cleanup_audit_tables
    for x in (select f_chk_days_to_keep(a.a_tablename) days_to_keep, upper(a.a_tablename) a_tablename
              from   a_tablelist a
              where  nvl(a.days_to_keep, 0) >= 1
              and    a.processed = 1
              and    substr(a.a_tablename, 1, 2) = 'A_' --only cleanup A_ tables
              and    a.tablename <> 'DATABASESETTINGS' --this is table does not need to be cleanup up ever
              order  by a.a_tablename) loop
      begin
        lv_count := 0;
        --create delete statement
        lv_sql_stmnt := 'delete from ' || x.a_tablename ||
                        ' e where e.a_timestamp < trunc(sysdate-' || to_char(x.days_to_keep) ||
                        ' ) and rownum <= 25000';
        --max 100 loops 25000000 records per table per run max
        for i in 1 .. 100 loop
          begin
            lv_message   := 'Deleting for ' || x.a_tablename || ' chunk ' || i;
            lv_cursornum := dbms_sql.open_cursor;
            dbms_sql.parse(lv_cursornum, lv_sql_stmnt, dbms_sql.v7);
            lv_cursor_count := dbms_sql.execute(lv_cursornum);
            lv_count        := lv_count + lv_cursor_count;
            dbms_sql.close_cursor(lv_cursornum);
            commit;
            --nothing deleted exit
            if lv_cursor_count = 0 then
              exit;
            end if;
          end;
        end loop; -- for i in 1 .. lv_numchunks
        finalize(x.days_to_keep, lv_count, x.a_tablename);
      exception
        when others then
          begin
            write_log('Delete from ' || x.a_tablename || ' ' || lv_message || ' Error: ' ||
                      sqlerrm, 3);
          end;
      end;
    end loop;
    commit;
  exception
    --exception handling
    when others then
      begin
        rollback;
        write_log('Error Others ' || sqlerrm || ' cleanup_audit_tables', 3);
      end;
  end cleanup_audit_tables;

  procedure monitor_audit_tables is
    lv_errorcode number;
  begin
    --monitor_audit_tables
    cleanup_audit_tables;
    --
    check_audit_functionality(lv_errorcode);
    --
    install_audit_functionality;
  end monitor_audit_tables;

  procedure remove_audit_table(fp_errorcode out number, fp_a_tablename in varchar2) is
    gv_cnt number := 0;
    gv_chk number := 0;

    procedure drop_audittable is
    begin
      --drop_audittable
      if substr(fp_a_tablename, 1, 2) = 'A_' then
        begin
          execute immediate 'DROP TABLE ' || fp_a_tablename;
          write_log('Audit table ' || fp_a_tablename || ' has been removed', 1);
          gv_cnt := 1;
        end;
      end if;
    exception
      when others then
        if sqlcode = -942 then
          null; -- suppresses ORA-00942 exception
        else
          raise;
        end if;
    end drop_audittable;
  begin
    fp_errorcode := 0;
    --remove_audit_table
    for x in (select upper(a.tablename) tablename
              from   a_tablelist a
              where  a.a_tablename = fp_a_tablename
              and    substr(a.a_tablename, 1, 2) = 'A_' --can only delete A_ tables
              and    a.tablename not in ('DATABASESETTINGS', 'SYSTEMSETTING')
              and    a.processed = 99) loop
      begin
        gv_chk := 1;
        --drop trigger
        drop_trigger(x.tablename);
        --drop audit table
        drop_audittable;
      end;
    end loop; --x
    if gv_cnt = 0 and gv_chk = 1 then
      begin
        --All ok
        write_log('Table ' || fp_a_tablename || ' was already removed', 1);
      end;
    end if;
    if gv_cnt = 0 and gv_chk = 0 then
      begin
        --not ok, nothing found to be removed
        fp_errorcode := 1;
        write_log('Table ' || fp_a_tablename || ' is not marked for being removed', 1);
      end;
    end if;
    --remove old triggers
    remove_old_triggers;
  exception
    --exception handling
    when others then
      begin
        rollback;
        write_log('Error Others ' || sqlerrm || ' remove_audit_table', 3);
        fp_errorcode := 1;
      end;
  end remove_audit_table;

end pack_auditfunctionality;
/
create or replace package pack_bm is

  /****************************************************************************************\
  *  -- Author  : PVD                                                                      *
  *  -- Created : 28-07-2008                                                               *
  *  -- Purpose : Export newly added bill to customer records                              *
  *               to the Blue Martini System and import web catalog invoices.              *
  *  -- Changes : 16-Oct-2008/HVH: Add activeY check on illegal char                       *
  *               27-Oct-2008/HVH: todo 8087 Substitute del-to with bill-to                *
  *               26-Nov-2008/HVH: Order 502571 Implement Canadian tax                     *
  *               03-Dec-2008/HVH: todo 8268 cut off too long strings                      *
  *               09-Dec-2008/HVH: todo 8290 cut off too long strings 2                    *
  *               06-Mar-2009/HVH: todo 8597 add additional decorationtypes                *
  *               10-Jul-2009/HVH: todo 9100 don't export dummy state GS                   *
  *               18-Nov-2009/PVD: Order 502743 make email address 300                     *
  *               11-Jan-2010/LCO: todo 9884 Change required in export partnerpricelist    *
  *                                for web catalog customers, instead of discountbands     *
  *               04-Jun-2010/LCO: todo 10324 change calculation of paymenttermsduedate,   *
  *                                because it swapps 2 types of payment terms              *
  *               08-Jul-2010/PVD: todo 10578 skip fake state codes MP BP and OP           *
  *               04-Jan-2011/LCO: todo 11066 Blue Martini Interface fails when the value  *
  *                                passed from the web is too long                         *
  \****************************************************************************************/

  --The only 2 functions that can be used from this package
  function exp_wc_customers(fp_plantcode in varchar2 default 'ALL',
                            fp_debugmode in varchar2 default 'N',
                            fp_exportall in varchar2 default 'N',
                            fp_custxml   out clob) return number;

  function imp_wc_invoices(fp_custxml in clob, fp_debugmode in varchar2 default 'N') return number;

end pack_bm;
/
create or replace package body pack_bm is
  gv_pack_bm_type            varchar2(100);
  gv_systemuserid            systemuser.systemuser_id%type;
  gv_lastexportdate          date;
  gv_currexportdate          date;
  gv_bmdiscount_id           specialcharge.specialcharge_id%type;
  gv_bmfreight_id            specialcharge.specialcharge_id%type;
  gv_size_minus_id           sizedefinition.sizedefinition_id%type;
  gv_product_c0emb_id        product.product_id%type;
  gv_product_c0slkp_id       product.product_id%type;
  gv_product_c0embr_id       product.product_id%type;
  gv_product_c0embco_id      product.product_id%type;
  gv_product_c0embna_id      product.product_id%type;
  gv_return                  char(1) := chr(10);
  gv_contactpersonfunctionid contactperson.contactpersonfunction_id%type;
  gv_returnstatus            number;

  procedure write_log(fp_err_msg   in varchar2,
                      fp_debugmode in varchar2 default 'Y',
                      fp_priority  in number default 1) is
  begin
    /* writes conversion logs into database.
    priority
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info  */
    if fp_debugmode = 'Y' then
      abslogwrite.abslog_write(5, gv_pack_bm_type, null, fp_priority, fp_err_msg,
                               gv_systemuserid);
    end if;
  end write_log;

  function get_day_number(fp_date in date) return number is
    lv_day_number number;
  begin
    lv_day_number := to_char(fp_date, 'D') - 1;
    if lv_day_number <= 0 then
      lv_day_number := 7;
    end if;
    return lv_day_number;
  exception
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('In pack_bm.get_day_number', 'Y', 3);
        raise;
      end;
  end get_day_number;

  function check_char_via_lookup(fp_lookuptype  in lookupvalues.lookuptype%type,
                                 fp_checkstring in varchar2,
                                 fp_debugmode   in varchar2 default 'N') return number is
    le_wrongchar exception;
  begin
    for x in (select luv.code from lookupvalues luv where luv.lookuptype = fp_lookuptype and luv.activeyn='Y') loop
      begin
        if replace(fp_checkstring, x.code) <> fp_checkstring then
          raise le_wrongchar;
        end if;
      end;
    end loop;
    return 0; --all ok
  exception
    when le_wrongchar then
      return 1;
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('In pack_bm.check_char_via_lookup ' || fp_lookuptype || ' !', fp_debugmode, 3);
        return 2;
        raise;
      end;
  end check_char_via_lookup;

  procedure get_last_export_date(fp_debugmode in varchar2 default 'N') is
  begin
    write_log('Begin pack_bm.get_last_export_date', fp_debugmode,5);
    --get previous export date
    select nvl(gs.datevalue, to_date('1-1-2000', 'DD-MM-YYYY'))
    into   gv_lastexportdate
    from   generalsystemsetting gs
    where  gs.settingname = 'WEBCATTIMESTAMPLASTEXPORT'
    and    gs.settingtype = 'D';
    write_log('End pack_bm.get_last_export_date', fp_debugmode,5);
  exception
    when no_data_found then
      begin
        insert into generalsystemsetting
          (settingname, settingtype, datevalue)
        values
          ('WEBCATTIMESTAMPLASTEXPORT', 'D', to_date('1-1-2000', 'DD-MM-YYYY'));
        write_log('End pack_bm.get_last_export_date', fp_debugmode,5);
      end;
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.get_last_export_date', fp_debugmode,5);
        raise;
      end;
  end get_last_export_date;

  procedure set_last_export_date(fp_debugmode in varchar2 default 'N') is
  begin
    write_log('Begin pack_bm.set_last_export_date', fp_debugmode,5);
    --set current export date
    update generalsystemsetting gs
    set    gs.datevalue = gv_currexportdate
    where  gs.settingname = 'WEBCATTIMESTAMPLASTEXPORT'
    and    gs.settingtype = 'D';
    if sql%rowcount = 0 then
      begin
        insert into generalsystemsetting
          (settingname, settingtype, datevalue)
        values
          ('WEBCATTIMESTAMPLASTEXPORT', 'D', trunc(sysdate));
      end;
    end if;
    commit;
    write_log('End pack_bm.set_last_export_date', fp_debugmode,5);
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.get_last_export_date', fp_debugmode,5);
        raise;
      end;
  end set_last_export_date;

  procedure webcatcustomerexp_delete(fp_plantcode in varchar2 default 'ALL',
                                     fp_debugmode in varchar2 default 'N',
                                     fp_exportall in varchar2 default 'N') is
  begin
    write_log('Begin pack_bm.webcatcustomerexp_delete', fp_debugmode,5);
    --delete old entries
    case
      when fp_plantcode = 'ALL' then
        --all business units
        if fp_exportall = 'Y' then
          delete from webcatcustomerexp;
        else
          delete from webcatcustomerexp wecc
          where  exists (select 1
                  from   customer c
                  where  c.customer_id = wecc.customer_id
                  and    ((c.timestamp > gv_lastexportdate and wecc.processedflag='E')
                  or  wecc.processedflag<>'E'));
        end if;
      else
        --one business unit
        if fp_exportall = 'Y' then
          delete from webcatcustomerexp where branchcode = fp_plantcode;
        else
          delete from webcatcustomerexp wecc
          where  branchcode = fp_plantcode
          and    exists (select 1
                  from   customer c
                  where  c.customer_id = wecc.customer_id
                  and    ((c.timestamp > gv_lastexportdate and wecc.processedflag='E')
                  or  wecc.processedflag<>'E'));
        end if;
    end case;
    commit;
    write_log('End pack_bm.webcatcustomerexp_delete', fp_debugmode,5);
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatcustomerexp_delete', fp_debugmode,5);
        raise;
      end;
  end webcatcustomerexp_delete;

  procedure webcatcustomerexp_fill(fp_plantcode in varchar2 default 'ALL',
                                   fp_debugmode in varchar2 default 'N',
                                   fp_exportall in varchar2 default 'N') is
  begin
    write_log('Begin pack_bm.webcatcustomerexp_fill', fp_debugmode,5);
    --fill webcatcustomerexp table
    -- todo 9884
    -- Added column PARTNERPRICELIST in table webcatcustomerexp
    insert into webcatcustomerexp
      (customer_id, actioncode, customernumber, name, organizationstatus, addressid, address1,
       address2, city, state, county, postalcode, country, branchcode, payonaccount,
       catalogdiscountband, decorationdiscountband, partnerpricelist, taxexemptid, micrositecode, contract)
      select c.customer_id,
             case
               when c.exportdatefin is null then
                'N'
               else
                'U'
             end, c.customernumber, c.name,
             case
               when c.active = 'Y' then
                'A'
               else
                'I'
             end, a.address_id, nvl(nvl(a.street, a.street2), '-'),
             case
               when a.street is not null then
                a.street2
               else
                null
             end,
             nvl((select cc.name from citycounty cc where cc.citycounty_id = c.citytaxauthority_id),
                  a.city),
/* 10-07-2009 HVH change to export state from address when tax state is 'GS'
                  change to export county from address when tax county is 'GST'
*/
--             nvl((select st.code from states st where st.states_id = c.states_id), a.state),
--             nvl((select cc.name from citycounty cc where cc.citycounty_id = c.countytaxauthority_id),
--               a.county),
             nvl((select substr(st.code,1,2) from states st
                   where st.states_id = c.states_id and st.code not in ('GS','MP','BP','OP')), a.state),
             nvl((select cc.name from citycounty cc
                   where cc.citycounty_id = c.countytaxauthority_id and cc.name <> 'GST'), a.county),
/* End Change */
             a.zipcode postalcode, substr(co.code, 1, 2), substr(b.code, 1, 3),
             case
               when c.paymentmethod = 1 then
                'N' -- COD
               else
                'Y' -- Charge
             end,
           -- todo 9884
     /*  case
               when substr(r.ranking, 5, 1) between '0' and '9' then
                nvl(to_number(substr(r.ranking, 5, 1)), 0)
               else
                0
             end,
             case
               when substr(r.ranking, 10, 1) between '0' and '9' then
                nvl(to_number(substr(r.ranking, 10, 1)), 0)
               else
                0
             end, */
       0,
       0,
       r.ranking,
      -- End todo 9884
             c.taxexemptcode,
             cm.description, -- microsite = communication method description
             substr(co.code, 1, 2) || '_Contract'
      from   customer c, businessunit b, customerranking r, address a, country co,
             communicationmethod_desc cm
      where  c.customer_id = c.debtor_id -- only bill to customers
      and    c.defaultbusinessunit_id = b.businessunit_id
      and    c.customerranking_id = r.customerranking_id(+)
      and    c.communicationmethod_id = cm.communicationmethod_id
      and    cm.language_id=1   -- only English description for commm.method
      and    c.invoiceaddress_id = a.address_id
      and    c.country_id = co.country_id
      and    ((c.exportdatefin is null or
              (c.timestamp > gv_lastexportdate and
               c.timestamp <= gv_currexportdate)) or
            fp_exportall = 'Y')
      and    ((fp_plantcode = 'ALL') or (b.code = fp_plantcode))
      and    not exists
       (select 1 from webcatcustomerexp wcce where wcce.customer_id = c.customer_id);
    commit;
    --
    write_log('End pack_bm.webcatcustomerexp_fill', fp_debugmode,5);
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatcustomerexp_fill', fp_debugmode, 5);
        raise;
      end;
  end webcatcustomerexp_fill;

  procedure webcatcustomerexp_defaultfix(fp_debugmode in varchar2 default 'N') is
  begin
    write_log('Begin pack_bm.webcatcustomerexp_defaultfix', fp_debugmode,5);
    --only check not yet processed lines
    --fix customer name
    update webcatcustomerexp wcce
    set    wcce.name = replace(replace(replace(replace(replace(wcce.name, '{', '('), '}', ')'), '\',
                                                '/'), ':', ''), '*', ''), wcce.timestamp = sysdate
    where  wcce.processedflag = 'N'
    and    wcce.name <> replace(replace(replace(replace(replace(wcce.name, '{', '('), '}', ')'), '\',
                                                '/'), ':', ''), '*', '');
    --fix address
    update webcatcustomerexp wcce
    set    wcce.address1 = substr(replace(replace(wcce.address1, '@', 'at'), '\', '/'),1,30),
           wcce.address2 = substr(replace(replace(wcce.address2, '@', 'at'), '\', '/'),1,30),
           wcce.timestamp = sysdate
    where  wcce.processedflag = 'N'
    and    (wcce.address1 <> replace(replace(wcce.address1, '@', 'at'), '\', '/') or
          wcce.address2 <> replace(replace(wcce.address2, '@', 'at'), '\', '/'));
    --update state
    update webcatcustomerexp wcce
    set    wcce.state = 'NL', wcce.timestamp = sysdate
    where  wcce.processedflag = 'N'
    and    wcce.state = 'NF'
    and    wcce.country = 'CA';
    --fix postalcode
    update webcatcustomerexp wcce
    set    wcce.postalcode = replace(replace(replace(wcce.postalcode, ' - ', ' '), '   ', ' '), '  ',
                                      ' '), wcce.timestamp = sysdate
    where  wcce.processedflag = 'N'
    and    wcce.postalcode <>
           replace(replace(replace(wcce.postalcode, ' - ', ' '), '   ', ' '), '  ', ' ');
    --
    commit;
    write_log('End pack_bm.webcatcustomerexp_defaultfix', fp_debugmode,5);
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatcustomerexp_defaultfix', fp_debugmode,5);
        raise;
      end;
  end webcatcustomerexp_defaultfix;

  procedure webcatcustomerexp_upd_procflag(fp_customerid  in webcatcustomerexp.customer_id%type,
                                           fp_processflag in webcatcustomerexp.processedflag%type,
                                           fp_debugmode   in varchar2 default 'N') is
  begin
    update webcatcustomerexp wcce
    set    wcce.processedflag = fp_processflag, wcce.timestamp = sysdate
    where  wcce.customer_id = fp_customerid;
    commit;
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('In pack_bm.webcatcustomerexp_upd_procflag.', fp_debugmode, 3);
        raise;
      end;
  end webcatcustomerexp_upd_procflag;

  procedure webcatcustomerexp_validate(fp_debugmode in varchar2 default 'N') is
  begin
    write_log('Begin pack_bm.webcatcustomerexp_validate', fp_debugmode,5);
    --update all to processed flag = N were previously an error occurred
    update webcatcustomerexp wcce
    set    wcce.processedflag = 'N', wcce.timestamp = sysdate
    where  wcce.processedflag = 'E';
    --fix general settings
    webcatcustomerexp_defaultfix;
    --loop all recods to be processed
    for x in (select wcce.customer_id, wcce.customernumber, wcce.name, wcce.address1, wcce.address2,
                     wcce.city, wcce.county, wcce.postalcode, wcce.state
              from   webcatcustomerexp wcce
              where  wcce.processedflag = 'N') loop
      begin
        --check chars in:
        --name
        if check_char_via_lookup('ILLEGALCHARNAME', x.name, fp_debugmode) <> 0 then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('Illegal character found in name ' || x.name || ' of customer ' || x.customernumber, 'Y',
                      3);
          end;
        end if;
        --address1
        if check_char_via_lookup('ILLEGALCHARADDRESS', x.address1, fp_debugmode) <> 0 then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('Illegal character found in address ' || x.address1 || ' of customer ' ||
                      x.customernumber, 'Y', 3);
          end;
        end if;
        --address2
        if check_char_via_lookup('ILLEGALCHARADDRESS', x.address2, fp_debugmode) <> 0 then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('Illegal character found in address ' || x.address2 || ' of customer ' ||
                      x.customernumber, 'Y', 3);
          end;
        end if;
        --city
        if check_char_via_lookup('ILLEGALCHARCITY', x.city, fp_debugmode) <> 0 then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('Illegal character found in city ' || x.city || ' of customer ' || x.customernumber, 'Y',
                      3);
          end;
        end if;
        --county
        if check_char_via_lookup('ILLEGALCHARCOUNTY', x.county, fp_debugmode) <> 0 then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('Illegal character found in county ' || x.county || ' of customer ' || x.customernumber,
                      'Y', 3);
          end;
        end if;
        --postal code
        if not (regexp_like(upper(x.postalcode),
                            '^[[:alpha:]][[:digit:]][[:alpha:]]( |-|)[[:digit:]][[:alpha:]][[:digit:]]$') or
            regexp_like(x.postalcode, '^[[:digit:]]{5}$') or
            regexp_like(x.postalcode, '^[[:digit:]]{5}( |-|)[[:digit:]]{4}$')) then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('Illegal formatted postalcode ' || x.postalcode || ' of customer ' ||
                      x.customernumber, 'Y', 3);
          end;
        end if;
        --check if customer has state
        if x.state is null then
          begin
            webcatcustomerexp_upd_procflag(x.customer_id, 'E', fp_debugmode);
            write_log('No state defined for customer ' || x.customernumber,'Y', 3);
          end;
        end if;
      end;
    end loop;
    --
    commit;
    write_log('End pack_bm.webcatcustomerexp_validate', fp_debugmode,5);
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatcustomerexp_validate', fp_debugmode,5);
        raise;
      end;
  end webcatcustomerexp_validate;

  procedure webcatcustomerexp_to_exported is
  begin
    --set customer as exported
    update customer c
    set    c.exportdatefin = sysdate
    where  exists (select 1
            from   webcatcustomerexp wcce
            where  wcce.customer_id = c.customer_id
            and    wcce.processedflag = 'N');
    --flag record as processed
    update webcatcustomerexp wcce
    set    wcce.processedflag = 'Y', wcce.timestamp = sysdate
    where  wcce.processedflag = 'N';
    commit;
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatcustomerexp_to_exported!', 'Y', 3);
        raise;
      end;
  end webcatcustomerexp_to_exported;

  function exp_wc_customers(fp_plantcode in varchar2 default 'ALL',
                            fp_debugmode in varchar2 default 'N',
                            fp_exportall in varchar2 default 'N',
                            fp_custxml   out clob) return number is
    lv_plantcode varchar2(3);
    lv_queryctx  sys.dbms_xmlgen.ctxtype;
    le_nodata2process exception;
    lv_counter number;
  begin
    gv_pack_bm_type := 'Export Web Catalog Customers';
    write_log('Start Export Web Catalog Customers');
    write_log('Parameters: Business Unit Code='||fp_plantcode||' Export All='||fp_exportall, fp_debugmode, 5);
    --intialize
    get_last_export_date(fp_debugmode);
    select sysdate into gv_currexportdate from dual;
    write_log('Last Export='||to_char(gv_lastexportdate,'MM-DD-YYYY HH24:MM:SS')||' Current Export='||to_char(gv_currexportdate,'MM-DD-YYYY HH24:MM:SS'), fp_debugmode, 5);
    lv_plantcode := nvl(substr(fp_plantcode, 1, 3), 'ALL'); --only length 3 allowed
    --delete old entries
    webcatcustomerexp_delete(lv_plantcode, fp_debugmode, fp_exportall);
    --fill with new entries
    webcatcustomerexp_fill(lv_plantcode, fp_debugmode, fp_exportall);
    --validate all entries
    webcatcustomerexp_validate(fp_debugmode);
    --check if there's data to process
    select count(1) into lv_counter from webcatcustomerexp wcce where wcce.processedflag = 'N';
    if lv_counter = 0 then
      raise le_nodata2process;
    end if;
    --export to html clob
    lv_queryctx := sys.dbms_xmlgen.newcontext('select
    CUSTOMERNUMBER OrganizationCode,
    ACTIONCODE OrganizationActionCode,
    CUSTOMER_ID ABSCustomerID,
    NAME Name,
    ORGANIZATIONSTATUS OrganizationStatus,
    ADDRESSID,
    ADDRESS1,
    ADDRESS2,
    CITY,
    STATE,
    COUNTY,
    POSTALCODE,
    COUNTRY,
    BRANCHCODE,
    PAYONACCOUNT,
    CATALOGDISCOUNTBAND,
    DECORATIONDISCOUNTBAND,
    PARTNERPRICELIST,
    TAXEXEMPTID TaxExempt,
    MICROSITECODE,
    CONTRACT
    from webcatcustomerexp where processedflag = ''N''');
    sys.dbms_xmlgen.setrowtag(lv_queryctx, 'Organization');
    sys.dbms_xmlgen.setrowsettag(lv_queryctx, 'ABSOutbound');
    fp_custxml := sys.dbms_xmlgen.getxml(lv_queryctx);
    sys.dbms_xmlgen.closecontext(lv_queryctx);
    --finalize
    set_last_export_date(fp_debugmode);
    webcatcustomerexp_to_exported;
    write_log(to_char(lv_counter) || ' customers exported succesfully.');
    write_log('End Export Web Catalog Customers');
    return 0;
  exception
    when le_nodata2process then
      begin
        write_log('No data to process..', fp_debugmode);
        write_log('End Export Web Catalog Customers');
        return 1;
      end;
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('End Export Web Catalog Customers');
        return 2;
      end;
  end exp_wc_customers;

  procedure webcatinvoice_wcih_update_flag(fp_payloadid     in webcatinvoiceheaderimp.payloadid%type,
                                           fp_paymentid     in webcatinvoiceheaderimp.paymentid%type,
                                           fp_processedflag in webcatinvoiceheaderimp.processedflag%type) is
  begin
    update webcatinvoiceheaderimp wcih
    set    wcih.processedflag = fp_processedflag, wcih.timestamp = sysdate
    where  wcih.payloadid = fp_payloadid
    and    wcih.paymentid = fp_paymentid;
  exception
    when others then
      begin
        gv_returnstatus := 1;
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_wcih_update_flag', 'Y', 3);
        raise;
      end;
  end webcatinvoice_wcih_update_flag;

  procedure webcatinvoice_wcip_update_flag(fp_payloadid     in webcatinvoiceproductimp.payloadid%type,
                                           fp_paymentid     in webcatinvoiceproductimp.paymentid%type,
                                           fp_linenumber    in webcatinvoiceproductimp.linenumber%type,
                                           fp_processedflag in webcatinvoiceproductimp.processedflag%type) is
  begin
    update webcatinvoiceproductimp wcip
    set    wcip.processedflag = fp_processedflag, wcip.timestamp = sysdate
    where  wcip.payloadid = fp_payloadid
    and    wcip.paymentid = fp_paymentid
    and    wcip.linenumber = fp_linenumber;
  exception
    when others then
      begin
        gv_returnstatus := 1;
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_wcip_update_flag', 'Y', 3);
        raise;
      end;
  end webcatinvoice_wcip_update_flag;

  procedure webcatinvoice_wcid_update_flag(fp_payloadid     in webcatinvoicedecorationimp.payloadid%type,
                                           fp_paymentid     in webcatinvoicedecorationimp.paymentid%type,
                                           fp_linenumber    in webcatinvoicedecorationimp.linenumber%type,
                                           fp_processedflag in webcatinvoicedecorationimp.processedflag%type) is
  begin
    --update WCID
    update webcatinvoicedecorationimp wcid
    set    wcid.processedflag = fp_processedflag, wcid.timestamp = sysdate
    where  wcid.payloadid = fp_payloadid
    and    wcid.paymentid = fp_paymentid
    and    wcid.linenumber = fp_linenumber;
    --update WCIDL for they belong together
    update webcatinvdecorationlineimp wcidl
    set    wcidl.processedflag = fp_processedflag, wcidl.timestamp = sysdate
    where  wcidl.payloadid = fp_payloadid
    and    wcidl.paymentid = fp_paymentid
    and    wcidl.linenumber = fp_linenumber;
  exception
    when others then
      begin
        gv_returnstatus := 1;
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_wcid_update_flag', 'Y', 3);
        raise;
      end;
  end webcatinvoice_wcid_update_flag;

  procedure webcatinvoice_process_wcih(fp_wcih_rec in out webcatinvoiceheaderimp%rowtype,
                                       fp_extract  in varchar2,
                                       fp_counter  in number,
                                       fp_newline  in out boolean) is
    le_toomanycolumns exception;
  begin
    fp_newline := false;
    case
      when fp_counter = 1 then
        fp_wcih_rec.payloadid := substr(fp_extract,1,40);
      when fp_counter = 2 then
        fp_wcih_rec.paymentid := substr(fp_extract,1,10);
      when fp_counter = 3 then
        fp_wcih_rec.ordernumber := fp_extract;
      when fp_counter = 4 then
        fp_wcih_rec.customerordernumber := substr(fp_extract,1,30);
      when fp_counter = 5 then
        fp_wcih_rec.settlementdate := to_date(fp_extract, 'yyyy-mm-dd');
      when fp_counter = 6 then
        fp_wcih_rec.orderdate := to_date(fp_extract, 'yyyy-mm-dd');
      when fp_counter = 7 then
        fp_wcih_rec.currency := substr(fp_extract,1,3);
      when fp_counter = 8 then
        fp_wcih_rec.settlementtype := substr(fp_extract,1,1);
      when fp_counter = 9 then
        fp_wcih_rec.invoicetotal := fp_extract;
      when fp_counter = 10 then
        fp_wcih_rec.invoicediscount := nvl(fp_extract,0);
      when fp_counter = 11 then
        fp_wcih_rec.freighttotal := nvl(fp_extract,0);
      when fp_counter = 12 then
        fp_wcih_rec.freightdiscount := nvl(fp_extract,0);
      when fp_counter = 13 then
        fp_wcih_rec.freighttax := nvl(fp_extract,0);
      when fp_counter = 14 then
        fp_wcih_rec.taxtotal := nvl(fp_extract,0);
      when fp_counter = 15 then
        fp_wcih_rec.customernumber := fp_extract;
      when fp_counter = 16 then
        fp_wcih_rec.customername := substr(fp_extract,1,80);
      when fp_counter = 17 then
        fp_wcih_rec.billtoaddressid := fp_extract;
      when fp_counter = 18 then
        fp_wcih_rec.billtoaddressstreet1 := substr(fp_extract,1,240);
      when fp_counter = 19 then
        fp_wcih_rec.billtoaddressstreet2 := substr(fp_extract,1,240);
      when fp_counter = 20 then
        fp_wcih_rec.billtoaddresscity := substr(fp_extract,1,60);
      when fp_counter = 21 then
        fp_wcih_rec.billtoaddressstate := substr(fp_extract,1,2);
      when fp_counter = 22 then
        fp_wcih_rec.billtoaddresszipcode := substr(fp_extract,1,15);
      when fp_counter = 23 then
        fp_wcih_rec.billtoaddresscounty := substr(fp_extract,1,80);
      when fp_counter = 24 then
        fp_wcih_rec.billtocontactname := substr(fp_extract,1,80);
      when fp_counter = 25 then
        fp_wcih_rec.shiptoaddressid := fp_extract;
      when fp_counter = 26 then
        fp_wcih_rec.shiptoaddressstreet1 := substr(fp_extract,1,240);
      when fp_counter = 27 then
        fp_wcih_rec.shiptoaddressstreet2 := substr(fp_extract,1,240);
      when fp_counter = 28 then
        fp_wcih_rec.shiptoaddresscity := substr(fp_extract,1,60);
      when fp_counter = 29 then
        fp_wcih_rec.shiptoaddressstate := substr(fp_extract,1,2);
      when fp_counter = 30 then
        fp_wcih_rec.shiptoaddresszipcode := substr(fp_extract,1,15);
      when fp_counter = 31 then
        fp_wcih_rec.shiptoaddresscounty := substr(fp_extract,1,80);
      when fp_counter = 32 then
        fp_wcih_rec.shiptocontactname := substr(fp_extract,1,80);
      when fp_counter = 33 then
        fp_wcih_rec.promotioncode := substr(fp_extract,1,30);
      when fp_counter = 34 then
        fp_wcih_rec.contactpersonid := fp_extract;
      when fp_counter = 35 then
        --Order 502743 make email address 300, for PACK_BM (8.02.03.2487)
        fp_wcih_rec.contactpersonemail := substr(fp_extract,1,300);
      when fp_counter = 36 then
        fp_wcih_rec.contactpersonname := substr(fp_extract,1,80);
      when fp_counter = 37 then
        fp_wcih_rec.accomodationnotestype := substr(fp_extract,1,80);
      when fp_counter = 38 then
        fp_wcih_rec.creditcardtype := substr(fp_extract,1,10);
      when fp_counter = 39 then
        fp_wcih_rec.payamount := fp_extract;
      when fp_counter = 40 then
        fp_wcih_rec.cybersourcetransactionnumber := substr(fp_extract,1,40);
      when fp_counter = 41 then
        fp_wcih_rec.freightgst := nvl(fp_extract,0);
      else
        raise le_toomanycolumns;
    end case;
    if fp_counter = 41 then
      begin
        fp_wcih_rec.processedflag := 'N';
        fp_wcih_rec.timestamp     := sysdate;
        insert into webcatinvoiceheaderimp values fp_wcih_rec;
        fp_newline := true;
      end;
    end if;
  exception
    when dup_val_on_index then
      begin
        --first delete
        delete from webcatinvoiceheaderimp wcih
        where  wcih.payloadid = fp_wcih_rec.payloadid
        and    wcih.paymentid = fp_wcih_rec.paymentid
        and    wcih.processedflag in ('E','N');
        --then insert
        insert into webcatinvoiceheaderimp values fp_wcih_rec;
        fp_newline := true;
      exception
        when dup_val_on_index then
          begin
            gv_returnstatus := 2;
            write_log('Invoice record already exists, with payloadID ' || fp_wcih_rec.payloadid || ' and payID: '
                      || fp_wcih_rec.paymentid, 'Y', 3);
            raise;
          end;
      end;
    when le_toomanycolumns then
      begin
        gv_returnstatus := 2;
        write_log('Error too many columns in header record!', 'Y', 3);
        raise;
      end;
    when others then
      begin
        gv_returnstatus := 2;
        write_log(sqlerrm, 'Y', 3);
        write_log('For column number ' || to_char(fp_counter) || ' value ' || fp_extract, 'Y', 3);
        write_log('For payloadID and payID: ' || fp_wcih_rec.payloadid || ' ' ||
                  fp_wcih_rec.paymentid, 'Y', 3);
        raise;
      end;
  end webcatinvoice_process_wcih;

  procedure webcatinvoice_process_wcip(fp_wcip_rec in out webcatinvoiceproductimp%rowtype,
                                       fp_extract  in varchar2,
                                       fp_counter  in number,
                                       fp_newline  in out boolean) is
    le_toomanycolumns exception;
  begin
    fp_newline := false;
    case
      when fp_counter = 1 then
        fp_wcip_rec.payloadid := substr(fp_extract,1,40);
      when fp_counter = 2 then
        fp_wcip_rec.paymentid := substr(fp_extract,1,10);
      when fp_counter = 3 then
        fp_wcip_rec.linenumber := fp_extract;
      when fp_counter = 4 then
        fp_wcip_rec.itemid := substr(fp_extract,1,24);
      when fp_counter = 5 then
        fp_wcip_rec.productcode := substr(fp_extract,1,12);
      when fp_counter = 6 then
        fp_wcip_rec.sizecode := substr(fp_extract,1,12);
      when fp_counter = 7 then
        fp_wcip_rec.description := substr(fp_extract,1,80);
      when fp_counter = 8 then
        fp_wcip_rec.quantity := nvl(fp_extract, 1);
      when fp_counter = 9 then
        fp_wcip_rec.price := fp_extract;
      when fp_counter = 10 then
        fp_wcip_rec.amount := fp_extract;
      when fp_counter = 11 then
        fp_wcip_rec.taxableyn := substr(fp_extract,1,1);
      when fp_counter = 12 then
        fp_wcip_rec.pstamount := nvl(fp_extract,0);
      else
        raise le_toomanycolumns;
    end case;
    if fp_counter = 12 then
      begin
        fp_wcip_rec.processedflag := 'N';
        fp_wcip_rec.timestamp     := sysdate;
        insert into webcatinvoiceproductimp values fp_wcip_rec;
        fp_newline := true;
      end;
    end if;
  exception
    when le_toomanycolumns then
      begin
        gv_returnstatus := 2;
        write_log('Error too many columns in product record!', 'Y', 3);
        raise;
      end;
    when dup_val_on_index then
      begin
        gv_returnstatus := 2;
        write_log('Product record already exists, with payloadID, payID and line#: ' ||
                  fp_wcip_rec.payloadid || ' ' || fp_wcip_rec.paymentid || ' ' ||
                  fp_wcip_rec.linenumber, 'Y', 3);
        raise;
      end;
    when others then
      begin
        gv_returnstatus := 2;
        write_log(sqlerrm, 'Y', 3);
        write_log('For field number ' || to_char(fp_counter) || ' value ' || fp_extract, 'Y', 3);
        write_log('For payloadID, payID and line#: ' || fp_wcip_rec.payloadid || ' ' ||
                  fp_wcip_rec.paymentid || ' ' || fp_wcip_rec.linenumber, 'Y', 3);
        raise;
      end;
  end webcatinvoice_process_wcip;

  procedure webcatinvoice_process_wcid(fp_wcid_rec in out webcatinvoicedecorationimp%rowtype,
                                       fp_extract  in varchar2,
                                       fp_counter  in number,
                                       fp_newline  in out boolean) is
    le_toomanycolumns exception;
  begin
    fp_newline := false;
    case
      when fp_counter = 1 then
        fp_wcid_rec.payloadid := substr(fp_extract,1,40);
      when fp_counter = 2 then
        fp_wcid_rec.paymentid := substr(fp_extract,1,10);
      when fp_counter = 3 then
        fp_wcid_rec.linenumber := fp_extract;
      when fp_counter = 4 then
        fp_wcid_rec.decorationtype := substr(fp_extract,1,10);
      when fp_counter = 5 then
        fp_wcid_rec.location := substr(fp_extract,1,3);
      when fp_counter = 6 then
        fp_wcid_rec.logocode := substr(fp_extract,1,20);
      when fp_counter = 7 then
        fp_wcid_rec.appliquestyle := substr(fp_extract,1,2);
      when fp_counter = 8 then
        fp_wcid_rec.emblemtype := substr(fp_extract,1,10);
      when fp_counter = 9 then
        fp_wcid_rec.alignment := substr(fp_extract,1,10);
      when fp_counter = 10 then
        fp_wcid_rec.backgroundcolor := substr(fp_extract,1,30);
      when fp_counter = 11 then
        fp_wcid_rec.bordercolor := substr(fp_extract,1,30);
      when fp_counter = 12 then
        fp_wcid_rec.quantity := nvl(fp_extract, 1);
      when fp_counter = 13 then
        fp_wcid_rec.price := fp_extract;
      when fp_counter = 14 then
        fp_wcid_rec.amount := fp_extract;
      when fp_counter = 15 then
        fp_wcid_rec.taxableyn := substr(fp_extract,1,1);
      when fp_counter = 16 then
        fp_wcid_rec.pstamount := nvl(fp_extract,0);
      else
        raise le_toomanycolumns;
    end case;
    if fp_counter = 16 then
      begin
        fp_wcid_rec.processedflag := 'N';
        fp_wcid_rec.timestamp     := sysdate;
        insert into webcatinvoicedecorationimp values fp_wcid_rec;
        fp_newline := true;
      end;
    end if;
  exception
    when le_toomanycolumns then
      begin
        gv_returnstatus := 2;
        write_log('Error too many columns in decoration record !', 'Y', 3);
        raise;
      end;
    when dup_val_on_index then
      begin
        gv_returnstatus := 2;
        write_log('Decoration already exists, with payloadID, payID and line#: ' ||
                  fp_wcid_rec.payloadid || ' ' || fp_wcid_rec.paymentid || ' ' ||
                  fp_wcid_rec.linenumber, 'Y', 3);
        raise;
      end;
    when others then
      begin
        gv_returnstatus := 2;
        write_log(sqlerrm, 'Y', 3);
        write_log('For field number ' || to_char(fp_counter) || ' value ' || fp_extract, 'Y', 3);
        write_log('For payloadID, payID and line#: ' || fp_wcid_rec.payloadid || ' ' ||
                  fp_wcid_rec.paymentid || ' ' || fp_wcid_rec.linenumber, 'Y', 3);
        raise;
      end;
  end webcatinvoice_process_wcid;

  procedure webcatinvoice_process_wcidl(fp_wcidl_rec in out webcatinvdecorationlineimp%rowtype,
                                        fp_extract   in varchar2,
                                        fp_counter   in number,
                                        fp_newline   in out boolean) is
    le_toomanycolumns exception;
  begin
    fp_newline := false;
    case
      when fp_counter = 1 then
        fp_wcidl_rec.payloadid := substr(fp_extract,1,40);
      when fp_counter = 2 then
        fp_wcidl_rec.paymentid := substr(fp_extract,1,10);
      when fp_counter = 3 then
        fp_wcidl_rec.linenumber := fp_extract;
      when fp_counter = 4 then
        fp_wcidl_rec.decorationlinenumber := fp_extract;
      when fp_counter = 5 then
        fp_wcidl_rec.fontcolor := substr(fp_extract,1,30);
      when fp_counter = 6 then
        fp_wcidl_rec.fontstyle := substr(fp_extract,1,3);
      when fp_counter = 7 then
        fp_wcidl_rec.fontsize := substr(fp_extract,1,10);
      when fp_counter = 8 then
        fp_wcidl_rec.text := substr(fp_extract,1,80);
      else
        raise le_toomanycolumns;
    end case;
    if fp_counter = 8 then
      begin
        fp_wcidl_rec.processedflag := 'N';
        fp_wcidl_rec.timestamp     := sysdate;
        insert into webcatinvdecorationlineimp values fp_wcidl_rec;
        fp_newline := true;
      end;
    end if;
  exception
    when le_toomanycolumns then
      begin
        gv_returnstatus := 2;
        write_log('Error too many columns in decoration line record!', 'Y', 3);
        raise;
      end;
    when dup_val_on_index then
      begin
        gv_returnstatus := 2;
        write_log('Decoration line already exists, with payloadID, payID, line# and deco.line#: ' ||
                  fp_wcidl_rec.payloadid || ' ' || fp_wcidl_rec.paymentid || ' ' ||
                  fp_wcidl_rec.linenumber || ' ' || fp_wcidl_rec.decorationlinenumber, 'Y', 3);
        raise;
      end;
    when others then
      begin
        gv_returnstatus := 2;
        write_log(sqlerrm, 'Y', 3);
        write_log('For field number ' || to_char(fp_counter) || ' value ' || fp_extract, 'Y', 3);
        write_log('For payloadID, payID, line# and deco.line#: ' || fp_wcidl_rec.payloadid || ' ' ||
                  fp_wcidl_rec.paymentid || ' ' || fp_wcidl_rec.linenumber || ' ' ||
                  fp_wcidl_rec.decorationlinenumber, 'Y', 3);
        raise;
      end;
  end webcatinvoice_process_wcidl;


  function webcatinvoice_get_subtotal(fp_payloadid in webcatinvoiceheaderimp.payloadid%type,
                                      fp_paymentid in webcatinvoiceheaderimp.paymentid%type)
    return number is
    lv_subtotal1 number;
    lv_subtotal2 number;
  begin
    --get subtotals product
    select nvl(sum(wcip.amount), 0)
    into   lv_subtotal1
    from   webcatinvoiceproductimp wcip
    where  wcip.payloadid = fp_payloadid
    and    wcip.paymentid = fp_paymentid;
    --get subtotals decoration
    select nvl(sum(wcid.amount), 0)
    into   lv_subtotal2
    from   webcatinvoicedecorationimp wcid
    where  wcid.payloadid = fp_payloadid
    and    wcid.paymentid = fp_paymentid;
    return(lv_subtotal1 + lv_subtotal2);
  exception
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_get_subtotal', 'Y',5);
        raise;
      end;
  end webcatinvoice_get_subtotal;


  function webcatinvoice_get_pst_total(fp_payloadid in webcatinvoiceheaderimp.payloadid%type,
                                      fp_paymentid in webcatinvoiceheaderimp.paymentid%type)
    return number is
    lv_psttotal1 number;
    lv_psttotal2 number;
  begin
    --get subtotals product
    select nvl(sum(wcip.pstamount), 0)
    into   lv_psttotal1
    from   webcatinvoiceproductimp wcip
    where  wcip.payloadid = fp_payloadid
    and    wcip.paymentid = fp_paymentid;
    --get subtotals decoration
    select nvl(sum(wcid.pstamount), 0)
    into   lv_psttotal2
    from   webcatinvoicedecorationimp wcid
    where  wcid.payloadid = fp_payloadid
    and    wcid.paymentid = fp_paymentid;
    return(lv_psttotal1 + lv_psttotal2);
  exception
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_get_PST_total', 'Y', 3);
        raise;
      end;
  end webcatinvoice_get_pst_total;

  procedure webcatinvoice_read_clob(fp_custxml in clob, fp_debugmode in varchar2 default 'N') is
    lv_errormsg   abslog.message%type;
    lv_cloblength binary_integer;
    lv_extract    varchar2(1000);
    lv_newline    boolean := true;
    lv_endpos     binary_integer;
    lv_startpos   binary_integer := 1;
    lv_linetype   varchar2(2);
    lv_counter    number;
    lv_wcih_rec   webcatinvoiceheaderimp%rowtype;
    lv_wcip_rec   webcatinvoiceproductimp%rowtype;
    lv_wcid_rec   webcatinvoicedecorationimp%rowtype;
    lv_wcidl_rec  webcatinvdecorationlineimp%rowtype;
    lv_subtotal   number;
    le_toofewcolumns exception;

  begin
    write_log('Begin pack_bm.webcatinvoice_read_clob', fp_debugmode,5);
    lv_cloblength := dbms_lob.getlength(fp_custxml);
    loop
      --Get field values
      lv_endpos := dbms_lob.instr(fp_custxml, '|', lv_startpos);
      exit when(lv_startpos > lv_cloblength or lv_endpos = 0 or lv_cloblength is null or
                lv_endpos is null);
      lv_extract := dbms_lob.substr(fp_custxml, lv_endpos - lv_startpos, lv_startpos);
--    HVH Add check on too few columns
      if dbms_lob.instr(lv_extract,chr(10)) > 0 and lv_newline <> true
         then raise le_toofewcolumns;
      end if;
      lv_extract := replace(lv_extract,chr(10));   -- remove CR
      lv_startpos := lv_endpos + 1;
      --Check linetype
      if lv_extract in ('H', 'L', 'D', 'DL') and lv_newline then
        begin
          lv_linetype := lv_extract;
          lv_counter  := 0;
        end;
      else
        --WCIH
        case
          when lv_linetype = 'H' then
            webcatinvoice_process_wcih(lv_wcih_rec, lv_extract, lv_counter, lv_newline);
            --WCIP
          when lv_linetype = 'L' then
            begin
              if lv_counter = 1 then
                begin
                  --insert header
                  webcatinvoice_process_wcip(lv_wcip_rec, lv_wcih_rec.payloadid, 1, lv_newline);
                  webcatinvoice_process_wcip(lv_wcip_rec, lv_wcih_rec.paymentid, 2, lv_newline);
                  lv_counter := 3;
                end;
              end if;
              webcatinvoice_process_wcip(lv_wcip_rec, lv_extract, lv_counter, lv_newline);
            end;
            --WCID
          when lv_linetype = 'D' then
            begin
              if lv_counter = 1 then
                begin
                  --insert header
                  webcatinvoice_process_wcid(lv_wcid_rec, lv_wcih_rec.payloadid, 1, lv_newline);
                  webcatinvoice_process_wcid(lv_wcid_rec, lv_wcih_rec.paymentid, 2, lv_newline);
                  lv_counter := 3;
                end;
              end if;
              webcatinvoice_process_wcid(lv_wcid_rec, lv_extract, lv_counter, lv_newline);
            end;
            --WCIDL
          when lv_linetype = 'DL' then
            begin
              if lv_counter = 1 then
                begin
                  --insert header
                  webcatinvoice_process_wcidl(lv_wcidl_rec, lv_wcih_rec.payloadid, 1, lv_newline);
                  webcatinvoice_process_wcidl(lv_wcidl_rec, lv_wcih_rec.paymentid, 2, lv_newline);
                  webcatinvoice_process_wcidl(lv_wcidl_rec, lv_wcid_rec.linenumber, 3, lv_newline);
                  lv_counter := 4;
                end;
              end if;
              webcatinvoice_process_wcidl(lv_wcidl_rec, lv_extract, lv_counter, lv_newline);
            end;
        end case; end if;
      lv_counter := lv_counter + 1;
    end loop;
   --check if totals match
    for lv_wcih_rec in (select * from webcatinvoiceheaderimp wcih where wcih.processedflag = 'N') loop
        lv_subtotal := webcatinvoice_get_subtotal(lv_wcih_rec.payloadid, lv_wcih_rec.paymentid) +
                       lv_wcih_rec.invoicediscount + lv_wcih_rec.freighttotal +
                       lv_wcih_rec.freightdiscount + lv_wcih_rec.taxtotal +
                       lv_wcih_rec.freighttax + lv_wcih_rec.freightgst;
        if lv_subtotal <> lv_wcih_rec.invoicetotal then
          begin
            gv_returnstatus := 2;
            lv_errormsg := 'Total invoice amount does not compute!';
            write_log(lv_errormsg || ' For payloadID ' || lv_wcih_rec.payloadid || ' payID ' ||
                      lv_wcih_rec.paymentid, 'Y', 3);
          end;
        end if;
    end loop;
    if gv_returnstatus=0
      then commit;
      else rollback;
    end if;
    write_log('End pack_bm.webcatinvoice_read_clob', fp_debugmode,5);
  exception
    when le_toofewcolumns then
      begin
        gv_returnstatus := 2;
        write_log('Error too few columns in ' || lv_linetype || ' record! for payloadID:'||lv_wcih_rec.payloadid, 'Y', 3);
        write_log('During pack_bm.read_clob', 'Y', 3);
        raise;
      end;
    when others then
      begin
        rollback;
        gv_returnstatus := 2;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatinvoice_read_clob',fp_debugmode,5);
        raise;
      end;
  end webcatinvoice_read_clob;

  procedure webcatinvoice_checks(fp_debugmode in varchar2) is
    lv_errormsg abslog.message%type;
  begin
    write_log('Begin pack_bm.webcatinvoice_checks', fp_debugmode,5);
    --check special charge code 'BMDISC'
    lv_errormsg := 'Error: special charge BMDISC does not exists!';
    select sp.specialcharge_id into gv_bmdiscount_id from specialcharge sp where sp.code = 'BMDISC';
    --check special charge code 'BMFREI'
    lv_errormsg := 'Error: special charge BMFREI does not exists!';
    select sp.specialcharge_id into gv_bmfreight_id from specialcharge sp where sp.code = 'BMFREI';
    --check special products if they exist
    lv_errormsg := 'Error: product C0EMB does not exists!';
    select p.product_id into gv_product_c0emb_id from product p where p.code = 'C0EMB';
    --
    lv_errormsg := 'Error: product C0SLKP does not exists!';
    select p.product_id into gv_product_c0slkp_id from product p where p.code = 'C0SLKP';
    --
    lv_errormsg := 'Error: product C0EMBR does not exists!';
    select p.product_id into gv_product_c0embr_id from product p where p.code = 'C0EMBR';
    --
    lv_errormsg := 'Error: product C0EMBCO does not exists!';
    select p.product_id into gv_product_c0embco_id from product p where p.code = 'C0EMBCO';
    --
    lv_errormsg := 'Error: product C0EMBNA does not exists!';
    select p.product_id into gv_product_c0embna_id from product p where p.code = 'C0EMBNA';
    --get size '-'
    lv_errormsg := 'Error: size code - does not exists!';
    select s.sizedefinition_id into gv_size_minus_id from sizedefinition s where s.code = '-';
    --get contact person function
    begin
      lv_errormsg := 'Error getting/creating contactperson function WEBCAT!';
      select cpf.contactpersonfunction_id
      into   gv_contactpersonfunctionid
      from   contactpersonfunction cpf
      where  cpf.code = 'WEBCAT';
    exception
      when no_data_found then
        insert into contactpersonfunction
          (contactpersonfunction_id, code, systemuser_id, timestamp)
        values
          (seq_contactpersonfunction.nextval, 'WEBCAT', gv_systemuserid, sysdate)
        returning contactpersonfunction_id into gv_contactpersonfunctionid;
        insert into contactpersonfunction_desc
          (contactpersonfunction_id, language_id, description, systemuser_id, timestamp)
          select gv_contactpersonfunctionid, l.language_id, 'WEBCAT', gv_systemuserid, sysdate
          from   languages l;
    end;
    --
    write_log('End pack_bm.webcatinvoice_checks', fp_debugmode,5);
  exception
    when no_data_found then
      begin
        gv_returnstatus := 1;
        write_log(lv_errormsg, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_checks', fp_debugmode,5);
        write_log('End pack_bm.webcatinvoice_checks', fp_debugmode,5);
        raise;
      end;
    when others then
      begin
        gv_returnstatus := 1;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatinvoice_checks',fp_debugmode,5);
        raise;
      end;
  end webcatinvoice_checks;

  function webcatinvoice_remark(fp_payloadid  in webcatinvoicedecorationimp.payloadid%type,
                                fp_paymentid  in webcatinvoicedecorationimp.paymentid%type,
                                fp_linenumber in webcatinvoicedecorationimp.linenumber%type,
                                fp_languageid in languages.language_id%type)
    return varchar2 is
    lv_remark invoiceline.remark%type;
    lv_line_str varchar2(10);
  begin
    if fp_languageid = 1 -- 1=English
     then lv_line_str := 'Line ';
     else lv_line_str := 'Ligne ';
    end if;
    for lv_wcidl_rec in (select *
                         from   webcatinvdecorationlineimp wcidl
                         where  wcidl.payloadid = fp_payloadid
                         and    wcidl.paymentid = fp_paymentid
                         and    wcidl.linenumber = fp_linenumber) loop
      begin
        if lv_remark is not null then
          lv_remark := lv_remark || gv_return;
        end if;
        lv_remark := lv_remark || lv_line_str || lv_wcidl_rec.decorationlinenumber || ' : ' ||
                     lv_wcidl_rec.text;
      end;
    end loop; --wcidl
    return lv_remark;
  exception
    when others then
      begin
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatinvoice_remark','Y',3);
        raise;
      end;
  end webcatinvoice_remark;

  function webcatinvoice_create_route(fp_daynumber number, fp_plantid plant.plant_id%type)
    return number is
    lv_routeid          route.route_id%type;
    lv_deliveryschemeid deliveryscheme.deliveryscheme_id%type;
    lv_districtid       districtplant.district_id%type;
  begin
    --get a deliveryscheme
    select min(s.deliveryscheme_id) into lv_deliveryschemeid from deliveryscheme s;
    --get district
    select min(dp.district_id)
    into   lv_districtid
    from   districtplant dp
    where  dp.plant_id = fp_plantid;
    --insert route
    insert into route
      (route_id, plant_id, drivingday_id, routenumber, description, depot_id, systemuser_id,
       codeonlabel, timestamp, driver_id, truck_id, starttime, endtime, packingday_id,
       packingdeadline, loadingdock, putupreportpercustomer, putupreportperroute,
       putupreportperdepot, putupreportroutestop, printsoilticket, printorderform, bundletagsflatw,
       bundletagsgarm, active, sortbatchdefinition_id, commissionpayabledriver, spareroute,
       splitperpackingdept, deliveryscheme_id, printpicklistrsc, printmountingorder,
       printdismountingorder, printsalesnotes, district_id, routemanager_id)
    values
      (seq_route.nextval, fp_plantid, fp_daynumber, 1000, 'Web Catalog Sales', null,
       gv_systemuserid, null, sysdate, null, null, null, null, null, null, null, 0, 'N', 'N', 0, 'N',
       0, 0, 0, 'Y', null, 'N', 'N', 'N', lv_deliveryschemeid, 'N', 'N', 'N', 'N', lv_districtid,
       null)
    returning route_id into lv_routeid;
    commit;
    return lv_routeid;
  exception
    when others then
      begin
        rollback;
        gv_returnstatus := 1;
        write_log(sqlerrm, 'Y', 3);
        write_log('During pack_bm.webcatinvoice_create_route!', 'Y',5);
        raise;
      end;
  end webcatinvoice_create_route;

  function webcatinvoice_routecontrol(fp_routeid     in route.route_id%type,
                                      fp_plantid     in plant.plant_id%type,
                                      fp_drivingdate in routecontrol.drivingdate%type) return number is
    lv_routecontrolid routecontrol.routecontrol_id%type;
  begin
    --create routecontrol records
    insert into routecontrol
      (routecontrol_id, route_id, routelistprinted, soilticketsprinted, soilcountstatus,
       settlementstatus, packingstatus, originaldrivingdate, drivingdate, packingday_id, timestamp,
       systemuser_id, overageamount, voucheramount, totalcashcollected, totalcoddelayed,
       totalcodpaythisamnt, totalcodundelivered, totalcodplusadj, totalcodminusadj,
       totalcodprebilled, totalchargecollections, totalchargepaythisamnt, totalchargeundelivered,
       totalchargeplusadj, totalchargeminusadj, totalchargeprebilled, returntime, returndate,
       starttime, loadingdock, packingdeadline, truckcode, drivernumber, plant_id, invoicesgenerated,
       arbalance_id, startmileage, endmileage, pocketpcstatus, straightevenreturnstatus,
       routesettlementprinted, activestockcompleted, bulkputuproutecompleted, safetyremarks,
       optimizingstatus, exportdate, truckreloadcalculated, sortingstatus)
    values
      (seq_routecontrol.nextval, fp_routeid, 'Y', 'N', 1, 1, 4, trunc(fp_drivingdate),
       trunc(fp_drivingdate), null, sysdate, gv_systemuserid, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, null, null, null, null, null, null, null, fp_plantid, 3, null, 0, 0, 0, 0, 'Y', 'N',
       'N', null, 0, null, 'N', 0)
    returning routecontrol_id into lv_routecontrolid;
    commit;
    return lv_routecontrolid;
  exception
    when others then
      begin
        rollback;
        gv_returnstatus := 1;
        write_log(sqlerrm, 'Y', 3);
        write_log('During creating routecontrol in pack_bm.webcatinvoice_routecontrol!', 'Y',5);
        raise;
      end;
  end webcatinvoice_routecontrol;

  function webcatinvoice_invoiceheader(fp_wcih_rec           in webcatinvoiceheaderimp%rowtype,
                                       fp_billtocustomerid   in customer.customer_id%type,
                                       fp_billtocustomernr   in customer.customernumber%type,
                                       fp_deltocustomerid    in customer.customer_id%type,
                                       fp_currencyid         in currency.currency_id%type,
                                       fp_stateid            in states.states_id%type,
                                       fp_countyid           in citycounty.citycounty_id%type,
                                       fp_routeid            in route.route_id%type,
                                       fp_routecontrolid     in routecontrol.routecontrol_id%type,
                                       fp_debugmode          in varchar2,
                                       fp_languageid         out languages.language_id%type,
                                       fp_countryid          out country.country_id%type,
                                       fp_realcollectiontype out invoiceheader.realcollectiontype%type)
    return number is
    lv_invoiceheaderid         invoiceheader.invoiceheader_id%type;
    lv_businessunitid          businessunit.businessunit_id%type;
    lv_businessunitcode        businessunit.code%type;
    lv_invoicenumber           invoiceheader.invoicenumber%type;
    lv_discountdays            paymentterms.discountdays%type;
    lv_discountdays2           paymentterms.discountdays2%type;
    lv_netpaymentdays          paymentterms.netpaymentdays%type;
    lv_statusid                status.status_id%type;
    lv_countrydescription      country.description%type;
    lv_siccode                 customer.siccode%type;
    lv_attachementcopies       customerbillinginfo.attachinvoicecopies%type;
    lv_paymenttermid           paymentterms.paymentterms_id%type;
    lv_paymenttermsdescription paymentterms_desc.description%type;
    lv_paymenttype             customer.paymenttype%type;
    lv_paymentdiscount         paymentterms.paymentdiscount%type;
    lv_paymentdiscount2        paymentterms.paymentdiscount2%type;
    lv_paymenttermsduedate     invoiceheaderextrainfo.paymenttermsduedate%type;
    lv_paymenttermstype        paymentterms.paymenttermtype%type;
    lv_statesid                states.states_id%type;
    lv_paymentmethod           customer.paymentmethod%type;
    lv_address_rec             address%rowtype;
    lv_errormsg                abslog.message%type;
    lv_netpaymentmonths        paymentterms.netpaymentmonths%type;
  begin
    write_log('Begin pack_bm.webcatinvoice_invoiceheader', fp_debugmode,5);
    --get businessunit code
    --get customer values
    lv_errormsg := 'Error getting customer values';
    select py.discountdays, py.discountdays2, py.netpaymentdays, bu.code, c.defaultbusinessunit_id,
           c.siccode, cb.attachinvoicecopies, c.language_id, cb.paymentterms_id, c.paymenttype,
           py.paymentdiscount, py.paymentdiscount2, py.paymenttermtype, c.paymentmethod,py.netpaymentmonths
    into   lv_discountdays, lv_discountdays2, lv_netpaymentdays, lv_businessunitcode,
           lv_businessunitid, lv_siccode, lv_attachementcopies, fp_languageid, lv_paymenttermid,
           lv_paymenttype, lv_paymentdiscount, lv_paymentdiscount2, lv_paymenttermstype, lv_paymentmethod, lv_netpaymentmonths
    from   customer c, customerbillinginfo cb, businessunit bu, paymentterms py
    where  c.customer_id = fp_billtocustomerid
    and    c.customer_id = cb.customer_id
    and    py.paymentterms_id = cb.paymentterms_id
    and    c.defaultbusinessunit_id = bu.businessunit_id;
    lv_errormsg := 'Error getting paymentterms description for paymentterms with ID ' ||
    to_char(lv_paymenttermid) || ' for language ID ' || to_char(fp_languageid);
    --get paymentterm desc
    select pds.description
    into   lv_paymenttermsdescription
    from   paymentterms_desc pds
    where  pds.paymentterms_id = lv_paymenttermid
    and    pds.language_id = fp_languageid;
    --get invoicenumber
    execute immediate 'select seq_invoice_' || lv_businessunitcode || '.nextval from dual'
      into lv_invoicenumber;
    lv_errormsg := 'Error getting invoice status';
    --get status id
    select st.status_id
    into   lv_statusid
    from   status st
    where  st.statustype = 'IN'
    and    st.code = '1';
    lv_errormsg := 'Error getting invoice address';
    -- determine address for charge customers
    -- if bill-to was passed then invoice address of bill to
    -- if del-to was passed then mail address of del-to.
    if lv_paymentmethod = 2 then
      if fp_deltocustomerid=fp_billtocustomerid
       then
          select a.*
          into   lv_address_rec
          from   customer c, address a
          where  c.customer_id = fp_billtocustomerid
          and    c.invoiceaddress_id = a.address_id;
       else
          select a.*
          into   lv_address_rec
          from   customer c, address a
          where  c.customer_id = fp_deltocustomerid
          and    c.mailaddress_id = a.address_id;
       end if;
    end if;
    --get real collection type
    case
      when fp_wcih_rec.creditcardtype = 'IVC' then
        fp_realcollectiontype := 2;
      else
        fp_realcollectiontype := 1;
    end case;
  --create invoiceheader
    lv_errormsg := 'Error creating invoiceheader';
    insert into invoiceheader
      (invoiceheader_id, invoicedate, invoicenumber, documenttype, invoicebusinessunit_id,
       billtocustomer_link_id, deltocustomer_link_id, endweek, startweek, endmonth, startmonth,
       county, state, city, zipcode, street2, street, deltocustomername, deltocustomernumber,
       billtocustomername, billtocustomernumber, routecontrol_id, route_id, contactpersonphone,
       emailstatus, emailaddress, contactpersonname, stopnumber, realcollectiontype,
       originalcollectiontype, invoicetype, adjustmentreason_id, timestamp, systemuser_id, exported,
       purchaseorder, deliverinstructions, invoicecomments, totalminusadjustment,
       totalplusadjustment, cashcollected, paythisamount, prebillamount, invoicefrequency_id,
       currency_id, status_id, endyear, startyear, routenumber, depotcode, contractcode, startdate,
       enddate, creditsqueezeamount, convertedfromlegacy, totalamountexclvat, cluster_id,
       creditsqueezeperc, splitupcode, splitupdescription, stop_id, invoiceyear, invoiceweek,
       invoicedaynumber, extraname1, extraname2, parentinvoiceheader_id, contractstartdate,
       contractenddate, paymentdiscountdays, netpaymentdays, deltostreet, deltostreet2, deltocounty,
       deltostate, deltocity, deltozipcode, roundingamount, nextperiodstartdate, nextperiodenddate,
       nextperiodnoweeks, credited, creditedinvoiceno, nextperiodstartweek,
       nextperiodendweek, containresidentialservice, externalprintdate, housenumber, housenumberext,
       exportdocuware, addtoconsolidatedinv, paidamount, creditedinvoiceheader_id, underuseamount,
       invoicejobschedule_id, printdate)
    values
      (seq_invoiceheader.nextval, fp_wcih_rec.settlementdate, lv_invoicenumber, 1,
       lv_businessunitid, fp_billtocustomerid, fp_deltocustomerid, 0, 0, 0, 0,
       case when lv_paymentmethod = 1 then substr(fp_wcih_rec.billtoaddresscounty,1,20) else
        lv_address_rec.county end,
       case when lv_paymentmethod = 1 then fp_wcih_rec.billtoaddressstate else lv_address_rec.state end,
       case when lv_paymentmethod = 1 then substr(fp_wcih_rec.billtoaddresscity,1,30) else lv_address_rec.city end,
       case when lv_paymentmethod = 1 then fp_wcih_rec.billtoaddresszipcode else
        lv_address_rec.zipcode end,
       case when lv_paymentmethod = 1 then substr(fp_wcih_rec.billtoaddressstreet2,1,30) else
        lv_address_rec.street2 end,
       case when lv_paymentmethod = 1 then substr(fp_wcih_rec.billtoaddressstreet1,1,30) else
        lv_address_rec.street end, fp_wcih_rec.customername, fp_wcih_rec.customernumber,
       fp_wcih_rec.customername, fp_billtocustomernr, fp_routecontrolid, fp_routeid, null, 0,
       substr(fp_wcih_rec.contactpersonemail,1,300),substr(fp_wcih_rec.billtocontactname,1,40), 0, fp_realcollectiontype,
       fp_realcollectiontype, 1, null, sysdate, gv_systemuserid, 'N', fp_wcih_rec.ordernumber, null,
       fp_wcih_rec.accomodationnotestype, 0, 0,
       case when fp_wcih_rec.creditcardtype = 'IVC' then 0 else fp_wcih_rec.payamount end,
       fp_wcih_rec.payamount, fp_wcih_rec.invoicetotal, 0, fp_currencyid, lv_statusid, 0, 0, 1000,
       null, substr(fp_wcih_rec.customerordernumber,1,15), fp_wcih_rec.settlementdate, fp_wcih_rec.settlementdate,
       0, 'N', (fp_wcih_rec.invoicetotal - fp_wcih_rec.freighttax - fp_wcih_rec.freightgst - fp_wcih_rec.taxtotal), null, 0,
       null, null, null, to_char(fp_wcih_rec.settlementdate, 'IYYY'),
       getisoweek(fp_wcih_rec.settlementdate), to_char(fp_wcih_rec.settlementdate-1, 'D'), null,
       null, null, null, null, lv_discountdays, lv_netpaymentdays, substr(fp_wcih_rec.shiptoaddressstreet1,1,30),
       substr(fp_wcih_rec.shiptoaddressstreet2,1,30), substr(fp_wcih_rec.shiptoaddresscounty,1,20),
       fp_wcih_rec.shiptoaddressstate, substr(fp_wcih_rec.shiptoaddresscity,1,30),
       fp_wcih_rec.shiptoaddresszipcode, 0, null, null, 0, 0, 0, 0, 0, 0, null, 0, null, null,
       'N', null, null, 0, null, null)
    returning invoiceheader_id into lv_invoiceheaderid;
    --get country description
    select ct.description, ct.country_id
    into   lv_countrydescription, fp_countryid
    from   country ct, customer c
    where  ct.country_id = c.country_id
    and    c.customer_id = fp_deltocustomerid;
    --get paymentterms due date
    if (lv_paymenttermstype = 0 or fp_wcih_rec.payamount < 0) then
      lv_paymenttermsduedate := fp_wcih_rec.settlementdate;
    elsif lv_paymenttermstype = 1 then
      lv_paymenttermsduedate := fp_wcih_rec.settlementdate + lv_netpaymentdays;
    elsif lv_paymenttermstype = 2 then
      lv_paymenttermsduedate := last_day(fp_wcih_rec.settlementdate) + lv_netpaymentdays;
    elsif lv_paymenttermstype = 3 then
      lv_paymenttermsduedate := fp_wcih_rec.settlementdate + lv_netpaymentdays + lv_netpaymentmonths;
    else lv_paymenttermsduedate := last_day(fp_wcih_rec.settlementdate) + lv_netpaymentmonths + lv_netpaymentdays;
      end if;
    --create inv.header.extra info
    insert into invoiceheaderextrainfo
      (invoiceheader_id, formlayoutcode, billtocountrydescription, deltocountrydescription,
       bankinstitution_id, laundrybankinstitution_id, bankaccount, ibanno, deltocustvatnumber,
       invoicecopies, customermarkinggarment, taxable, siccode, attachinvoicecopies,
       paymenttermsdescription, acceptgiroreference, acceptgirocodeline, paymenttype, discountdays,
       paymentdiscount, discountdays2, paymentdiscount2, checknumber, paymenttermsduedate,
       paymenttermstype, paybycustomer_link_id, archivedate, expdatedailysystem)
    values
      (lv_invoiceheaderid, 'BM', lv_countrydescription, lv_countrydescription, null, null,
       fp_wcih_rec.payloadid, fp_wcih_rec.paymentid,
       null, 1, null,
       case when(fp_wcih_rec.taxtotal + fp_wcih_rec.freighttax + fp_wcih_rec.freightgst) <> 0 then 'Y' else 'N' end,
       lv_siccode, lv_attachementcopies, lv_paymenttermsdescription,
       fp_wcih_rec.cybersourcetransactionnumber, null,
       case when fp_wcih_rec.creditcardtype = 'IVC' then 2 else lv_paymenttype end, lv_discountdays,
       lv_paymentdiscount, lv_discountdays2, lv_paymentdiscount2,
       fp_wcih_rec.creditcardtype || ' ' || substr(fp_wcih_rec.cybersourcetransactionnumber,7,6),
       lv_paymenttermsduedate, lv_paymenttermstype, null, null, null);
    --check states id
    if fp_stateid is null
     then
      select st.states_id
      into   lv_statesid
      from   states st
      where  st.code = fp_wcih_rec.billtoaddressstate;
     else
      lv_statesid:=fp_stateid;
    end if;
    --insert into invoiceheader us
    insert into invoiceheaderus
      (invoiceheader_id, countytaxrate, citytaxrate, statestaxrate, taxstates_id, taxcity_id,
       taxcounty_id, timestamp, systemuser_id)
    values
      (lv_invoiceheaderid, null, null, null, lv_statesid, null, fp_countyid, sysdate, gv_systemuserid);
    write_log('End pack_bm.webcatinvoice_invoiceheader', fp_debugmode,5);
    return lv_invoiceheaderid;
  exception
    when others then
      begin
        gv_returnstatus := 1;
        write_log(lv_errormsg, 'Y', 3);
        write_log(sqlerrm, 'Y', 3);
        write_log('During creating invoiceheader in pack_bm.webcatinvoice_invoiceheader!', fp_debugmode,5);
        write_log('End pack_bm.webcatinvoice_invoiceheader', fp_debugmode,5);
        raise;
      end;
  end webcatinvoice_invoiceheader;

  procedure webcatinvoice_linevarious(fp_invoicelinecode   in invoiceline.code%type,
                                      fp_linenumber        in invoiceline.linenumber%type,
                                      fp_invoicelinetypeid in invoicelinetype.invoicelinetype_id%type,
                                      fp_amount            in invoiceline.amount%type,
                                      fp_invoiceheaderid   in invoiceheader.invoiceheader_id%type,
                                      fp_debugmode         in varchar2,
                                      fp_languageid        in languages.language_id%type,
                                      fp_countryid         in country.country_id%type,
                                      fp_statecode         in varchar2,
                                      fp_freighttax        in webcatinvoiceheaderimp.freighttax%type default 0) is
    lv_invoicelineid   invoiceline.invoiceline_id%type;
    lv_specialchargeid specialcharge.specialcharge_id%type;
    lv_description     invoiceline.description%type;
    lv_taxgroupcode    taxgroup.code%type;
    lv_errormsg        abslog.message%type;
    lv_invoicelinecode invoiceline.code%type;
  begin
    write_log('Begin pack_bm.webcatinvoice_linevarious ' || fp_invoicelinecode, fp_debugmode,5);
    --process per invoice line code
    lv_invoicelinecode := fp_invoicelinecode;
    case
      when fp_invoicelinecode = 'BMFREI' then
        begin
          lv_specialchargeid := gv_bmfreight_id;
          --get taxgroup code
          if fp_freighttax <> 0 then
            begin
              select t.code
              into   lv_taxgroupcode
              from   specialchargetax st, taxgroup t
              where  st.specialcharge_id = lv_specialchargeid
              and    st.country_id = fp_countryid
              and    t.taxgroup_id = st.taxgroup_id;
            exception
              when no_data_found then
                lv_taxgroupcode := null;
            end;
          else
            lv_taxgroupcode := null;
          end if;
        end;
      when fp_invoicelinecode = 'BMDISC' then
        begin
          lv_specialchargeid := gv_bmdiscount_id;
          lv_taxgroupcode    := null;
        end;
      when fp_invoicelinecode = 'TAX' then
        begin
          lv_invoicelinecode := fp_statecode;
          lv_specialchargeid := null;
          lv_taxgroupcode    := null;
          lv_description     := 'TAX';
        end;
      else
        begin
          lv_specialchargeid := null;
          lv_taxgroupcode    := null;
          lv_description     := fp_invoicelinecode;
        end;
    end case;
    begin
      if lv_specialchargeid is not null then
        --get lv_specialcharge_desc
        lv_errormsg := 'Error getting special charge description for special charge id ' ||
                       to_char(lv_specialchargeid);
        select spd.description
        into   lv_description
        from   specialcharge_desc spd
        where  spd.specialcharge_id = lv_specialchargeid
        and    spd.language_id = fp_languageid;
      end if;
    exception
      when no_data_found then
        lv_description := fp_invoicelinecode;
    end;
    --create invoice freight line
    lv_errormsg := 'Error during insert invoiceline for invoiceline code / number ' ||
                   fp_invoicelinecode || ' / ' || fp_linenumber;
    insert into invoiceline
      (invoiceline_id, invoiceheader_id, linenumber, remark, invoicelinetype_id, code, description,
       adjustedamount, adjustedprice, adjustmentbilledqty, extend, amount, discountpercentage, price,
       billedqty, adjustmentreason_id, taxtype, taxgroupcode, subjecttominimum,
       turnovergroup_id, generated, systemuser_id, timestamp, invoicelinesubtype, lossweekstogo,
       credit)
    values
      (seq_invoiceline.nextval, fp_invoiceheaderid, fp_linenumber, null, fp_invoicelinetypeid,
       lv_invoicelinecode, lv_description, 0, 0, 0, 'Y', fp_amount, 0, 0, 1, null, 1,
       lv_taxgroupcode, 'N', null, 'Y', gv_systemuserid, sysdate, 0, 0, 'N')
    returning invoiceline_id into lv_invoicelineid;
    --invoice line various
    lv_errormsg := 'Error during insert invoicelinevarious for invoiceline code / number ' ||
                   lv_invoicelinecode || ' / ' || fp_linenumber;
    insert into invoicelinevarious
      (invoiceline_id, transactiontype, transactiondate, percentage, overamount, timestamp,
       systemuser_id)
    values
      (lv_invoicelineid, null, null, 0, 0, sysdate, gv_systemuserid);
    --
    write_log('End pack_bm.webcatinvoice_linvarious ' || fp_invoicelinecode, fp_debugmode,5);
  exception
    when others then
      begin
        gv_returnstatus := 1;
        write_log(lv_errormsg, 'Y', 3);
        write_log(sqlerrm, 'Y', 3);
        write_log('During creating invoiceline(various) in pack_bm.webcatinvoice_linevarious!', fp_debugmode,5);
        write_log('End webcatinvoice_linevarious ' || fp_invoicelinecode, fp_debugmode,5);
        raise;
      end;
  end webcatinvoice_linevarious;

  procedure webcatinvoice_lineproduct(fp_invoiceheaderid in invoiceheader.invoiceheader_id%type,
                                      fp_payloadid       in webcatinvoiceheaderimp.payloadid%type,
                                      fp_paymentid       in webcatinvoiceheaderimp.paymentid%type,
                                      fp_linenumber      in invoiceline.linenumber%type,
                                      fp_typeline        in varchar2,
                                      fp_invoicelinecode in invoiceline.code%type,
                                      fp_productcode     in product.code%type,
                                      fp_taxableyn       in varchar2,
                                      fp_sizecode        in sizedefinition.code%type,
                                      fp_amount          in invoiceline.amount%type,
                                      fp_price           in invoiceline.price%type,
                                      fp_quantity        in invoicelineproduct.deliveredqty%type,
                                      fp_remark          in invoiceline.remark%type,
                                      fp_debugmode       in varchar2,
                                      fp_languageid      in languages.language_id%type,
                                      fp_countryid       in country.country_id%type) is
    lv_invoicelineid    invoiceline.invoiceline_id%type;
    lv_productid        product.product_id%type;
    lv_description      invoiceline.description%type;
    lv_taxgroupcode     taxgroup.code%type;
    lv_sizedefinitionid sizedefinition.sizedefinition_id%type;
    lv_errormsg         abslog.message%type;
  begin
    write_log('Begin pack_bm.webcatinvoice_lineproduct ' || fp_productcode, fp_debugmode,5);
    --get product
    lv_errormsg := 'Product ' || fp_productcode || ' not found!';
    select p.product_id into lv_productid from product p where p.code = upper(fp_productcode);
    --get product desc
    lv_errormsg := 'Product description ' || fp_productcode || ' not found!';
    select pd.description
    into   lv_description
    from   product_desc pd
    where  pd.product_id = lv_productid
    and    pd.language_id = fp_languageid;
    --get taxgroup code
    if fp_taxableyn = 'Y' then
      begin
        lv_errormsg := 'Taxgroup for product ' || fp_productcode || ' not found!';
        select max(tx.code)
        into   lv_taxgroupcode
        from   producttax pt, taxgroup tx
        where  pt.product_id = lv_productid
        and    pt.country_id = fp_countryid
        and    pt.taxgroup_id = tx.taxgroup_id;
      end;
    else
      lv_taxgroupcode := null;
    end if;
    --get size
    lv_errormsg := 'Size ' || fp_sizecode || ' for product ' || fp_productcode || ' not found!';
    select sd.sizedefinition_id
    into   lv_sizedefinitionid
    from   sizedefinition sd
    where  sd.code = upper(fp_sizecode);
    --insert into invoiceline
    insert into invoiceline
      (invoiceline_id, invoiceheader_id, linenumber, remark, invoicelinetype_id, code, description,
       adjustedamount, adjustedprice, adjustmentbilledqty, extend, amount, discountpercentage, price,
       billedqty, adjustmentreason_id, taxtype, taxgroupcode, subjecttominimum,
       turnovergroup_id, generated, systemuser_id, timestamp, invoicelinesubtype, lossweekstogo,
       credit)
    values
      (seq_invoiceline.nextval, fp_invoiceheaderid, fp_linenumber, fp_remark, 5, fp_invoicelinecode,
       lv_description, 0, 0, 0, 'Y', fp_amount, 0, fp_price, fp_quantity, null, 1,
       lv_taxgroupcode, 'N', null, 'Y', gv_systemuserid, sysdate, 0, 0, 'N')
    returning invoiceline_id into lv_invoicelineid;
    --insert into invoiceline product
    insert into invoicelineproduct
      (invoiceline_id, product_link_id, sizedefinition_link_id, finishingmethod_id,
       weighingcategory_link_id, weareremployment_link_id, productshortdescription, wearername,
       wearerlocker, wearerbank, weareradminnr, wearernumber, sizecode, finishingmethoddescription,
       finishingmethodcode, sizedescription, invoiceqtycolumn, inventoryqty, deliveredqty,
       productgroupdescription, productgroupcode, abusedquantity, soilquantity, soilcountmethod,
       billingmethod, timestamp, systemuser_id, delayedevenexchange, replacementprice,
       relatedproduct, deliveryschemecode, soil1, soil2, soilaverage, minimumquantity,
       minimumpercentage, qtyoverunderuse, adjustmentdeliveredqty, auxiliarystatus, pricefactor)
    values
      (lv_invoicelineid, lv_productid, lv_sizedefinitionid, null, null, null, null, null, null,
       null, null, null, fp_sizecode, null, null, fp_sizecode, 0, 0, fp_quantity, null, null, null,
       null, 0, 4, sysdate, gv_systemuserid, 0, null, 0, null, null, null, null, null, null, null, 0,
       0, 1);
    --set flag to processed
    case
      when fp_typeline = 'WCIP' then
        webcatinvoice_wcip_update_flag(fp_payloadid, fp_paymentid, fp_linenumber, 'Y');
      when fp_typeline = 'WCID' then
        webcatinvoice_wcid_update_flag(fp_payloadid, fp_paymentid, fp_linenumber, 'Y');
    end case;
  --
    write_log('End pack_bm.webcatinvoice_lineproduct', fp_debugmode,5);
  exception
    when no_data_found then
      begin
        gv_returnstatus := 1;
        write_log(lv_errormsg, 'Y', 3);
        webcatinvoice_wcip_update_flag(fp_payloadid, fp_paymentid, fp_linenumber, 'E');
        write_log('During creating invoiceline(product) for product ' || fp_productcode ||
                  ' in pack_bm.webcatinvoice_lineproduct!', fp_debugmode,5);
        write_log('End pack_bm.webcatinvoice_lineproduct', fp_debugmode,5);
        raise;
      end;
    when others then
      begin
        gv_returnstatus := 1;
        write_log(lv_errormsg, 'Y', 3);
        write_log(sqlerrm, 'Y', 3);
        webcatinvoice_wcip_update_flag(fp_payloadid, fp_paymentid, fp_linenumber, 'E');
        write_log('During creating invoiceline(product) for product ' || fp_productcode ||
                  ' in pack_bm.webcatinvoice_lineproduct!', fp_debugmode,5);
        write_log('End pack_bm.webcatinvoice_lineproduct', fp_debugmode,5);
        raise;
      end;
  end webcatinvoice_lineproduct;

  procedure webcatinvoice_contactperson(fp_customerid          customer.customer_id%type,
                                        fp_externalreferenceid contactperson.externalreferenceid%type,
                                        fp_contactpersonemail  contactperson.email%type,
                                        fp_contactpersonname   contactperson.name%type) is
    lv_contactpersonid     contactperson.contactperson_id%type;
    lv_contactpersonnumber contactperson.contactpersonnumber%type;
    lv_contactperoncustID  contactperson.customer_id%type;
    lv_errormsg            abslog.message%type;
  begin
    begin
      --get contact person
      lv_errormsg := 'Error reading contact person id for customer id ' ||
                     fp_customerid || ' externalreference id ' || fp_externalreferenceid;
-- read contact person by exteneralrefID, should normally be only one.
-- prevent theoretical error by selecing Min(concactperson_id)
      select cp.contactperson_id, cp.customer_id, cp.contactpersonnumber
        into lv_contactpersonid,
             lv_contactperoncustID,
             lv_contactpersonnumber
        from contactperson cp
       where cp.contactperson_id =
             (select min(c.contactperson_id)
                from contactperson c
               where c.externalreferenceid = fp_externalreferenceid);
-- When contact person moved to other customer, get new contact person#
      if lv_contactperoncustID <> fp_customerid then
       begin
          select nvl(max(cp.contactpersonnumber), 0) + 1
          into   lv_contactpersonnumber
          from   contactperson cp
          where  cp.customer_id = fp_customerid;
       end;
      end if;
      --update contact person
      lv_errormsg := 'Error updating contact person id for customer id ' ||
                     fp_customerid || ' externalreference id ' || fp_externalreferenceid;
      update contactperson cp
      set    cp.email = fp_contactpersonemail,
             cp.name = fp_contactpersonname,
             cp.customer_id = fp_customerid,
             cp.contactpersonnumber = lv_contactpersonnumber
      where  cp.contactperson_id = lv_contactpersonid;
    exception
      when no_data_found then
        begin
          --get max contactperson number
          lv_errormsg := 'Error creating contact person id for customer id ' ||
                         fp_customerid || ' externalreference id ' || fp_externalreferenceid;
          select nvl(max(cp.contactpersonnumber), 0) + 1
          into   lv_contactpersonnumber
          from   contactperson cp
          where  cp.customer_id = fp_customerid;
          --create contact person
          insert into contactperson
            (customer_id, contactperson_id, contactpersonnumber, contactpersonfunction_id, name,
             phone, mobilephone, email, invoicecontactperson, fax, systemuser_id, timestamp,
             supplier_id, externalreferenceid)
          values
            (fp_customerid, seq_contactperson.nextval, lv_contactpersonnumber,
             gv_contactpersonfunctionid, fp_contactpersonname, null, null, fp_contactpersonemail,
             'N', null, gv_systemuserid, sysdate, null, fp_externalreferenceid);
        end;
    end;
  exception
    when others then
      begin
        gv_returnstatus := 1;
        write_log(lv_errormsg, 'Y', 3);
        write_log(sqlerrm, 'Y', 3);
        write_log('During webcatinvoice contactperson insert/update ', 'Y', 3);
        raise;
      end;
  end webcatinvoice_contactperson;

  procedure webcatinvoice_process(fp_debugmode in varchar2 default 'N') is
    lv_errormsg           abslog.message%type;
    lv_deltocustomerid    customer.customer_id%type;
    lv_billtocustomerid   customer.customer_id%type;
    lv_billtocustomernr   customer.customernumber%type;
    lv_languageid         languages.language_id%type;
    lv_countryid          country.country_id%type;
    lv_plantid            plant.plant_id%type;
    lv_productcode        product.code%type;
    lv_stateid            states.states_id%type;
    lv_statecode          states.code%type;
    lv_currencyid         currency.currency_id%type;
    --lv_daynumber          number;
    lv_routeid            route.route_id%type;
    lv_routecontrolid     routecontrol.routecontrol_id%type;
    lv_invoiceheaderid    invoiceheader.invoiceheader_id%type;
    lv_remark             invoiceline.remark%type;
    lv_realcollectiontype invoiceheader.realcollectiontype%type;
    lv_settlementstatus   routecontrol.settlementstatus%type;
    lv_counter            number;
    lv_PST_Total          number;
    lv_GST_Total          number;
    lv_countyid          citycounty.citycounty_id%type;
    lv_county_tax_auth    citycounty.taxauthoritycode%type;
  begin
    write_log('Begin pack_bm.webcatinvoice_process', fp_debugmode,5);
    --get daynumber
    --lv_daynumber := get_day_number(sysdate);
    --process the records
    lv_errormsg := 'Start loop webcatinvoiceheaderimp ';
    for lv_wcih_rec in (select * from webcatinvoiceheaderimp wcih where wcih.processedflag in ('N','E')) loop
      begin
        --get and check if customer exists
        lv_errormsg := 'Customer number ' || lv_wcih_rec.customernumber ||
                       ' does not exist!';
        select deltoc.customer_id, deltoc.debtor_id, billtoc.customernumber, deltoc.states_id, bu.plant_id
        into   lv_deltocustomerid, lv_billtocustomerid, lv_billtocustomernr, lv_stateid, lv_plantid
        from   customer deltoc, customer billtoc, businessunit bu
        where  deltoc.customernumber = lv_wcih_rec.customernumber
        and    deltoc.defaultbusinessunit_id = bu.businessunit_id
        and    billtoc.customer_id=deltoc.debtor_id;
        --get currency
        lv_errormsg := 'Currency ' || lv_wcih_rec.currency || ' does not exists!';
        select cur.currency_id
        into   lv_currencyid
        from   currency cur
        where  cur.code = lv_wcih_rec.currency;
        --state exists
        if lv_wcih_rec.taxtotal + lv_wcih_rec.freighttax + lv_wcih_rec.freightgst <> 0
         then
          begin
            if lv_stateid is null
              then
                lv_errormsg := 'No state found!';
                select st.states_id, st.code
                into   lv_stateid, lv_statecode
                from   states st
                where  st.code = lv_wcih_rec.billtoaddressstate;
              else
                select st.code
                into   lv_statecode
                from   states st
                where  st.states_id=lv_stateid;
            end if;
          end;
        end if;
        lv_countyid := null;
        lv_county_tax_auth := null;
        if lv_wcih_rec.currency='CAD' then
         begin
          -- Calculate Tax Canadian tax
          lv_PST_Total := webcatinvoice_get_pst_total(lv_wcih_rec.payloadid, lv_wcih_rec.paymentid);
          lv_GST_Total := lv_wcih_rec.taxtotal - lv_PST_Total;
          lv_PST_Total := lv_PST_Total + lv_wcih_rec.freighttax;
          lv_GST_Total := lv_GST_Total + lv_wcih_rec.freightgst;
          -- dummy county for GST exist in case GST total <> 0 and currency is = CAD
          if lv_GST_Total <> 0 and lv_stateid is not null
           then
            begin
              begin
                lv_errormsg := 'No dummy county for GST defined for province ' || lv_statecode;
                select c.citycounty_id, c.taxauthoritycode
                  into lv_countyid, lv_county_tax_auth
                  from citycounty c
                 where c.citycounty_id =
                       (select min(cc.citycounty_id)
                          from citycounty cc
                         where cc.states_id = lv_stateid
                           and cc.type=2 -- county
                           and cc.taxauthoritycode is not null);
              exception
                when no_data_found then  -- probably HST and rounding difference so put all under PST/HST
                  begin
                    lv_PST_Total := lv_PST_Total + lv_GST_Total;
                    lv_GST_Total := 0;
                  end;
              end;
            end;
          end if;
         end;
        end if; -- if currency = CAD
        --check if routecontrol exists if not create one
        begin
          lv_errormsg := 'routecontrol check/creation ';
          lv_counter  := 0;
          while lv_counter between 0 and 10 loop
             --check if route 1000 exists if not create one
             -->TD 11985
         begin
          lv_errormsg := 'route check/creation ';
          select r.route_id
          into   lv_routeid
          from   route r
          where  r.drivingday_id = getabsdaynumber(trunc(sysdate) + lv_counter)
          and    r.routenumber = 1000
          and    r.plant_id = lv_plantid;
        exception
          when no_data_found then
            begin
              lv_routeid := webcatinvoice_create_route(getabsdaynumber(trunc(sysdate) + lv_counter), lv_plantid);
            end;
        end;

        --<TD 11985
        --route check/creation
            begin
              select rc.routecontrol_id, rc.settlementstatus
              into   lv_routecontrolid, lv_settlementstatus
              from   routecontrol rc
              where  rc.route_id = lv_routeid
              and    rc.plant_id = lv_plantid
              and    rc.drivingdate = trunc(sysdate) + lv_counter;
              if lv_settlementstatus <> 3 then
                exit;
              end if;
              lv_counter := lv_counter + 1;
            end;
          end loop;
        exception
          when no_data_found then
            begin
              lv_routecontrolid := webcatinvoice_routecontrol(lv_routeid, lv_plantid,
                                                              trunc(sysdate) + lv_counter);
            end;
        end;
        --create invoiceheader
        lv_errormsg        := 'Creating invoiceheader ';
        lv_invoiceheaderid := webcatinvoice_invoiceheader(lv_wcih_rec, lv_billtocustomerid,
                                                          lv_billtocustomernr, lv_deltocustomerid,
                                                          lv_currencyid, lv_stateid, lv_countyid, lv_routeid,
                                                          lv_routecontrolid, fp_debugmode,
                                                          lv_languageid, lv_countryid,
                                                          lv_realcollectiontype);
        --update route control status
        lv_errormsg := 'update route control status ';
        case
          when lv_realcollectiontype = 1 then
            begin
              update routecontrol rc
              set    rc.totalcodprebilled = rc.totalcodprebilled + lv_wcih_rec.invoicetotal,
                     rc.totalcodpaythisamnt = rc.totalcodpaythisamnt + lv_wcih_rec.invoicetotal,
                     rc.totalcashcollected = rc.totalcashcollected + lv_wcih_rec.payamount,
/* HVH 02/10/2008 */
                     rc.packingstatus=4, -- completed
                     rc.invoicesgenerated=3 -- completed
/* End change HVH */
              where  rc.routecontrol_id = lv_routecontrolid;
            end;
          else
            begin
              update routecontrol rc
              set    rc.totalchargepaythisamnt = rc.totalchargepaythisamnt + lv_wcih_rec.invoicetotal,
                     rc.totalchargeprebilled = rc.totalchargeprebilled + lv_wcih_rec.invoicetotal,
/* HVH 02/10/2008 */
--                   rc.totalchargecollections = rc.totalchargecollections + lv_wcih_rec.payamount
                     rc.packingstatus=4, -- completed
                     rc.invoicesgenerated=3 -- completed
/* End change HVH */
              where  rc.routecontrol_id = lv_routecontrolid;
            end;
        end case;
      --create freigh(shipping) invoiceline
        if (lv_wcih_rec.freighttotal + lv_wcih_rec.freightdiscount) <> 0 then
          begin
            lv_errormsg := 'Creating invoiceline freight ';
            webcatinvoice_linevarious('BMFREI', 900, 16,
                                      (lv_wcih_rec.freighttotal + lv_wcih_rec.freightdiscount),
                                      lv_invoiceheaderid, fp_debugmode, lv_languageid, lv_countryid,
                                      lv_statecode, (lv_wcih_rec.freighttax+lv_wcih_rec.freightgst));
          end;
        end if;
        --invoice discount line
        if lv_wcih_rec.invoicediscount <> 0 then
          begin
            lv_errormsg := 'Creating discount invoiceline ';
            webcatinvoice_linevarious('BMDISC', 901, 16, lv_wcih_rec.invoicediscount,
                                      lv_invoiceheaderid, fp_debugmode, lv_languageid, lv_countryid, lv_statecode);
          end;
        end if;
        --invoice tax line
        if lv_wcih_rec.currency='CAD' then
         begin
            if lv_PST_Total <> 0 then
              begin
                lv_errormsg := 'Creating tax invoiceline PST/HST ';
                webcatinvoice_linevarious('TAX', 950, 18, lv_PST_Total,
                                          lv_invoiceheaderid, fp_debugmode, lv_languageid, lv_countryid, lv_statecode);
              end;
            end if; --
            if lv_GST_Total <> 0 then
                 begin
                  lv_errormsg := 'Creating tax invoiceline GST ';
                  webcatinvoice_linevarious('TAX', 951, 18, lv_GST_Total,
                                            lv_invoiceheaderid, fp_debugmode, lv_languageid, lv_countryid, lv_county_tax_auth);
                 end;
            end if;
          end;
         else  -- for USD
          begin
            if (lv_wcih_rec.taxtotal + lv_wcih_rec.freighttax) <> 0 then
              begin
                lv_errormsg := 'Creating tax invoiceline ';
                webcatinvoice_linevarious('TAX', 950, 18,
                                          (lv_wcih_rec.taxtotal + lv_wcih_rec.freighttax),
                                          lv_invoiceheaderid, fp_debugmode, lv_languageid, lv_countryid, lv_statecode);
              end;
            end if;
          end;
        end if;
        --loop product line
        lv_errormsg := 'While importing product lines ';
        for lv_wcip_rec in (select *
                            from   webcatinvoiceproductimp wcip
                            where  wcip.payloadid = lv_wcih_rec.payloadid
                            and    wcip.paymentid = lv_wcih_rec.paymentid) loop
          begin
            webcatinvoice_lineproduct(lv_invoiceheaderid, lv_wcip_rec.payloadid,
                                      lv_wcip_rec.paymentid, lv_wcip_rec.linenumber, 'WCIP',
                                      substr(lv_wcip_rec.itemid, 1, 12), lv_wcip_rec.productcode,
                                      lv_wcip_rec.taxableyn, lv_wcip_rec.sizecode,
                                      lv_wcip_rec.amount, lv_wcip_rec.price, lv_wcip_rec.quantity,
                                      null, fp_debugmode, lv_languageid, lv_countryid);
          end;
        end loop; --product
        --loop decoration records
        lv_errormsg := 'While importing decoration lines ';
        for lv_wcid_rec in (select *
                            from   webcatinvoicedecorationimp wcid
                            where  wcid.payloadid = lv_wcih_rec.payloadid
                            and    wcid.paymentid = lv_wcih_rec.paymentid) loop
          begin
            case
              when upper(lv_wcid_rec.decorationtype) = 'STANDARD' then
                lv_productcode := 'C0EMB';
              when upper(lv_wcid_rec.decorationtype) = 'SCREEN' then
                lv_productcode := 'C0SLKP';
              when upper(lv_wcid_rec.decorationtype) = 'LOGO' then
                lv_productcode := 'C0EMBR';
              when upper(lv_wcid_rec.decorationtype) = 'EMBLEM' then
                begin
                  if upper(lv_wcid_rec.emblemtype) = 'NAME' then
                    lv_productcode := 'C0EMBNA';
                  else
                    lv_productcode := 'C0EMBCO';
                  end if;
                end;
              else
-- HVH 6-mar-2009 todo 8597 other decoration types will have as product code the decorationtype
--               lv_productcode := null; ---will give an error
                 lv_productcode := upper(lv_wcid_rec.decorationtype);
-- End Change
            end case;
-- HVH 6-mar-2009 todo 8597 other decoration types will have as product code the decorationtype
--          if lv_wcid_rec.decorationtype in ('SCREEN', 'LOGO') then
            if lv_wcid_rec.decorationtype in ('SCREEN', 'LOGO') or
              lv_productcode = upper(lv_wcid_rec.decorationtype) then
-- End Change
              lv_remark := 'Logo : ' || lv_wcid_rec.logocode;
            else
              lv_remark := webcatinvoice_remark(lv_wcid_rec.payloadid, lv_wcid_rec.paymentid,
                                                lv_wcid_rec.linenumber, lv_languageid);
            end if;
            webcatinvoice_lineproduct(lv_invoiceheaderid, lv_wcid_rec.payloadid,
                                      lv_wcid_rec.paymentid, lv_wcid_rec.linenumber, 'WCID',
                                      lv_productcode, lv_productcode, lv_wcid_rec.taxableyn, '-',
                                      lv_wcid_rec.amount, lv_wcid_rec.price, lv_wcid_rec.quantity,
                                      lv_remark, fp_debugmode, lv_languageid, lv_countryid);
          end;
        end loop; --decoration
        --insert/update contactperson
        webcatinvoice_contactperson(lv_deltocustomerid, lv_wcih_rec.contactpersonid,
                                    lv_wcih_rec.contactpersonemail, lv_wcih_rec.contactpersonname);
        --flag wcih as processed
        webcatinvoice_wcih_update_flag(lv_wcih_rec.payloadid, lv_wcih_rec.paymentid, 'Y');
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            gv_returnstatus := 1;
            write_log(lv_errormsg || ' For payloadID ' || lv_wcih_rec.payloadid || ' payID ' ||
                      lv_wcih_rec.paymentid, 'Y', 3);
            webcatinvoice_wcih_update_flag(lv_wcih_rec.payloadid, lv_wcih_rec.paymentid, 'E');
          end;
        when others then
          begin
            rollback;
            gv_returnstatus := 1;
            write_log(sqlerrm, 'Y', 3);
            write_log('For payloadID ' || lv_wcih_rec.payloadid || ' payID ' ||
                      lv_wcih_rec.paymentid, 'Y', 3);
            write_log('During pack_bm.webcatinvoice_process wcih loop.', 'Y', 3);
            webcatinvoice_wcih_update_flag(lv_wcih_rec.payloadid, lv_wcih_rec.paymentid, 'E');
          end;
      end;
    end loop;
    commit;
    write_log('End pack_bm.webcatinvoice_process', fp_debugmode,5);
  exception
    when others then
      begin
        rollback;
        gv_returnstatus := 2;
        write_log(sqlerrm, 'Y', 3);
        write_log('End pack_bm.webcatinvoice_process',fp_debugmode,5);
        raise;
      end;
  end webcatinvoice_process;

  function imp_wc_invoices(fp_custxml in clob, fp_debugmode in varchar2 default 'N') return number is
    le_nodata2process exception;
  begin
    gv_returnstatus := 0;
    gv_pack_bm_type := 'Import Web Catalog Invoices';
    write_log('Begin Import Web Catalog Invoices');
    webcatinvoice_read_clob(fp_custxml, fp_debugmode);
    webcatinvoice_checks(fp_debugmode);
    webcatinvoice_process(fp_debugmode);
    write_log('End Import Web Catalog Invoices');
    return gv_returnstatus;
  exception
    when le_nodata2process then
      begin
        write_log(' No data to process..', fp_debugmode);
        write_log('End Import Web Catalog Invoices');
        gv_returnstatus := 2;
        return gv_returnstatus;
      end;
    when others then
      begin
        write_log('End Import Web Catalog Invoices');
        gv_returnstatus := 2;
        return gv_returnstatus;
      end;
  end imp_wc_invoices;

begin
  -- Initialization
  select s.systemuser_id into gv_systemuserid from systemuser s where s.username = 'SYSADM';
exception
  when no_data_found then
    begin
      select min(s.systemuser_id) into gv_systemuserid from systemuser s;
    end;
end pack_bm;
/
create or replace package pack_bm6 as
  function getcurrentfactors(fp_plpc_id in number) return bm6_type;
  function recalculatefixedbillingqty(fp_plpc_id in number, fp_sourcecaller in number,fp_user_id in number) return varchar2;
  function recalculatecircinv(fp_plpc_id in number, fp_sourcecaller in number, fp_user_id in number) return varchar2;
  function recalculatestddeliveryqty(fp_plpc_id in number, fp_sourcecaller in number, fp_user_id in number ) return varchar2;
  procedure scheduledprocess(fp_servername in out varchar2);
  procedure creaDeliveryVariation(fp_plpc_id in number, fp_user_id in number, fp_creaOrStoreWeeklyUsg in varchar2);
end pack_bm6;
/
create or replace package body pack_bm6 as
  gv_customer_id     productlistpercustomer.customer_id%type := -1;
  gv_defalutbusinessunit_id customer.defaultbusinessunit_id%type := -1;
  gv_product_id      productlistpercustomer.product_id%type := -1;
  gv_prodfimmeth_id  productlistpercustomer.finishingmethod_id%type := -1;
  gv_prodszdef_id    productlistpercustomer.sizedefinition_id%type := -1;
  gv_productgroup_id product.productgroup_id%type := -1;
  gv_plant_id        plantprodsettingsbm6.plant_id%type := -1;
  gv_daysperweek     productgroupbm6deldays.deliveriesperweek%type := -1;
  gv_distrpoint      distributionpoint.distributionpoint_id%type := -1;
  gv_location        productlistpercustomer.location%type;
  gv_dateactive      productlistpercustomer.dateactive%type;
  gv_dateinactive    productlistpercustomer.dateinactive%type;
  gv_countContractProd number :=0;
  gv_errorMessage varchar2(20):=  'PACK_BM6 error ';
  gv_standarddeliveryline_id standarddeliveryline.standarddeliveryline_id%type := -1;
  gv_deliveryscheme_id standarddeliveryline.deliveryscheme_id%type := -1 ;


  type array_qtymax is varray(3) of number;
  gv_array_qtymax array_qtymax:=array_qtymax(0,0,0);

  type array_messages is varray(5) of varchar2(50);
  gv_arraymessages array_messages := array_messages('Computed billing quantity is ',
                                                 'Computed circulating inventory is ',
                                                 'Computed standard delivery quantity is ',
                                                 ' greater than max ',
                                                 '. Max value will be used.');


  type array_tbl_name is varray(5) of varchar2(35);
  gv_arrtblbm6name array_tbl_name := array_tbl_name('PLPCBM6',
                                                 'PLANTPRODSETTINGSBM6',
                                                 'PLANTPGSETTINGSBM6',
                                                 'PRODUCTBM6',
                                                 'PRODUCTGROUPBM6');

  gv_arrtblbm6deldaysname array_tbl_name := array_tbl_name('PLPCBM6DELDAYS',
                                                        'PLANTPRODSETTINGSBM6DELDAYS',
                                                        'PLANTPGSETTINGSBM6DELDAYS',
                                                        'PRODUCTBM6DELDAYS',
                                                        'PRODUCTGROUPBM6DELDAYS');

  type bm6 is record(
    weeklyusage                  number,
    oneoffpricemultiplier        number,
    inventorymaintperc           number,
    changedoneoffpricemultiplier varchar2(1),
    changedinventorymaintperc    varchar2(1),
    variabledeliveryquantity     varchar2(1));
  type gv_bm6_rec is table of bm6 index by pls_integer;

  type bm6deldays is record(
    circinventorymultiplier1day        number,
    circinventorymultiplier            number,
    loadpercentperday                  number,
    changedcircinventorymultiplier1day varchar2(1),
    changedcircinvmultiplier           varchar2(1),
    changedloadpercperday              varchar2(1),
    deliveriesperweek                  number);
  type gv_bm6deldays_rec is table of bm6deldays index by pls_integer;

  gv_bm6_strQuery_fields varchar2(170) := 'select null, ONEOFFPRICEMULTIPLIER, INVENTORYMAINTPERC, CHANGEDONEOFFPRICEMULTIPLIER, CHANGEDINVENTORYMAINTPERC, null as VARIABLEDELIVERYQUANTITY ';

  type gv_bm6_strQuery_typ is varray(5) of varchar2(250);
  gv_bm6_arr_strQuery gv_bm6_strQuery_typ := gv_bm6_strQuery_typ('select WEEKLYUSAGE, ONEOFFPRICEMULTIPLIER,INVENTORYMAINTPERC, ' ||
                          ' null as CHANGEDONEOFFPRICEMULTIPLIER, null as CHANGEDINVENTORYMAINTPERC, VARIABLEDELIVERYQUANTITY ' ||
                          ' from ' || gv_arrtblbm6name(1) || ' where productlistpercustomer_id = :1 ', --plpcbm6
                           gv_bm6_strQuery_fields || ' from ' || gv_arrtblbm6name(2) || ' where Product_Id = :1 and Plant_Id = :2 ', --plantprodsettingsbm6
                           gv_bm6_strQuery_fields || ' from ' || gv_arrtblbm6name(3) || ' where Productgroup_Id = :1 and Plant_Id = :2 ', --plantpgsettingsbm6
                           gv_bm6_strQuery_fields || ' from ' || gv_arrtblbm6name(4) || ' where Product_Id = :1 ', --productbm6
                           gv_bm6_strQuery_fields || ' from ' || gv_arrtblbm6name(5) || ' where Productgroup_Id = :1 ');   --productgroupbm6

    gv_bm6DelDays_strQueryFirst varchar2(170) :=  'select case when DELIVERIESPERWEEK = 1 then    CIRCINVENTORYMULTIPLIER else  0  end CIRCINVENTORYMULTIPLIER1DAY,  CIRCINVENTORYMULTIPLIER,  LOADPERCENTPERDAY ';
    gv_bm6DelDays_strQuerySecond varchar2(200) := ' , case when DELIVERIESPERWEEK = 1 then CHANGEDCIRCINVMULTIPLIER else null end CHANGEDCIRCINVENTORYMULTIPLIER1DAY, CHANGEDCIRCINVMULTIPLIER, CHANGEDLOADPERCPERDAY, DELIVERIESPERWEEK ';

    type gv_bm6DelDay_strQuery_typ is varray(5) of varchar2(700);
    gv_bm6DelDay_arr_strQuery gv_bm6DelDay_strQuery_typ := gv_bm6DelDay_strQuery_typ( gv_bm6DelDays_strQueryFirst || ', null, null, null, DELIVERIESPERWEEK ' ||
                          ' from ' || gv_arrtblbm6deldaysname(1) || ' where productlistpercustomer_id = :1 and Deliveriesperweek in  (1, :2) ', --plpcbm6deldays
          gv_bm6DelDays_strQueryFirst || gv_bm6DelDays_strQuerySecond || ' from ' || gv_arrtblbm6deldaysname(2) ||  ' aa inner join  plantprodsettingsbm6 bb on aa.PLANTPRODSETTINGSBM6_ID=bb.PLANTPRODSETTINGSBM6_ID ' ||
                          ' where bb.Product_Id = :1 and  bb.Plant_Id = :2 and aa.Deliveriesperweek in  (1,:3) ', --plantprodsettingsbm6deldays
          gv_bm6DelDays_strQueryFirst || gv_bm6DelDays_strQuerySecond || ' from ' || gv_arrtblbm6deldaysname(3) || ' aa inner join  PLANTPGSETTINGSBM6 bb on aa.PLANTPGSETTINGSBM6_ID=bb.PLANTPGSETTINGSBM6_ID ' ||
                         ' where  bb.Productgroup_Id = :1 and  bb.Plant_Id = :2 and aa.Deliveriesperweek in  (1,:3) ', --plantpgsettingsbm6deldays
          gv_bm6DelDays_strQueryFirst || gv_bm6DelDays_strQuerySecond || ' from ' || gv_arrtblbm6deldaysname(4) || ' where  Product_Id = :1  and Deliveriesperweek in  (1,:2) ', --productbm6deldays
          gv_bm6DelDays_strQueryFirst || gv_bm6DelDays_strQuerySecond || ' from ' || gv_arrtblbm6deldaysname(5) || ' where Productgroup_Id = :1  and Deliveriesperweek in  (1,:2) ' );   --productgroupbm6deldays


 procedure write_log(fpsource varchar2, fpserr_msg varchar2) is
  begin
    /* writes conversion logs into database.
    priority
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info  */
    abslogwrite.abslog_write(5, 'PACK_BM6.' || fpsource, null, 5, fpserr_msg);
  end write_log;

  -- private function utilsgetcustprodplant data
  procedure utilsgetcustprodplant(fp_plpc_id number) is
  begin
    select plpc.customer_id,  plpc.product_id, plpc.finishingmethod_id,
           plpc.sizedefinition_id,  plpc.location, plpc.dateinactive, plpc.dateactive, pg.productgroup_id, bu.plant_id,c.defaultbusinessunit_id
      into gv_customer_id,   gv_product_id, gv_prodfimmeth_id, gv_prodszdef_id, gv_location,
           gv_dateinactive, gv_dateactive, gv_productgroup_id, gv_plant_id,gv_defalutbusinessunit_id
      from productlistpercustomer plpc, product p, productgroup  pg,
           businessunit  bu, customer  c
     where plpc.productlistpercustomer_id = fp_plpc_id
       and p.product_id = plpc.product_id
       and p.productgroup_id = pg.productgroup_id
       and c.customer_id = plpc.customer_id
       and bu.businessunit_id = c.defaultbusinessunit_id;
  exception
    when others then
      write_log('utilsGetCustProdPlant',  'fp_plpc_id=' || fp_plpc_id || ' ' ||  substr(sqlerrm, 1, 1000));
  raise;
  end utilsgetcustprodplant;

  -- private function utilsgetcustprodplant data
  procedure utilsgetdistribpoint is
  begin
      select dp.distributionpoint_id
        into gv_distrpoint
        from department d, distributionpoint dp
       where d.customer_id = gv_customer_id
         and d.department_id = dp.department_id;
  exception
    when others then
      write_log('utilsGetDistribPoint',substr(sqlerrm, 1, 1000));
      raise;
  end utilsgetdistribpoint;

   procedure utilgetsdlanddeliveryScheme is
   begin
       select sdl.standarddeliveryline_id,sdl.deliveryscheme_id
        into gv_standarddeliveryline_id, gv_deliveryscheme_id
        from productlistperdistribpoint prodlstds,
             standarddeliveryline       sdl
       where prodlstds.distributionpoint_id = gv_distrpoint
         and prodlstds.productlistperdistribpoint_id =
             sdl.productlistperdistribpoint_id
         and prodlstds.finishingmethod_id = gv_prodfimmeth_id
         and prodlstds.sizedefinition_id = gv_prodszdef_id
         and prodlstds.product_id = gv_product_id
         and sdl.dateinactive > sysdate;
   exception
     when others then
     null;
  end utilgetsdlanddeliveryScheme;


  -- private function getting util data
  procedure utilGetDaysPerWeek(fp_plpc_id number) is
  begin
      select count(sda.day_id)
        into gv_daysperweek
        from productlistperdistribpoint prodlstds,
             standarddeliveryline       sdl,
             standarddeliveryamount     sda
       where prodlstds.distributionpoint_id = gv_distrpoint
         and prodlstds.productlistperdistribpoint_id =
             sdl.productlistperdistribpoint_id
         and prodlstds.finishingmethod_id = gv_prodfimmeth_id
         and prodlstds.sizedefinition_id = gv_prodszdef_id
         and prodlstds.product_id = gv_product_id
         and sda.standarddeliveryline_id = sdl.standarddeliveryline_id
         and sdl.dateinactive > sysdate;

        if (gv_daysperweek <= 0) then

            utilgetsdlanddeliveryScheme();

             if(gv_standarddeliveryline_id < 0 and gv_deliveryscheme_id < 0 ) then
                    select deliveryscheme_id
                    into gv_deliveryscheme_id
                    from (select cds.deliveryscheme_id
                        from customerdeliveryscheme cds
                        join deliveryscheme ds
                          on cds.deliveryscheme_id = ds.deliveryscheme_id
                        where cds.customer_id = gv_customer_id
                        order by ds.frequency)
                    where rownum = 1;
             end if;

            if(gv_deliveryscheme_id > 0) then
                       select count(cdd.day_id)
                     into gv_daysperweek
                     from customerdeliveryday cdd,customerdeliveryscheme cds
                    where cdd.customer_id = gv_customer_id
                      and cdd.typeofmerchadise = 1
                      and cdd.day_id = cds.day_id
                      and cds.customer_id = cdd.customer_id
                      and cds.deliveryscheme_id = gv_deliveryscheme_id;
            else
                 select count(cdd.day_id)
               into gv_daysperweek
               from customerdeliveryday cdd
              where cdd.customer_id = gv_customer_id
                and cdd.typeofmerchadise = 1;
                  end if;
           end if;
  exception
    when others then
      write_log('utilGetDaysPerWeek','fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      raise;
  end utilGetDaysPerWeek;


  procedure utilgetmaxqty(fp_plpc_id number) is
  begin
    select cpqmg.maxbillingquantity,
           cpqmg.maxcirculatinginventory,
           cpqmg.maxdeliveryquantity
      into gv_array_qtymax(1), gv_array_qtymax(2), gv_array_qtymax(3)
      from productlistpercustomer plpc
      join contractproductplpc cpplpc
        on plpc.productlistpercustomer_id =
           cpplpc.productlistpercustomer_id
      join contractproduct cp
        on cp.contractproduct_id = cpplpc.contractproduct_id
      join contractcustomer cc
        on (cp.contract_id = cc.contract_id
        and plpc.customer_id = cc.customer_link_id)
      join contractcustomerqmgroup ccqmg
        on cc.contractcustomer_id = ccqmg.contractcustomer_id
      join contractproductqmglimit cpqmg
        on cpqmg.contractproduct_id = cpplpc.contractproduct_id
       and cpqmg.contractqmgroup_id = ccqmg.contractqmgroup_id
     where plpc.productlistpercustomer_id = fp_plpc_id;

  exception
    when others then
    gv_countContractProd:=0;
  end utilgetmaxqty;


  function isContractProduct(fp_plpc_id number) return boolean is
  begin
  gv_countContractProd:=0;

   select count(1)
    into gv_countcontractprod
      from contractproductplpc cpplpc
      join contractproduct cp
        on cp.contractproduct_id = cpplpc.contractproduct_id
      join contractproductqmglimit cpqmgl
        on cpqmgl.contractproduct_id = cp.contractproduct_id
     where cpplpc.productlistpercustomer_id = fp_plpc_id;

   return (gv_countContractProd >0);

  exception
     when others then
      write_log('isContractProduct','fp_plpc_id=' || fp_plpc_id || ' ' ||substr(sqlerrm, 1, 1000));
     return  false;
  end isContractProduct;


  -- private function getting data from ..bm6 tables
  function getvaluefrombm6table(fp_tablename varchar2, fp_plpc_id number)
    return gv_bm6_rec is
    lv_arrbm6    gv_bm6_rec;
    begin
      if (fp_tablename = gv_arrtblbm6name(1)) then --plpcbm6
          execute immediate gv_bm6_arr_strQuery(1)  bulk collect  into lv_arrbm6 using  fp_plpc_id;
      end if;

      if (fp_tablename = gv_arrtblbm6name(2)) then --plantprodsettingsbm6
          execute immediate gv_bm6_arr_strQuery(2)  bulk collect  into lv_arrbm6 using  gv_product_id, gv_plant_id;
      end if;

      if (fp_tablename = gv_arrtblbm6name(3)) then --plantprodsettingsbm6
          execute immediate gv_bm6_arr_strQuery(3)  bulk collect  into lv_arrbm6 using  gv_productgroup_id, gv_plant_id;
     end if;

      if (fp_tablename = gv_arrtblbm6name(4)) then --productbm6
          execute immediate gv_bm6_arr_strQuery(4)  bulk collect  into lv_arrbm6 using gv_product_id;
       end if;

       if (fp_tablename = gv_arrtblbm6name(5)) then --productgroupbm6
          execute immediate gv_bm6_arr_strQuery(5)  bulk collect  into lv_arrbm6 using gv_productgroup_id;
      end if;

    return lv_arrbm6;
    exception
      when others then
        write_log('getValueFromBM6Table','fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      raise;
  end getvaluefrombm6table;

  -- private function getting data from ..bm6deldays tables
  function getvaluefrombm6deldaystable(fp_tablename varchar2, fp_plpc_id number)
    return gv_bm6deldays_rec is

    lv_arrbm6deldays gv_bm6deldays_rec;
  begin
    if (fp_tablename = gv_arrtblbm6deldaysname(1)) then  --plpcbm6deldays
      execute immediate gv_bm6DelDay_arr_strQuery(1) bulk collect into lv_arrbm6deldays using fp_plpc_id, gv_daysperweek;
    end if;

   if (fp_tablename = gv_arrtblbm6deldaysname(2)) then --plantprodsettingsbm6deldays
      execute immediate gv_bm6DelDay_arr_strQuery(2) bulk collect into lv_arrbm6deldays using gv_product_id, gv_plant_id,gv_daysperweek ;
    end if;

    if (fp_tablename = gv_arrtblbm6deldaysname(3)) then --plantpgsettingsbm6deldays
      execute immediate gv_bm6DelDay_arr_strQuery(3) bulk collect into lv_arrbm6deldays using gv_productgroup_id, gv_plant_id,gv_daysperweek ;
    end if;

    if (fp_tablename = gv_arrtblbm6deldaysname(4)) then --productbm6deldays
      execute immediate gv_bm6DelDay_arr_strQuery(4) bulk collect into lv_arrbm6deldays using gv_product_id, gv_daysperweek ;
    end if;

    if (fp_tablename = gv_arrtblbm6deldaysname(5)) then --productgroupbm6deldays
      execute immediate gv_bm6DelDay_arr_strQuery(5) bulk collect into lv_arrbm6deldays using gv_productgroup_id, gv_daysperweek ;
    end if;

  return lv_arrbm6deldays;
  exception
    when others then
      write_log('getValueFromBM6DelDaysTable','fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      raise;
  end getvaluefrombm6deldaystable;

  --public function to getcurrentfactors
  function getcurrentfactors(fp_plpc_id number) return bm6_type is
    lv_factors_type  bm6_type;
    lv_arr           gv_bm6_rec ;
    lv_arrbm6deldays gv_bm6deldays_rec;

  begin
    lv_factors_type := bm6_type(null,  null, null,  null, null, null,null, null, null, null, null,  null, null);
    --1. get util data
    utilsgetcustprodplant(fp_plpc_id);
    utilsgetdistribpoint();
    utilGetDaysPerWeek(fp_plpc_id);

    --2 bm6 tables
    for i in 1 .. gv_arrtblbm6name.count loop
      lv_arr := getvaluefrombm6table(gv_arrtblbm6name(i), fp_plpc_id);
      if lv_arr.count >= 1 then
        if(lv_factors_type.weeklyusage is  null) then
            lv_factors_type.weeklyusage := lv_arr(1).weeklyusage;
        end if;

         if(lv_factors_type.variabledeliveryquantity is  null) then
            lv_factors_type.variabledeliveryquantity  := lv_arr(1).variabledeliveryquantity;
        end if;


        if(lv_factors_type.oneoffpricemultiplier is null) then
           lv_factors_type.oneoffpricemultiplier        := lv_arr(1).oneoffpricemultiplier;
           if(lv_factors_type.changedoneoffpricemultiplier is null or lv_factors_type.changedoneoffpricemultiplier='N') then
                lv_factors_type.changedoneoffpricemultiplier := lv_arr(1).changedoneoffpricemultiplier;
           end if;
        end if;

        if(lv_factors_type.inventorymaintperc is null) then
           lv_factors_type.inventorymaintperc           := lv_arr(1).inventorymaintperc;
           if(lv_factors_type.changedinventorymaintperc is null or lv_factors_type.changedinventorymaintperc = 'N') then
             lv_factors_type.changedinventorymaintperc    := lv_arr(1).changedinventorymaintperc;
           end if;
        end if;
      end if;

      if lv_arr.count > 1 then
        write_log('getCurrentFactors','plpc_id=' || fp_plpc_id ||  '  more than 1 record for bm6tablename= ' ||  gv_arrtblbm6name(i));
      end if;
      if (lv_factors_type.oneoffpricemultiplier is not null and
         lv_factors_type.inventorymaintperc is not null) then
        exit;
      end if;
    end loop;

    --3 bm6deldays tables
    for i in 1 .. gv_arrtblbm6deldaysname.count loop
      lv_arrbm6deldays := getvaluefrombm6deldaystable(gv_arrtblbm6deldaysname(i), fp_plpc_id);
      if lv_arrbm6deldays.count >= 1 then
        for j in 1..lv_arrbm6deldays.count loop
           if(lv_arrbm6deldays(j).deliveriesperweek =1 and lv_factors_type.circinventorymultiplier1day is null) then
             lv_factors_type.circinventorymultiplier1day        := lv_arrbm6deldays(j).circinventorymultiplier1day;
              if(lv_factors_type.changedcircinventorymultiplier1day is null or lv_factors_type.changedcircinventorymultiplier1day ='N') then
                 lv_factors_type.changedcircinventorymultiplier1day := lv_arrbm6deldays(j).changedcircinventorymultiplier1day;
              end if;
           end if;

           if (lv_arrbm6deldays(j).deliveriesperweek=gv_daysperweek and lv_factors_type.circinventorymultiplier is null) then
            lv_factors_type.circinventorymultiplier   := lv_arrbm6deldays(j).circinventorymultiplier;
            if(lv_factors_type.changedcircinvmultiplier is null or lv_factors_type.changedcircinvmultiplier='N') then
               lv_factors_type.changedcircinvmultiplier := lv_arrbm6deldays(j).changedcircinvmultiplier;
            end if;
           end if;

          if(lv_arrbm6deldays(j).deliveriesperweek=gv_daysperweek and lv_factors_type.loadpercentperday is null) then
            lv_factors_type.loadpercentperday    := lv_arrbm6deldays(j).loadpercentperday;
             if(lv_factors_type.changedloadpercperday is null or lv_factors_type.changedloadpercperday='N') then
               lv_factors_type.changedloadpercperday  := lv_arrbm6deldays(j).changedloadpercperday;
             end if;
           end if;

           lv_factors_type.deliveriesperweek  := gv_daysperweek;
        end loop;
     end if;

      if (lv_factors_type.circinventorymultiplier1day is not null and
         lv_factors_type.circinventorymultiplier is not null and
         lv_factors_type.loadpercentperday is not null) then
        exit;
      end if;
    end loop;
    return lv_factors_type;
  exception
   when others then
      write_log('GETCURRENTFACTORS','fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
  end getcurrentfactors;

--private proc audit
  procedure addauditlog(fp_rechistory plpcbm6history%rowtype, fp_sourcecaller number) is
  begin
   insert into plpcbm6history
      (plpcbm6history_id,
       productlistpercustomer_id,
       newweeklyusage,
       newcircinventorymultiplier,
       newcircinventory,
       newdeliveriesperweek,
       newloadpercentperday,
       newdeliveryqty,
       newbillingmultiplier,
       newbillingqty,
       newoneoffpricemultiplier,
       newinventorymaintperc,
       changecause,
       dateofchange,
       systemuser_id,
       timestamp,
       remark)
    values
      (seq_plpcbm6history.nextval,
       fp_rechistory.productlistpercustomer_id,
       fp_rechistory.newweeklyusage,
       fp_rechistory.newcircinventorymultiplier,
       fp_rechistory.newcircinventory,
       fp_rechistory.newdeliveriesperweek,
       fp_rechistory.newloadpercentperday,
       fp_rechistory.newdeliveryqty,
       fp_rechistory.newbillingmultiplier,
       fp_rechistory.newbillingqty,
       fp_rechistory.newoneoffpricemultiplier,
       fp_rechistory.newinventorymaintperc,
       fp_sourcecaller,
       sysdate,
       fp_rechistory.systemuser_id,
       sysdate,
       fp_rechistory.remark);

  exception
    when others then
      write_log('auditLog', 'plpc_id=' || fp_rechistory.productlistpercustomer_id || ' ' || substr(sqlerrm, 1, 1000));
  end addauditlog;

--private func distrPoint
function createprodstperdistrpoint(fp_plpc_id in number, fp_nfixedrentqty in number, fp_user_id in number) return number is
   lv_prodistperdistrpoint_id productlistperdistribpoint.productlistperdistribpoint_id%type := -1;
   lv_standarddelivery_id  standarddelivery.standarddelivery_id%type := -1;
   lv_standarddeliveryline_id standarddeliveryline.standarddeliveryline_id%type := -1;
   lv_dateActiveForSDL date;

   lv_maxseq          number := 1;
   begin
          begin
             select nvl(productlistperdistribpoint_id, -1)
               into lv_prodistperdistrpoint_id
               from productlistperdistribpoint
              where distributionpoint_id = gv_distrpoint
                and product_id = gv_product_id
                and sizedefinition_id = gv_prodszdef_id
                and finishingmethod_id = gv_prodfimmeth_id;
           exception
             when no_data_found then
               begin
                 select nvl(max(countsequence), 0)
                   into lv_maxseq
                   from productlistperdistribpoint
                  where distributionpoint_id = gv_distrpoint;

                 select seq_productlistperdistribpoint.nextval
                   into lv_prodistperdistrpoint_id
                   from dual;

                 insert into productlistperdistribpoint
                   (productlistperdistribpoint_id,
                    distributionpoint_id,
                    product_id,
                    sizedefinition_id,
                    finishingmethod_id,
                    countsequence,
                    systemuser_id,
                    timestamp)
                 values
                   (lv_prodistperdistrpoint_id,
                    gv_distrpoint,
                    gv_product_id,
                    gv_prodszdef_id,
                    gv_prodfimmeth_id,
                    (lv_maxseq + 1),
                    fp_user_id,
                    sysdate);
               end;
           end;

           select standarddelivery_id into lv_standarddelivery_id
           from standarddelivery
           where distributionpoint_id = gv_distrpoint
           and rownum=1;

           if lv_standarddelivery_id < 0 then
                      select seq_standarddelivery.nextval
                        into lv_standarddelivery_id
                        from dual;

                            insert into standarddelivery
                              (standarddelivery_id,
                               distributionpoint_id,
                               sequencenumber,
                               deliversterile,
                               cleanreturn,
                               transportarticle_id,
                               generatezerolines,
                               numberoftransportarticles,
                               correctoverdeliveries,
                               correctshortages,
                               weighingcategory_id,
                               combinedtransportationnr,
                               systemuser_id,
                               timestamp)
                            values
                              (lv_standarddelivery_id,
                               gv_distrpoint,
                               1,
                               'N',
                               (select value from systemsetting where name = 'DEFAULTCLEANRETURN' and plant_id = gv_plant_id),
                               (select transportarticle_id from transportarticle where defaulttransportarticle = 'Y' and rownum=1 ) ,
                               'Y',
                               1,
                               'Y',
                               'Y',
                               null,
                               0,
                               fp_user_id,
                               sysdate);
           end if;


           select seq_standarddeliveryline.nextval
              into lv_standarddeliveryline_id
              from dual;

           select deliveryscheme_id
             into gv_deliveryscheme_id
             from (select cds.deliveryscheme_id
                     from customerdeliveryscheme cds
                     join deliveryscheme ds
                       on cds.deliveryscheme_id = ds.deliveryscheme_id
                    where cds.customer_id = gv_customer_id
                    order by ds.frequency)
            where rownum = 1;

           if(trunc(gv_dateactive) > trunc(sysdate)) then
              lv_dateActiveForSDL := gv_dateactive;
           else
              lv_dateActiveForSDL := sysdate;
           end if;

           insert into standarddeliveryline
              (standarddeliveryline_id,
               standarddelivery_id,
               productlistperdistribpoint_id,
               location,
               fixedrentquantity,
               dateactive,
               dateinactive,
               deliveryscheme_id,
               productlistpercustomer_id,
               systemuser_id,
               timestamp)
          values
              (lv_standarddeliveryline_id,
               lv_standarddelivery_id,
               lv_prodistperdistrpoint_id,
               gv_location,
               fp_nfixedrentqty,
               trunc(lv_dateActiveForSDL),
               gv_dateinactive,
               gv_deliveryscheme_id,
               fp_plpc_id,
               fp_user_id,
               sysdate);

    return lv_standarddeliveryline_id;

exception
     when others then
     write_log('createProdstPerDistrPoint', 'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
end  createprodstperdistrpoint;


function getActiveSDL(fp_plpc_id in number, fp_user_id in number)
  return number is
   lv_nodata boolean := FALSE;
   lv_step number := 0;
   lv_standarddeliveryline_id standarddeliveryline.standarddeliveryline_id%type := -1;
   begin
       delete from standarddeliveryline
              where productlistpercustomer_id = fp_plpc_id
                 and trunc(dateactive) > trunc(sysdate);

       update standarddeliveryline
         set dateinactive =  trunc(sysdate-1),
          systemuser_id = fp_user_id,
          timestamp     = sysdate
          where productlistpercustomer_id = fp_plpc_id
          and trunc(dateactive) < trunc(gv_dateactive);

       while ((lv_nodata=FALSE) and lv_standarddeliveryline_id < 0 and lv_step <= 5)
       loop
            begin
               lv_step :=lv_step +1;
               select sdl.standarddeliveryline_id
                into lv_standarddeliveryline_id
                from standarddeliveryline sdl
               where sdl.productlistpercustomer_id = fp_plpc_id
                 and trunc(sdl.dateinactive) >= trunc(sysdate);
            exception
                when no_data_found then
                     lv_nodata := TRUE;
                     null;
                when too_many_rows then
                   lv_standarddeliveryline_id := -1;

                   update standarddeliveryline
                         set dateinactive  = trunc(sysdate-1),
                             systemuser_id = fp_user_id,
                             timestamp     = sysdate
                       where productlistpercustomer_id = fp_plpc_id
                         and trunc(dateinactive) >= trunc(sysdate);
              end;
         end loop;
     return lv_standarddeliveryline_id;
end getActiveSDL;

--private func billingQty
  function setfixedbillingqty(fp_plpc_id in number, fp_sourcecaller in number,fp_inds in bm6_type, fp_user_id in number) return varchar2 is
    lv_standarddeliveryline_id standarddeliveryline.standarddeliveryline_id%type := -1;
    lv_rechistory plpcbm6history%rowtype;
    l_fixedrentqty number:=-1;
    lv_messageRet varchar2(100):='';
  begin

    l_fixedrentqty :=ceil(fp_inds.weeklyusage *  fp_inds.circinventorymultiplier1day);
    lv_standarddeliveryline_id := getActiveSDL(fp_plpc_id, fp_user_id);

    if isContractProduct(fp_plpc_id) then
      utilGetMaxQty(fp_plpc_id);
    end if;

    if(gv_countContractProd > 0 and gv_array_qtymax(1) > 0 and l_fixedrentqty > gv_array_qtymax(1)) then
     lv_messageRet := gv_arraymessages(1) || l_fixedrentqty || gv_arraymessages(4)|| gv_array_qtymax(1)  || gv_arraymessages(5);
     l_fixedrentqty := gv_array_qtymax(1);
    end if;

    if (lv_standarddeliveryline_id > 0) then
      update standarddeliveryline sdl
         set sdl.fixedrentquantity = l_fixedrentqty,
         sdl.dateinactive = to_date('31/12/2099', 'DD/MM/YYYY'),
         sdl.systemuser_id = fp_user_id,
         sdl.timestamp = sysdate
       where sdl.standarddeliveryline_id = lv_standarddeliveryline_id;
    else
       lv_standarddeliveryline_id := createprodstperdistrpoint(fp_plpc_id, l_fixedrentqty, fp_user_id);
    end if;

    lv_rechistory.newbillingqty := l_fixedrentqty;
    lv_rechistory.productlistpercustomer_id := fp_plpc_id;
    lv_rechistory.newweeklyusage:=fp_inds.weeklyusage;
    lv_rechistory.newbillingmultiplier:=fp_inds.circinventorymultiplier1day;
    lv_rechistory.newdeliveriesperweek := fp_inds.deliveriesperweek;
    lv_rechistory.systemuser_id:=fp_user_id;
    lv_rechistory.newoneoffpricemultiplier :=fp_inds.oneoffpricemultiplier;
    lv_rechistory.newinventorymaintperc := fp_inds.inventorymaintperc;
    if(lv_messageRet is not null and length(lv_messageRet) >0) then
         lv_rechistory.remark := lv_messageRet;
    end if;

    addauditlog(lv_rechistory, fp_sourcecaller);

return lv_messageRet;
  exception
      when others then
      write_log('RECALCFIXEDBILLINGQUNATITY', 'fp_plpc_id=' || fp_plpc_id || ' '  || ' sdl=' || lv_standarddeliveryline_id || ' ' || substr(sqlerrm, 1, 1000));
  end setfixedbillingqty;

  --public function billingQty
  function recalculatefixedbillingqty(fp_plpc_id in number, fp_sourcecaller in number,fp_user_id in number) return varchar2 is
    lv_inds bm6_type;
    lv_messageRet varchar2(100):='';
  begin
    --1. get util data
   lv_inds := bm6_type(null, null,null,  null, null, null, null,  null,null,null,  null,null,null);
   select getcurrentfactors(fp_plpc_id) into lv_inds from dual;

   if (lv_inds.weeklyusage is null) then
       write_log('RECALCFIXEDBILLINGQUNATITY', 'fp_plpc_id=' || fp_plpc_id || ' '  ||  'weeklyUsage is null for fp_plpc_id=' || fp_plpc_id );
       return gv_errorMessage || ' RECALCFIXEDBILLINGQUNATITY';
   end if;

   lv_messageRet:=setfixedbillingqty(fp_plpc_id, fp_sourcecaller,lv_inds, fp_user_id);
   commit;

    return lv_messageRet;
  exception
    when others then
      write_log('RECALCFIXEDBILLINGQUNATITY',  'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      rollback;
  end recalculatefixedbillingqty;


  --private function circInv
  function setcircinv(fp_plpc_id in number, fp_sourcecaller in number,fp_inds in bm6_type, fp_user_id in number ) return varchar2 is
    lv_qualitygrade_id qualitygrade.qualitygrade_id%type :=-1;
    lv_productistperdistrpointid productlistperdistribpoint.productlistperdistribpoint_id%type := -1;
    lv_rechistory plpcbm6history%rowtype;
    lv_rentalqtyadjustment_id rentalqtyadjustment.rentalqtyadjustment_id%type := -1;

    lv_newcircinv number := -1;
    lv_currentcircinv number := 0;
    lv_newrqaqty number := 0;
    lv_flagAudit varchar2(1):='N';
    lv_messageRet varchar2(100):='';
    lv_maxDate date := to_date('31/12/2099', 'DD/MM/YYYY');


  begin
      lv_newcircinv := ceil(fp_inds.weeklyusage * fp_inds.circinventorymultiplier);

      select qualitygrade_id
        into lv_qualitygrade_id
        from (select q.qualitygrade_id
                from qualitygrade q
               where q.newgarment = 'Y'
               order by q.priority asc)
       where rownum = 1;

      select pldp.productlistperdistribpoint_id
        into lv_productistperdistrpointid
        from productlistperdistribpoint pldp
       where pldp.distributionpoint_id = gv_distrpoint
         and pldp.product_id = gv_product_id
         and pldp.sizedefinition_id = gv_prodszdef_id
         and pldp.finishingmethod_id = gv_prodfimmeth_id;

      if(lv_productistperdistrpointid <0) then
            write_log('setCircInv',  'fp_plpc_id=' || fp_plpc_id || ' ' ||
                               ' no record in PRODUCTLISTPERDISTRIBPOINT for DISTRIBUTIONPOINT_ID = ' || gv_distrpoint ||
                               ' and product_id= ' || gv_product_id);
            return gv_errorMessage || ' RECALCFIXEDBILLINGQUNATITY';
      end if;

       select nvl(sum(quantity), 0)
         into lv_currentcircinv
         from rentalqtyadjustment rqa
        where rqa.productlistperdistribpoint_id =
              lv_productistperdistrpointid
          and rqa.adjustmentdate < trunc(sysdate);

       if isContractProduct(fp_plpc_id) then
          utilGetMaxQty(fp_plpc_id);
       end if;

      if(gv_countContractProd > 0 and gv_array_qtymax(2) > 0 and lv_newcircinv > gv_array_qtymax(2)) then
         lv_messageRet := gv_arraymessages(2) || lv_newcircinv || gv_arraymessages(4)|| gv_array_qtymax(2)  || gv_arraymessages(5);
         lv_newcircinv := gv_array_qtymax(2);
      end if;

       lv_newrqaqty := lv_newcircinv - lv_currentcircinv;

       begin
            select rqa.rentalqtyadjustment_id
              into lv_rentalqtyadjustment_id
              from rentalqtyadjustment rqa
             where rqa.productlistperdistribpoint_id =   lv_productistperdistrpointid
               and rqa.adjustmentdate = trunc(sysdate)
               and rqa.reasoncode_id =
                   (select rc.reasoncode_id
                      from reasoncode rc
                     where rc.code in
                           (select value
                              from systemsetting
                             where name = 'REASONCODEFORBM6CIRCINV'))
               and rqa.cancellationtimestamp is null
               and rqa.deliveryvariations_id is null
               and rownum = 1;
       exception
           when no_data_found then
           null;
       end;

       if(lv_rentalqtyadjustment_id >0) then
           update rentalqtyadjustment rqa
              set rqa.quantity      = case when lv_newcircinv=0 then (-1 * lv_currentcircinv)
                                      else lv_newrqaqty
                                      end ,
                  rqa.timestamp     = sysdate,
                  rqa.systemuser_id = fp_user_id
            where rqa.rentalqtyadjustment_id = lv_rentalqtyadjustment_id;

           lv_flagAudit :='Y';
       else
           if(lv_newrqaqty <> 0) then
             insert into rentalqtyadjustment
              (rentalqtyadjustment_id,productlistperdistribpoint_id, remark,
               quantity,
               adjustmentdate,
               reasoncode_id,
               deliveryvariations_id, quitmatstobeflagged, quitmatsflagged,sampleitem,
               desiredmountingdate,actualmountingdate,
               mountingorder_id,  startrentdate, endrentdate,
               salesitem,salesprice,  qualitygrade_id,quantityfirstdelivery,  tobemounted,   startservice,
               expirationdate,autobillonexpirationdate, autoprocessed,salesemployee_id, cancellationtimestamp,
               origin, salesemployee2_id,  recalcstatus,timestamp,systemuser_id)
             values
              (seq_rentalqtyadjustment.nextval,  lv_productistperdistrpointid ,  null,
              lv_newrqaqty,
              trunc(sysdate),  (select rc.reasoncode_id
                from reasoncode rc
               where rc.code in
                     (select value
                        from systemsetting
                       where name = 'REASONCODEFORBM6CIRCINV')),
              null,0, 0,'N',
              lv_maxDate,lv_maxDate,
              null,  lv_maxDate, lv_maxDate,
              'N', null,lv_qualitygrade_id, 0, 'N', 'N',
              lv_maxDate, 'N',  'N', null,  null,
              0, null,  0, sysdate, fp_user_id);

               lv_flagAudit :='Y';
            end if;
          end if;

       if(lv_flagAudit = 'Y') then
           lv_rechistory.productlistpercustomer_id := fp_plpc_id;
           lv_rechistory.newweeklyusage := fp_inds.weeklyusage;
           lv_rechistory.newdeliveriesperweek := fp_inds.deliveriesperweek;
           lv_rechistory.newcircinventorymultiplier := fp_inds.circinventorymultiplier;
           lv_rechistory.newcircinventory := lv_newcircinv;
           lv_rechistory.systemuser_id := fp_user_id;
           lv_rechistory.newoneoffpricemultiplier :=fp_inds.oneoffpricemultiplier;
           lv_rechistory.newinventorymaintperc := fp_inds.inventorymaintperc;

           if(lv_messageRet is not null and length(lv_messageRet) >0) then
             lv_rechistory.remark := lv_messageRet;
           end if;

           addauditlog(lv_rechistory, fp_sourcecaller);
       end if;


   return lv_messageRet;
  exception
     when others then
      write_log('setCircInv',  'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
  end setcircinv;

--public func cirvInv
  function recalculatecircinv(fp_plpc_id in number, fp_sourcecaller in number, fp_user_id in number) return varchar2  is
   lv_inds      bm6_type;
   lv_messageRet varchar2(100) := '';
  begin
        --1. get util data
        lv_inds := bm6_type(null, null,null,  null, null, null, null,  null,null,null,  null,null,null);
        select getcurrentfactors(fp_plpc_id) into lv_inds from dual;

        if (lv_inds.weeklyusage is null) then
          abslogwrite.abslog_write(5,  'PACK_BM6.RECALCULATECIRCINV',null, 5,'weeklyUsage is null for fp_plpc_id=' || fp_plpc_id);
          return gv_errorMessage || ' RECALCULATECIRCINV';
        end if;

        lv_messageRet := setcircinv(fp_plpc_id, fp_sourcecaller ,lv_inds, fp_user_id );
      commit;

  return lv_messageRet;
  exception
    when others then
      write_log('RECALCULATECIRCINV',  'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      rollback;
  end recalculatecircinv;

--private proc delvQty
  function setstddeliveryqty(fp_plpc_id in number, fp_sourcecaller in number,fp_inds in bm6_type, fp_user_id in number) return varchar2 is
    lv_newstddlvqty number := -1;
    lv_deliveryload number :=-1;

    lv_nodays number:=0;
    lv_rechistory plpcbm6history%rowtype;

    lv_messageRet varchar2(100):='';
    lv_newlyCalculatedTotalDlvAmt number :=0;

    type arrtbldays is table of number index by pls_integer;
    gv_arrdays arrtbldays;

    type sda_values is varray(7) of bm6_type_sdavalues;
    lv_arr_sda_val sda_values := sda_values(bm6_type_sdavalues(null,null,null),bm6_type_sdavalues(null,null,null),bm6_type_sdavalues(null,null,null),
    bm6_type_sdavalues(null,null,null),bm6_type_sdavalues(null,null,null),bm6_type_sdavalues(null,null,null),bm6_type_sdavalues(null,null,null));

    lv_oldSDASum number := 0;
    lv_currentDayValue  number := 0;
    lv_poz number:=1;
    lv_totalSdaAmountTobeUpd number := 0;
    lv_newSdaRecalculated number :=0;
  begin

    lv_deliveryload:=fp_inds.loadpercentperday;
    lv_newstddlvqty := fp_inds.weeklyusage * lv_deliveryload/100;

    lv_newlyCalculatedTotalDlvAmt := ceil(lv_newstddlvqty * gv_daysperweek);

    if isContractProduct(fp_plpc_id) then
      utilGetMaxQty(fp_plpc_id);
    end if;

    if(gv_countContractProd > 0 and gv_array_qtymax(3) > 0 and lv_newlyCalculatedTotalDlvAmt > gv_array_qtymax(3)) then
      lv_messageRet := gv_arraymessages(3) || lv_newlyCalculatedTotalDlvAmt || gv_arraymessages(4)|| gv_array_qtymax(3)  || gv_arraymessages(5);
      lv_newstddlvqty := gv_array_qtymax(3) / gv_daysperweek;
    end if;

    lv_rechistory.productlistpercustomer_id := fp_plpc_id;
    lv_rechistory.newweeklyusage := fp_inds.weeklyusage;
    lv_rechistory.newloadpercentperday := lv_deliveryload;

    lv_rechistory.newdeliveryqty := 0;

   begin
      utilgetsdlanddeliveryScheme();
   exception
        when others then
          null;
   end;

   if(gv_standarddeliveryline_id > 0) then
      if(fp_inds.variabledeliveryquantity = 'Y') then
               for crs in (select sda.day_id,sda.amount
                 from standarddeliveryamount sda
                 where sda.standarddeliveryline_id =gv_standarddeliveryline_id order by sda.day_id) loop
                    lv_arr_sda_val(lv_poz).DAY_ID := crs.day_id;
                    lv_arr_sda_val(lv_poz).AMOUNT := crs.amount;
                    lv_arr_sda_val(lv_poz).percentDay := 0;

                    lv_poz := lv_poz+1;
               end loop;

               for i in 1..lv_arr_sda_val.Count loop
                     if(coalesce(lv_arr_sda_val(i).amount,0) > 0) then
                       lv_oldSDASum := lv_oldSDASum + lv_arr_sda_val(i).amount;
                     end if;
               end loop;

               if(lv_oldSDASum >0) then
                  for i in 1..lv_arr_sda_val.Count loop
                    if(lv_arr_sda_val(i).amount is not null) then
                       lv_arr_sda_val(i).percentDay := lv_arr_sda_val(i).amount /lv_oldSDASum;
                    end if;
                  end loop;
               end if;

               if(lv_oldSDASum <= 0) then
                  for i in 1..lv_arr_sda_val.Count loop
                      if(lv_arr_sda_val(i).amount is not null) then
                       lv_arr_sda_val(i).percentDay := 1 / gv_daysperweek;
                      end if;
                  end loop;
               end if;
      end if;

      lv_poz:=1;
      for crs in (select sda.day_id,sda.amount
         from standarddeliveryamount sda
         where sda.standarddeliveryline_id =gv_standarddeliveryline_id order by sda.day_id) loop
              lv_nodays := lv_nodays +1;
              lv_rechistory.newdeliveriesperweek := fp_inds.deliveriesperweek;

                if(gv_countContractProd > 0 and gv_array_qtymax(3) > 0 and lv_nodays = gv_daysperweek) then
                       lv_currentDayValue := gv_array_qtymax(3) - lv_rechistory.newdeliveryqty;
                else
                   if(fp_inds.variabledeliveryquantity = 'Y') then
                           lv_currentDayValue := ceil(round((lv_newstddlvqty * gv_daysperweek) * lv_arr_sda_val(lv_poz).percentDay,3));
                           lv_poz:=lv_poz+1;
                   else
                        lv_currentDayValue  := ceil(lv_newstddlvqty);
                   end if;
                end if;

              update standarddeliveryamount stda
              set  stda.previousamount=stda.amount, stda.amount = lv_currentDayValue
              where stda.day_id= crs.day_id and stda.standarddeliveryline_id=gv_standarddeliveryline_id;

              lv_rechistory.newdeliveryqty := lv_rechistory.newdeliveryqty + lv_currentDayValue;
              lv_rechistory.systemuser_id := fp_user_id;
     end loop;
   else
       gv_standarddeliveryline_id := createprodstperdistrpoint(fp_plpc_id, (fp_inds.weeklyusage * fp_inds.circinventorymultiplier1day),fp_user_id);
   end if;

    if(gv_standarddeliveryline_id >0) then
        if( gv_deliveryscheme_id > 0) then
                   execute immediate ' select distinct cdd.day_id
                   from customerdeliveryday cdd ,customerdeliveryscheme cds
                   where cdd.customer_id = ' || gv_customer_id ||
                   ' and cdd.typeofmerchadise = 1 ' ||
                   ' and cdd.day_id = cds.day_id ' ||
                   ' and cds.customer_id = cdd.customer_id ' ||
                   ' and cds.deliveryscheme_id = '  || gv_deliveryscheme_id ||
                   ' order by day_id ' bulk collect into gv_arrdays;
        else
                  execute immediate ' select distinct day_id
                   from customerdeliveryday cdd
                   where cdd.customer_id= ' || gv_customer_id ||
                   ' and cdd.typeofmerchadise = 1 ' ||
                   ' order by day_id ' bulk collect into gv_arrdays;
        end if;

       while (lv_nodays < gv_daysperweek) loop
         lv_nodays := lv_nodays +1;
         lv_rechistory.newdeliveriesperweek := fp_inds.deliveriesperweek;
            if(gv_countContractProd > 0 and gv_array_qtymax(3) > 0 and lv_nodays = gv_daysperweek) then
                lv_currentDayValue := gv_array_qtymax(3) - lv_rechistory.newdeliveryqty;
            else
                if(fp_inds.variabledeliveryquantity = 'Y') then
                     lv_currentDayValue := ceil(round((lv_newstddlvqty * gv_daysperweek) * lv_arr_sda_val(gv_arrdays(lv_nodays)).percentDay,3));
                else
                     lv_currentDayValue  := ceil(lv_newstddlvqty);
                end if;
            end if;
            insert into standarddeliveryamount(day_id, amount,systemuser_id,timestamp,standarddeliveryline_id, previousamount)
            values (gv_arrdays(lv_nodays), lv_currentDayValue, fp_user_id, sysdate, gv_standarddeliveryline_id, 0);
            lv_rechistory.newdeliveryqty := lv_rechistory.newdeliveryqty + lv_currentDayValue;

          lv_rechistory.systemuser_id:=fp_user_id;
        end loop;
    else
          write_log('RECALCULATEStdDeliveryQty',  'Error: STANDARDDELIVERYLINE_ID not determined for fp_plpc_id= ' ||  fp_plpc_id);
          rollback;
    end if;

  -- recalculate qty: total amount less than weeklyusage
     if(lv_rechistory.newdeliveryqty > fp_inds.weeklyusage and fp_inds.weeklyusage > 0) then

        lv_totalSdaAmountTobeUpd :=  lv_rechistory.newdeliveryqty - fp_inds.weeklyusage;

        for crs in (select sda.day_id,sda.amount
                from standarddeliveryamount sda
                where sda.standarddeliveryline_id =gv_standarddeliveryline_id order by sda.day_id) loop

              lv_newSdaRecalculated := 0;
               if((crs.amount -1) >0 and  (crs.amount -1) > lv_totalSdaAmountTobeUpd)  then
                   lv_newSdaRecalculated := crs.amount - lv_totalSdaAmountTobeUpd;
               elsif((crs.amount -1) > 0 and (crs.amount -1) <= lv_totalSdaAmountTobeUpd) then
                   lv_newSdaRecalculated := crs.amount - lv_totalSdaAmountTobeUpd;
                   if (lv_newSdaRecalculated < 1) then
                     lv_newSdaRecalculated := 1;
                   end if;
               else
                   lv_newSdaRecalculated := 0;
               end if;

              if(lv_newSdaRecalculated > 0 ) then
                lv_totalSdaAmountTobeUpd := lv_totalSdaAmountTobeUpd - (crs.amount - lv_newSdaRecalculated);

                 update standarddeliveryamount stda
                 set  stda.amount = lv_newSdaRecalculated
                 where stda.day_id= crs.day_id and stda.standarddeliveryline_id=gv_standarddeliveryline_id;
              end if;

             if(lv_totalSdaAmountTobeUpd <=0) then
                 exit;
             end if;
        end loop;
     end if;

    --recalculate history qty: total amount
    select sum(sda.amount)
    into lv_rechistory.newdeliveryqty
    from standarddeliveryamount sda
    where sda.standarddeliveryline_id = gv_standarddeliveryline_id;


    lv_rechistory.newdeliveriesperweek := gv_daysperweek;

    lv_rechistory.newoneoffpricemultiplier :=fp_inds.oneoffpricemultiplier;
    lv_rechistory.newinventorymaintperc := fp_inds.inventorymaintperc;

    if(lv_messageRet is not null and length(lv_messageRet) >0) then
         lv_rechistory.remark := lv_messageRet;
    end if;

    addauditlog(lv_rechistory, fp_sourcecaller);

return lv_messageRet;
  exception
    when others then
      write_log('RECALCULATEStdDeliveryQty',  'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      rollback;
  end  setstddeliveryqty;

--public func delvQty
  function recalculatestddeliveryqty(fp_plpc_id in number, fp_sourcecaller in number, fp_user_id in number) return varchar2 is
  lv_inds      bm6_type;
  lv_messageRet varchar2(100) := '';
  begin
    --1. get util data
     lv_inds := bm6_type(null, null,null,  null, null, null, null,  null,null,null,  null,null,null);
     select getcurrentfactors(fp_plpc_id) into lv_inds from dual;

     if (lv_inds.weeklyusage is null) then
       abslogwrite.abslog_write(5,   'PACK_BM6.RECALCULATEStdDeliveryQty',  null,   5, 'WeeklyUsage is null for fp_plpc_id=' || fp_plpc_id);
       return gv_errorMessage || ' RECALCULATEStdDeliveryQty';
     end if;

     lv_messageRet := setstddeliveryqty(fp_plpc_id, fp_sourcecaller, lv_inds, fp_user_id);
     commit;
  return lv_messageRet;
  exception
    when others then
       write_log('RECALCULATEStdDeliveryQty',  'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      rollback;
  end recalculatestddeliveryqty;


--scheluled process
--private proc getListbm6
procedure getplpcidlistbm6tbls(fp_servername in varchar2,fp_user_id in number) is
    type tstrquery is table of varchar2(500) index by binary_integer;
    lv_arrstrquery  tstrquery;
    lv_strmerge varchar2(1000);
    lv_strfrom varchar2(500);
    lv_strfromwhere varchar2(500);
begin
    lv_arrstrquery(1):=' select plpc.productlistpercustomer_id ';
    lv_arrstrquery(2):=' from product p, productlistpercustomer plpc ';
    lv_arrstrquery(3):=' where plpc.product_id=p.product_id and plpc.dateinactive>sysdate and plpc.billingmethod=6 ';
    lv_arrstrquery(4):= ' (CHANGEDONEOFFPRICEMULTIPLIER = ''Y'' or  CHANGEDINVENTORYMAINTPERC = ''Y'') ' ;

     for i in 2 .. gv_arrtblbm6name.count loop
        lv_strfrom := '';
        lv_strfromwhere := '';

        if ( upper(gv_arrtblbm6name(i))=upper('PlantProdSettingsBM6') or upper(gv_arrtblbm6name(i))=upper('ProductBM6') )  then
           lv_strfrom := ', ' || gv_arrtblbm6name(i) || ' pp ';
           lv_strfromwhere :=  ' and pp.product_id=p.product_id ';
        end if;

        if ( upper(gv_arrtblbm6name(i))=upper('ProductGroupBM6') or upper(gv_arrtblbm6name(i))=upper('PlantPGSettingsBM6')  )  then
           lv_strfrom := ', ' ||  gv_arrtblbm6name(i) || ' pg ';
           lv_strfromwhere := ' and pg.productgroup_id=p.productgroup_id ';
        end if;

       lv_strmerge:= ' merge into PLPCBM6RECALCUlATION ELIGIBLETBL  using (' ||
         lv_arrstrquery(1) || lv_arrstrquery(2) || lv_strfrom || lv_arrstrquery(3) || lv_strfromwhere || 'and (' ||  lv_arrstrquery(4) || ') ) INNERQUERY ' ||
        ' on (ELIGIBLETBL.PRODUCTLISTPERCUSTOMER_ID = INNERQUERY.PRODUCTLISTPERCUSTOMER_ID) ' ||
        ' when not matched then ' ||
        '  insert ' ||
        '    (PRODUCTLISTPERCUSTOMER_ID, PROCESSED,SYSTEMUSER_ID, timestamp) ' ||
        '  values ' ||
        '    (INNERQUERY.PRODUCTLISTPERCUSTOMER_ID, ''N'',''' || fp_user_id || ''' , sysdate) ';

        execute immediate lv_strmerge;
     commit;

     end loop;

exception
    when others then
      write_log('getPlpcIdListBM6Tbls ' || fp_servername, substr(sqlerrm, 1, 1000));
      rollback;

end getplpcidlistbm6tbls;

--private proc getListBM6deliveryDays
procedure getplpcidlistbm6tblsdeldays(fp_servername in varchar2, fp_user_id in number) is
begin
   execute immediate ' merge into PLPCBM6RECALCULATION ELIGIBLETBL ' ||
                     ' using ( ' ||
                   ' with plpcForBM6 as (select PLPC.PRODUCTLISTPERCUSTOMER_ID,' ||
                      ' PLPC.CUSTOMER_ID, ' ||
                      ' PLPC.SIZEDEFINITION_ID, ' ||
                      ' PLPC.FINISHINGMETHOD_ID, ' ||
                      ' PLPC.product_id ' ||
                      ' from PRODUCTLISTPERCUSTOMER    PLPC ' ||
                      ' where PLPC.BILLINGMETHOD = 6 ' ||
                      '  and PLPC.DATEINACTIVE > sysdate ), ' ||
                   ' PLPCDELDAYS as '||
                   ' (select PLPC.PRODUCTLISTPERCUSTOMER_ID PLPCID,  '||
                     '      PLPC.CUSTOMER_ID, '||
                     '    P.PRODUCT_ID, '||
                     '  PLPC.SIZEDEFINITION_ID, '||
                     ' PLPC.FINISHINGMETHOD_ID, '||
                     ' DELDAYS.DELIVERIESPERWEEK '||
                     ' from PRODUCT    P,  '||
                     '      plpcForBM6      PLPC,  '||
                     '     PLANTPRODSETTINGSBM6DELDAYS DELDAYS  '||
                    ' inner join PLANTPRODSETTINGSBM6 PP  '||
                    '    on PP.PLANTPRODSETTINGSBM6_ID = DELDAYS.PLANTPRODSETTINGSBM6_ID  '||
                    ' where PLPC.PRODUCT_ID = P.PRODUCT_ID  '||
                    '     and PP.PRODUCT_ID = P.PRODUCT_ID  '||
                    '       and (CHANGEDCIRCINVMULTIPLIER = ''Y'' or CHANGEDLOADPERCPERDAY = ''Y'')  '||
                    '   union  '||
                    ' select PLPC.PRODUCTLISTPERCUSTOMER_ID PLPCID, '||
                    ' PLPC.CUSTOMER_ID, '||
                    ' P.PRODUCT_ID, '||
                    ' PLPC.SIZEDEFINITION_ID, '||
                    '    PLPC.FINISHINGMETHOD_ID, '||
                    '   DELDAYS.DELIVERIESPERWEEK '||
                    '  from PRODUCT                   P, '||
                    '        plpcForBM6    PLPC, '||
                    '        PLANTPGSETTINGSBM6DELDAYS DELDAYS '||
                    '  inner join PLANTPGSETTINGSBM6 PLANTPG '||
                    '     on PLANTPG.PLANTPGSETTINGSBM6_ID = DELDAYS.PLANTPGSETTINGSBM6_ID '||
                    '  where PLPC.PRODUCT_ID = P.PRODUCT_ID '||
                    '        and PLANTPG.PRODUCTGROUP_ID = P.PRODUCTGROUP_ID '||
                    '        and (CHANGEDCIRCINVMULTIPLIER = ''Y'' or CHANGEDLOADPERCPERDAY = ''Y'') '||
                    ' union  '||
                    ' select PLPC.PRODUCTLISTPERCUSTOMER_ID PLPCID, '||
                      '      PLPC.CUSTOMER_ID, '||
                        '    P.PRODUCT_ID, '||
                          '  PLPC.SIZEDEFINITION_ID, '||
                           ' PLPC.FINISHINGMETHOD_ID, '||
                           ' DELDAYS.DELIVERIESPERWEEK  '||
                      ' from PRODUCT P, plpcForBM6 PLPC, PRODUCTBM6DELDAYS DELDAYS '||
                     ' where PLPC.PRODUCT_ID = P.PRODUCT_ID '||
                       '  and DELDAYS.PRODUCT_ID = P.PRODUCT_ID '||
                       ' and (CHANGEDCIRCINVMULTIPLIER = ''Y'' or CHANGEDLOADPERCPERDAY = ''Y'') '||
                  ' union  '||
                  ' select PLPC.PRODUCTLISTPERCUSTOMER_ID PLPCID, '||
                  '        PLPC.CUSTOMER_ID, '||
                  '        P.PRODUCT_ID, '||
                  '        PLPC.SIZEDEFINITION_ID, '||
                  '        PLPC.FINISHINGMETHOD_ID, '||
                  '        DELDAYS.DELIVERIESPERWEEK '||
                  '   from PRODUCT                P, '||
                  '        plpcForBM6 PLPC, '||
                  '        PRODUCTGROUPBM6DELDAYS DELDAYS '||
                  '  where PLPC.PRODUCT_ID = P.PRODUCT_ID '||
                  '     and DELDAYS.PRODUCTGROUP_ID = P.PRODUCTGROUP_ID '||
                  '    and (CHANGEDCIRCINVMULTIPLIER =''Y'' or CHANGEDLOADPERCPERDAY = ''Y'')), '||
                ' DISTRPOINT as '||
                '  (select PLPCDAY.CUSTOMER_ID, '||
                 '         min(DP.DISTRIBUTIONPOINT_ID) DISTRIBUTIONPOINT_ID '||
                  '   from PLPCDELDAYS PLPCDAY, DEPARTMENT D, DISTRIBUTIONPOINT DP '||
                  '  where PLPCDAY.CUSTOMER_ID = D.CUSTOMER_ID '||
                  '    and D.DEPARTMENT_ID = DP.DEPARTMENT_ID '||
                  '  group by PLPCDAY.CUSTOMER_ID), '||
                ' COUNTDAY_SDA as '||
                '  (select PLPCDAY.PLPCID, count(SDA.DAY_ID) DAYNO '||
                '     from PLPCDELDAYS                PLPCDAY, '||
                '          DISTRPOINT                 DISTRPOINT, '||
                '          PRODUCTLISTPERDISTRIBPOINT PRODLSTDS, '||
                '          STANDARDDELIVERYLINE       SDL, '||
                '          STANDARDDELIVERYAMOUNT     SDA '||
                '    where PLPCDAY.CUSTOMER_ID = DISTRPOINT.CUSTOMER_ID '||
                '      and PRODLSTDS.DISTRIBUTIONPOINT_ID = DISTRPOINT.DISTRIBUTIONPOINT_ID '||
                '      and PRODLSTDS.FINISHINGMETHOD_ID = PLPCDAY.FINISHINGMETHOD_ID '||
                '      and PRODLSTDS.SIZEDEFINITION_ID = PLPCDAY.SIZEDEFINITION_ID '||
                '      and PRODLSTDS.PRODUCT_ID = PLPCDAY.PRODUCT_ID '||
                '      and PRODLSTDS.PRODUCTLISTPERDISTRIBPOINT_ID = '||
                '          SDL.PRODUCTLISTPERDISTRIBPOINT_ID '||
                '      and SDA.STANDARDDELIVERYLINE_ID = SDL.STANDARDDELIVERYLINE_ID '||
                 '     and SDL.DATEINACTIVE > sysdate '||
                 '   group by PLPCDAY.PLPCID), '||
               '  COUNTDAY_CUSTDELDAY as '||
               '   (select PLPCDAY.PLPCID, count(CDD.DAY_ID) DAYNO '||
                '     from PLPCDELDAYS PLPCDAY, CUSTOMERDELIVERYDAY CDD '||
                 '   where CDD.CUSTOMER_ID = PLPCDAY.CUSTOMER_ID '||
                 '     and CDD.TYPEOFMERCHADISE = 1 '||
                 '     and not exists (select 1 '||
                 '            from COUNTDAY_SDA CSDA '||
                 '           where CSDA.PLPCID = PLPCDAY.PLPCID) '||
                 '   group by PLPCDAY.PLPCID) '||
                 '  select PLPC.PLPCID ' ||
                 '  from PLPCDELDAYS PLPC ' ||
                 ' where plpc.DELIVERIESPERWEEK=1 ' ||
                 ' union ' ||
               '  select PLPC.PLPCID '||
               '    from PLPCDELDAYS PLPC, '||
               '         (select * from COUNTDAY_SDA union select * from COUNTDAY_CUSTDELDAY) CDAY '||
               '   where PLPC.PLPCID = CDAY.PLPCID '||
               '     and PLPC.DELIVERIESPERWEEK = CDAY.DAYNO and PLPC.DELIVERIESPERWEEK >1 ) INNERQUERY on (ELIGIBLETBL.PRODUCTLISTPERCUSTOMER_ID = INNERQUERY.PLPCID)  '||
                '    when not matched then '||
                '   insert '||
                '     (PRODUCTLISTPERCUSTOMER_ID, PROCESSED, SYSTEMUSER_ID, timestamp) '||
                '   values '||
                '     (INNERQUERY.PLPCID, ''N'',' || fp_user_id || ', sysdate) ';

              commit;
exception
    when others then
      write_log('getPlpcIdListBM6TblsDelDays ' || fp_servername,   substr(sqlerrm, 1, 1000));
      rollback;

end getplpcidlistbm6tblsdeldays;

--private proc recalc factors
procedure recalculate(fp_servername in varchar2, p_systemuserid in number) is
  lv_inds  bm6_type;
  lv_messageRet varchar2(100):='';
   lv_rechistory plpcbm6history%rowtype;
begin
   for record in (select * from plpcbm6recalculation plpcrecalc where plpcrecalc.processed='N')
   loop
         begin
           lv_rechistory.productlistpercustomer_id := null;
           lv_rechistory.newweeklyusage := null;
           lv_rechistory.newoneoffpricemultiplier := null;
          --1. get util data
          lv_inds := bm6_type(null, null,null,  null, null, null, null,  null,null,null,  null,null,null);
          select getcurrentfactors(record.productlistpercustomer_id) into lv_inds from dual;

              if(lv_inds.weeklyusage is not null) then
                   if(lv_inds.changedcircinventorymultiplier1day ='Y') then
                     lv_messageRet := setfixedbillingqty(record.productlistpercustomer_id,4, lv_inds,p_systemuserid);
                   end if;

                   if(lv_inds.changedcircinvmultiplier ='Y') then
                      lv_messageRet:= setcircinv(record.productlistpercustomer_id,4, lv_inds, p_systemuserid);
                   end if;

                  if(lv_inds.changedloadpercperday ='Y') then
                      lv_messageret := setstddeliveryqty(record.productlistpercustomer_id,4, lv_inds,p_systemuserid);
                  end if;

                   if(lv_inds.changedoneoffpricemultiplier ='Y') then
                      lv_rechistory.productlistpercustomer_id := record.productlistpercustomer_id;
                      lv_rechistory.newweeklyusage := lv_inds.weeklyusage;
                      lv_rechistory.newoneoffpricemultiplier := lv_inds.oneoffpricemultiplier;
                      lv_rechistory.systemuser_id := p_systemuserid;
                      addauditlog(lv_rechistory, 4);
                  end if;

              end if;

         exception
             when others then
                   write_log('recalculate' || fp_servername , ' error recalculate for plpcId= ' || record.productlistpercustomer_id ||   substr(sqlerrm, 1, 1000) );
                  rollback;

         end ;

         update plpcbm6recalculation set processed='Y' where  productlistpercustomer_id = record.productlistpercustomer_id;
         commit;
   end loop;

exception
  when others then
    abslogwrite.abslog_write(5,'PACK_BM6.recalculate ' || fp_servername, null,  5, substr(sqlerrm, 1, 1000));
    rollback;
end recalculate;

--private proc checkPrevRun
procedure checkpreviousrun(fp_servername out varchar2,p_systemuser_id in number) is
 lv_tbprocessed number:=1;

    begin
          select count(*) into lv_tbprocessed
          from plpcbm6recalculation tblrecalcids
          where tblrecalcids.processed='N';

          if(lv_tbprocessed >0) then
            recalculate(fp_servername,p_systemuser_id);
          end if;

    exception
       when others then
       write_log('checkPreviousRun' || fp_servername , substr(sqlerrm, 1, 1000) );
    rollback;

end checkpreviousrun;

--private proc clean
procedure cleanflagsandtable(fp_servername in varchar2) is
  lv_processedrecordsno number :=0;
  lv_strquerywhere varchar2(100):=' (CHANGEDONEOFFPRICEMULTIPLIER = ''Y'' or  CHANGEDINVENTORYMAINTPERC = ''Y'') ' ;
  lv_strquerywheredeldays  varchar2(100):= '(Changedcircinvmultiplier = ''Y'' or  Changedloadpercperday = ''Y'') ';

begin
   select count(*) into lv_processedrecordsno
   from plpcbm6recalculation
   where processed='N';

   if(lv_processedrecordsno = 0) then
        for i in 2 .. gv_arrtblbm6name.count loop
           execute immediate 'update ' || gv_arrtblbm6name(i)  ||
           ' set CHANGEDONEOFFPRICEMULTIPLIER=''N''' ||
           ', CHANGEDINVENTORYMAINTPERC=''N''' ||
           '  where ' || lv_strquerywhere;
        end loop;

          for i in 2 .. gv_arrtblbm6deldaysname.count loop
           execute immediate 'update ' || gv_arrtblbm6deldaysname(i)  ||
           ' set Changedcircinvmultiplier=''N''' ||
           ', Changedloadpercperday=''N''' ||
           '  where ' || lv_strquerywheredeldays;
        end loop;
        commit;

       -- execute immediate 'truncate table PLPCBM6Recalculation';
   end if;
exception
  when others then
    write_log('cleanFlagsAndTable' || fp_servername ,  substr(sqlerrm, 1, 1000) );
    rollback;

end cleanflagsandtable;

--public proc scheduledProces
procedure scheduledprocess(fp_servername in out varchar2) is
  lv_unprocessed number :=0;
  lv_systemuserid systemuser.systemuser_id%type;
begin
    select sy.systemuser_id into lv_systemuserid from systemuser sy where sy.username = 'SYSADM';

    if(fp_servername is null) then
       fp_servername :=' ';
    end if;

    checkpreviousrun(fp_servername, lv_systemuserid);

        begin
          select count(*) into lv_unprocessed from plpcbm6recalculation where processed = 'N';
         exception
          when others then
          null;
        end;

       if (lv_unprocessed = 0) then
            execute immediate 'truncate table PLPCBM6Recalculation';

            getplpcidlistbm6tbls(fp_servername, lv_systemuserid);
            getplpcidlistbm6tblsdeldays(fp_servername,lv_systemuserid);

            recalculate(fp_servername, lv_systemuserid);

            cleanflagsandtable(fp_servername);
        else
            write_log('SCHEDULEDRECALCULATION ' || fp_servername ,  'Unprocessed records in PLPCBM6RECALCULATION. No of records processed=N is ' || lv_unprocessed );     end if;
exception
  when others then
    write_log('SCHEDULEDRECALCULATION ' || fp_servername ,  substr(sqlerrm, 1, 1000));
    rollback;

end scheduledprocess;

--public func creaDeliveryVariation
--this function to be called after standarddeliveryamount
  procedure creaDeliveryVariation(fp_plpc_id in number, fp_user_id in number, fp_creaOrStoreWeeklyUsg in varchar2) is
    lv_inds      bm6_type;
    lv_sumSdaAmount number  := 0;
    lv_qtyToBeDeliver number := 0;
    lv_delValNext_id number := -1;
    lv_startDateForDV date;
    lv_existingDvId number := -1;
    lv_oldWeeklyUsg number:=0;
    lv_oldSDA number :=0;
    lv_diffWeeklyUsg number :=0;
    lv_diffSDA number :=0;
  begin

        --1. get util data
        lv_inds := bm6_type(null, null,null,  null, null, null, null,  null,null,null,  null,null,null);
        select getcurrentfactors(fp_plpc_id) into lv_inds from dual;

        if (lv_inds.weeklyusage is null) then
          abslogwrite.abslog_write(5,  'PACK_BM6.creaDeliveryVariation',null, 5,'weeklyUsage is null for fp_plpc_id=' || fp_plpc_id);
          return;
        end if;


        if(fp_creaOrStoreWeeklyUsg = 'createWeeklyUsage') then
          lv_startDateForDV := gv_dateactive;
        else
          lv_startDateForDV := sysdate;
        end if;

        begin
            utilgetsdlanddeliveryScheme();
        exception
            when others then
               null;
        end;

        select sum(sda.amount) into lv_sumSdaAmount
                 from standarddeliveryamount sda
                 where sda.standarddeliveryline_id =gv_standarddeliveryline_id;

       if(fp_creaOrStoreWeeklyUsg = 'createWeeklyUsage') then
            lv_qtyToBeDeliver := lv_inds.weeklyusage - lv_sumSdaAmount;
       else
               begin
                       select newweeklyusage
                       into lv_oldWeeklyUsg
                       from (select rownum crt, newweeklyusage
                                from  (select hist.newweeklyusage
                                         from plpcbm6history hist
                                         where hist.productlistpercustomer_id=fp_plpc_id
                                         and hist.newweeklyusage !=  lv_inds.weeklyusage
                                          order by hist.timestamp desc) )
                       where crt = 1;
                exception
                       when others then
                         null;
                end;

                begin
                       select newdeliveryqty
                       into  lv_oldSDA
                       from (select rownum crt, newdeliveryqty
                                from  (select hist.newdeliveryqty
                                         from plpcbm6history hist
                                         where hist.productlistpercustomer_id=fp_plpc_id
                                          and hist.newdeliveryqty is not null
                                          and hist.newweeklyusage !=  lv_inds.weeklyusage
                                          order by hist.timestamp desc) )
                       where crt = 1;
                exception
                       when others then
                         null;
                end;

               if(lv_oldWeeklyUsg >= 0 AND (lv_inds.weeklyusage >= lv_oldWeeklyUsg)) then
                         lv_diffWeeklyUsg := lv_inds.weeklyusage - lv_oldWeeklyUsg;
                         lv_diffSDA :=lv_sumSdaAmount -  lv_oldSDA;
                         if(lv_diffSDA >= 0 AND (lv_diffWeeklyUsg >= lv_diffSDA)) then
                           lv_qtyToBeDeliver := lv_diffWeeklyUsg - lv_diffSDA;
                         end if;
               end if;
        end if;


        if(lv_qtyToBeDeliver >0 AND lv_sumSdaAmount >0) then

           FOR i IN 0..1 loop
                  lv_existingDvId  := -1;
                  begin
                          select dv.deliveryvariations_id
                                   into lv_existingDvId
                            from deliveryVariations dv
                           where dv.distributionpoint_id = gv_distrpoint
                             and nvl(dv.processed,'N')='N'
                             and dv.product_id = gv_product_id
                             and dv.finishingmethod_id = gv_prodfimmeth_id
                             and dv.sizedefinition_id= gv_prodszdef_id
                                   and trunc(dv.deliverydate) = trunc(lv_startDateForDV + i)
                                   and dv.origin =13;
                   exception
                   when others then
                           null;
                   end;

                   if(lv_existingDvId > 0 ) then
                        update deliveryVariations dv
                        set dv.amount = lv_qtyToBeDeliver
                        where dv.deliveryvariations_id = lv_existingDvId;
                    else
                        select seq_deliveryvariations.nextval
                        into lv_delValNext_id
                        from dual;
                        if(lv_delValNext_id > 0 ) then
                             insert into deliveryvariations (deliveryvariations_id,  product_id,
                                 deliverydate,origin,amount,finishingmethod_id,fixedamount,
                                  distributionpoint_id,packingnote_id,sizedefinition_id,reference,
                                  processed,causenote_id,updaterentqty,adjustmentreason_id,
                                  systemuser_id,timestamp,enddate,soilcountsubtype,
                                  deliveryscheme_id,weborderline_id,stockcountqty,normstocklevel,
                                  stockcountdate,plantdepartment_id,oldplantdepartment_id,reasoncode_id,chargestartdate,soilcountdate,scrutinystatus,
                                  addtoexistingpn,productconversioncpl_id,cleanroombatch_id,
                                  processbusinessunit_id,internalprocessingbu_id,creationsystemuser_id,creationtimestamp)
                              values (lv_delValNext_id,gv_product_id,
                                  trunc(lv_startDateForDV + i),
                                  13,
                                  lv_qtyToBeDeliver,
                                   gv_prodfimmeth_id,
                                  'N',
                                  gv_distrpoint,
                                  null,
                                  gv_prodszdef_id,
                                  null,'N',null,'N',null,fp_user_id ,sysdate,null,0,
                                  null,null,0,0,
                                  null,null,null,null,null,null,11,
                                  'N',null,null,
                                  gv_defalutbusinessunit_id,
                                  gv_defalutbusinessunit_id,
                                  fp_user_id,
                                  sysdate);
                          end if;
                    end if;
             END LOOP;
             commit;
        end if;

  exception
    when others then
       write_log('creaDeliveryVariation',  'fp_plpc_id=' || fp_plpc_id || ' ' || substr(sqlerrm, 1, 1000));
      rollback;
  end creaDeliveryVariation;

end pack_bm6;
/
create or replace package PACK_COMPRESSCWPRICE is

  -- Author  : MONICA
  -- Created : 7/14/2009 4:20:36 PM
  -- Purpose :

  -- Public type declarations

  -- Public constant declarations

  -- Public variable declarations

  -- Public function and procedure declarations
  procedure CompressCustomerCWPrice(testRun            boolean,
                                    compactOnStartDate boolean);

  procedure UndoCompressCustomerCWPrice(compactOnStartDate boolean);

  procedure CompressGeneralCWPrice(testRun            boolean,
                                   compactOnStartDate boolean);

  procedure UndoCompressGeneralCWPrice(compactOnStartDate boolean);

end PACK_COMPRESSCWPRICE;

/
create or replace package body PACK_COMPRESSCWPRICE is

  -- Function and procedure implementations
  PROCEDURE write_log(fp_err_msg   IN VARCHAR2,
                      fp_priority  IN NUMBER DEFAULT 1,
                      fp_procedure IN VARCHAR2 DEFAULT NULL) IS
  fpProc varchar2(50) := '';
  BEGIN
    /* writes logs into database.
    priority
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info  */
    if fp_procedure is not null then
       fpProc := '.' || fp_procedure;
    end if;
    abslogwrite.abslog_write(5,
                             'Pack_CompressCWPrice' || fpProc,
                             NULL,
                             fp_priority,
                             fp_err_msg);
  END write_log;


  function create_table(tableName varchar2) return number is
  table_already_exists exception;
  pragma exception_init(table_already_exists, -00955);
  stmt varchar2(1000);
  ret number := 1;
  begin
    stmt := 'create table ' || tableName ;
    if (tableName like 'CUSTOMERRENTPRICE%') then
      stmt := stmt || '(
                        CUSTOMERRENTPRICE_ID      NUMBER not null,
                        PRODUCTLISTPERCUSTOMER_ID NUMBER not null,
                        TIMESTAMP                 DATE not null,
                        SYSTEMUSER_ID             NUMBER not null,
                        PRICE                     NUMBER(15,6) not null,
                        STARTDATE                 DATE not null,
                        CHANGESPERWEEK            NUMBER not null,
                        TYPEOFRENT                NUMBER(1) not null,
                        INVOICEFREQUENCYNUMBER    NUMBER default 10 not null,
                        LASTINDEX                 NUMBER not null
                      )';
    end if;
    if (tableName like 'GENERALRENTPRICE%') then
      stmt := stmt || '(
                        GENERALRENTPRICE_ID    NUMBER not null,
                        GENERALPRICELIST_ID    NUMBER not null,
                        PRODUCT_ID             NUMBER not null,
                        SIZEDEFINITION_ID      NUMBER not null,
                        FINISHINGMETHOD_ID     NUMBER not null,
                        TIMESTAMP              DATE not null,
                        SYSTEMUSER_ID          NUMBER not null,
                        PRICE                  NUMBER(15,6) not null,
                        STARTDATE              DATE not null,
                        CHANGESPERWEEK         NUMBER not null,
                        TYPEOFRENT             NUMBER(1) not null,
                        INVOICEFREQUENCYNUMBER NUMBER default 10 not null,
                        LASTINDEX              NUMBER not null
                      )';
    end if;
    execute immediate stmt;
    return ret;
  exception
    when table_already_exists then
      execute immediate 'select max(LASTINDEX) + 1 from ' || tableName into ret;
      if (ret is null) then
         ret := 1;
      end if;
      return ret;
  end create_table;

  procedure drop_table(tableName varchar2) is
  lastIndex number;
  begin
    execute immediate 'select max(LASTINDEX) from ' || tableName into lastIndex;
    if (lastIndex is null) then
      execute immediate 'drop table ' || tableName;
    end if;
  end drop_table;

  procedure CompressCustomerCWPrice(testRun            boolean,
                                    compactOnStartDate boolean) is
  cursor c1_offSD is
          select crp2.customerrentprice_id, crp2.productlistpercustomer_id, crp2.price, crp2.startdate from customerrentprice crp2
          where crp2.customerrentprice_id in
            (select min(crp1.customerrentprice_id)
            from
                 (select crp.productlistpercustomer_id, crp.price, min(crp.startdate) startdate
                  from customerrentprice crp
                  where crp.typeofrent = 2
                  group by crp.productlistpercustomer_id, crp.price
                  having count(1)> 1) t, customerrentprice crp1
            where crp1.typeofrent = 2
                and crp1.productlistpercustomer_id = t.productlistpercustomer_id
                and crp1.price = t.price
                and crp1.startdate = t.startdate
                group by crp1.productlistpercustomer_id)
          and not exists (select 1 from customerrentprice crp3
              where crp3.productlistpercustomer_id = crp2.productlistpercustomer_id
              and crp3.price != crp2.price
              and crp3.typeofrent = 2
              and crp3.changesperweek = -1);

  cursor c2_onSD is
          select crp2.customerrentprice_id, crp2.productlistpercustomer_id, crp2.price, crp2.startdate from customerrentprice crp2
          where crp2.customerrentprice_id in
            (select min(crp1.customerrentprice_id)
            from
                 (select crp.productlistpercustomer_id, crp.price, crp.startdate
                  from customerrentprice crp
                  where crp.typeofrent = 2
                  group by crp.productlistpercustomer_id, crp.price, crp.startdate
                  having count(1)> 1) t, customerrentprice crp1
            where crp1.typeofrent = 2
                and crp1.productlistpercustomer_id = t.productlistpercustomer_id
                and crp1.price = t.price
                and crp1.startdate = t.startdate
                group by crp1.productlistpercustomer_id)
          and not exists (select 1 from customerrentprice crp3
              where crp3.productlistpercustomer_id = crp2.productlistpercustomer_id
              and crp3.price != crp2.price
              and crp3.typeofrent = 2
              and crp3.changesperweek = -1);

  cursor toBeDeleted(v_plpc number, v_price customerrentprice.price%type, v_startdate date) is
          select crp.*, c.customernumber, p.code productcode, sd.code sizecode, fm.code fmcode
          from
            customerrentprice crp, productlistpercustomer plpc,
            customer c, product p, sizedefinition sd, finishingmethod fm
          where
            crp.productlistpercustomer_id = plpc.productlistpercustomer_id
            and plpc.customer_id = c.customer_id
            and plpc.product_id = p.product_id
            and plpc.sizedefinition_id = sd.sizedefinition_id
            and plpc.finishingmethod_id = fm.finishingmethod_id
            and crp.productlistpercustomer_id = v_plpc
            and crp.price = v_price
            and crp.startdate >= nvl(v_startdate, to_date('01/01/1900', 'dd/mm/yyyy'))
            and crp.startdate <= nvl(v_startdate, to_date('31/12/9999', 'dd/mm/yyyy'))
            and crp.typeofrent = 2;
  tbExists number := 0;
  tableName varchar2(50);
  refRec toBeDeleted%rowtype;   -- will keep the reference record to copy values from into the new record for price *
  curentIndex number := 0;      -- each run of the procedure will insert into the backup table
                                -- a new lastindex value, so that we can make an consistent
                                -- recover of only the last deleted data
  begin
     if (compactOnStartDate) then
        tableName := 'CUSTOMERRENTPRICE_CPW_DATE';
        for rec in c2_onSD loop
          if (tbExists = 0 and not testRun) then -- create back-up table if doesn't exists/retrieve next lastindex number
              curentIndex := create_table(tableName);
              tbExists := 1;
          end if;

          for toDelRec in toBeDeleted(rec.productlistpercustomer_id, rec.price, rec.startdate) loop
              if (toDelRec.Customerrentprice_Id = rec.customerrentprice_id) then
                 refRec := toDelRec;
              end if;
              -- log the record to be deleted
              write_log('customer number = ' || toDelRec.Customernumber
              || ', product code = ' || toDelRec.Productcode || ', size code = ' || toDelRec.Sizecode
              || ', finishing method code = ' || toDelRec.Fmcode || ', changes per week = ' || toDelRec.Changesperweek
              || ', start date = ' || toDelRec.Startdate || ', price = ' || toDelRec.Price,
              1, 'CRP');
              if (not testRun) then
                 -- insert the record to be deleted into the back-up table
                 execute immediate 'insert into CUSTOMERRENTPRICE_CPW_DATE (select crp.*,' || curentIndex
                        || ' from CUSTOMERRENTPRICE crp
                        where crp.customerrentprice_id = ' || toDelRec.Customerrentprice_Id || ')' ;
                 -- delete record
                 delete from CUSTOMERRENTPRICE crp
                        where crp.customerrentprice_id = toDelRec.Customerrentprice_Id;
              end if;
          end loop; -- end delete loop

          if (not testRun) then
              -- insert new record for price *
              insert into CUSTOMERRENTPRICE(CUSTOMERRENTPRICE_ID,PRODUCTLISTPERCUSTOMER_ID,TIMESTAMP,SYSTEMUSER_ID,PRICE,STARTDATE,CHANGESPERWEEK,TYPEOFRENT,INVOICEFREQUENCYNUMBER,RATIFICATIONSTARTDATE,CREATIONUSER_ID,CREATIONTIMESTAMP,RATIFICATIONUSER_ID,RATIFICATIONTIMESTAMP,CONTRACTCOEFFICIENT,SIZEBILLINGGROUP_ID)
                     values
                     (refRec.Customerrentprice_Id,
                     refRec.Productlistpercustomer_Id,
                     sysdate,
                     refRec.Systemuser_Id,
                     refRec.Price,
                     refRec.Startdate,
                     -1,
                     refRec.Typeofrent,
                     refRec.Invoicefrequencynumber,
                     refRec.Ratificationstartdate,
                     refRec.Creationuser_Id,
                     refRec.Creationtimestamp,
                     refRec.Ratificationuser_Id,
                     refRec.Ratificationtimestamp,
                     refRec.Contractcoefficient,
                     refRec.Sizebillinggroup_Id);
          end if;
        end loop; -- end insert new rec. loop
     else
        tableName := 'CUSTOMERRENTPRICE_CPW_NODATE';
        for rec in c1_offSD loop
          if (tbExists = 0 and not testRun) then -- create back-up table if doesn't exists/retrieve next lastindex number
             curentIndex := create_table(tableName);
             tbExists := 1;
          end if;

          for toDelRec in toBeDeleted(rec.productlistpercustomer_id, rec.price, null) loop
              if (toDelRec.Customerrentprice_Id = rec.customerrentprice_id) then
                 refRec := toDelRec;
              end if;
              -- log the record to be deleted
              write_log('customernumber = ' || toDelRec.Customernumber
              || ', productcode = ' || toDelRec.Productcode || ', sizecode = ' || toDelRec.Sizecode
              || ', finishing method code = ' || toDelRec.Fmcode || ', changes per week = ' || toDelRec.Changesperweek
              || ', start date = ' || toDelRec.Startdate || ', price = ' || toDelRec.Price,
              1, 'CRP');
              if (not testRun) then
                 -- insert the record to be deleted into the back-up table
                 execute immediate 'insert into CUSTOMERRENTPRICE_CPW_NODATE (select crp.*,' || curentIndex
                        || ' from CUSTOMERRENTPRICE crp
                        where crp.customerrentprice_id = ' || toDelRec.Customerrentprice_Id || ')' ;
                 -- delete record
                 delete from CUSTOMERRENTPRICE crp
                        where crp.customerrentprice_id = toDelRec.Customerrentprice_Id;
              end if;
          end loop; -- end delete loop

          if (not testRun) then
              -- insert in CRP new record for price *
              insert into CUSTOMERRENTPRICE(CUSTOMERRENTPRICE_ID,PRODUCTLISTPERCUSTOMER_ID,TIMESTAMP,SYSTEMUSER_ID,PRICE,STARTDATE,CHANGESPERWEEK,TYPEOFRENT,INVOICEFREQUENCYNUMBER,RATIFICATIONSTARTDATE,CREATIONUSER_ID,CREATIONTIMESTAMP,RATIFICATIONUSER_ID,RATIFICATIONTIMESTAMP,CONTRACTCOEFFICIENT,SIZEBILLINGGROUP_ID)
                     values
                     (refRec.Customerrentprice_Id,
                     refRec.Productlistpercustomer_Id,
                     sysdate,
                     refRec.Systemuser_Id,
                     refRec.Price,
                     refRec.Startdate,
                     -1,
                     refRec.Typeofrent,
                     refRec.Invoicefrequencynumber,
                     refRec.Ratificationstartdate,
                     refRec.Creationuser_Id,
                     refRec.Creationtimestamp,
                     refRec.Ratificationuser_Id,
                     refRec.Ratificationtimestamp,
                     refRec.Contractcoefficient,
                     refRec.Sizebillinggroup_Id);
          end if;

        end loop; -- end insert new rec. loop
     end if;
     -- write in sqlscripts table
     if (not testRun) then
       begin
          insert into sqlscript (scriptname, issuccessful, createddate, modifieddate) values ('CompressCustomerCWPrice', 'Y', sysdate, null);
       exception
          when dup_val_on_index then
               update sqlscript ss set ss.modifieddate = sysdate where ss.scriptname like 'CompressCustomerCWPrice';
       end;
     end if;
     commit;
  end CompressCustomerCWPrice;

  procedure UndoCompressCustomerCWPrice(compactOnStartDate boolean) is
  table_not_exists exception;
  pragma exception_init(table_not_exists, -00942);
  tableName varchar2(50);
  lastIndex number := 1;
  begin
    if (compactOnStartDate) then
      tableName := 'CUSTOMERRENTPRICE_CPW_DATE';
    else
      tableName := 'CUSTOMERRENTPRICE_CPW_NODATE';
    end if;

    -- determine the last moved records
    execute immediate 'select max(LASTINDEX) from ' || tableName into lastIndex;
    if (lastIndex is null) then
      execute immediate 'drop table ' || tableName;
    else
      -- delete from CRP last inserted records
      execute immediate 'delete from CUSTOMERRENTPRICE crp
             where crp.changesperweek = -1
             and crp.customerrentprice_id in
             (select cpw.customerrentprice_id from ' || tableName || ' cpw
                     where cpw.lastindex = ' || lastIndex || ')';

      -- restore in CRP last moved records
      execute immediate 'insert into CUSTOMERRENTPRICE
      (select cpw.customerrentprice_id,
             cpw.productlistpercustomer_id,
             sysdate,
             cpw.systemuser_id,
             cpw.price,
             cpw.startdate,
             cpw.changesperweek,
             cpw.typeofrent,
             cpw.invoicefrequencynumber
      from ' || tableName || ' cpw where cpw.lastindex = ' || lastIndex || ')';

      -- delete from back-up table last moved records
      execute immediate 'delete from ' || tableName || ' cpw where cpw.lastindex = ' || lastIndex;


      -- write in sqlscripts table
      begin
        insert into sqlscript (scriptname, issuccessful, createddate, modifieddate) values ('UndoCompressCustomerCWPrice', 'Y', sysdate, null);
      exception
        when dup_val_on_index then
             update sqlscript ss set ss.modifieddate = sysdate where ss.scriptname like 'UndoCompressCustomerCWPrice';
      end;
      commit;
      -- drop temporary table if empty
      drop_table(tableName);
    end if;
  exception
    when table_not_exists then
      null;
  end UndoCompressCustomerCWPrice;

  procedure CompressGeneralCWPrice(testRun            boolean,
                                   compactOnStartDate boolean) is
  cursor c1_offSD is
          select grp2.generalrentprice_id, grp2.generalpricelist_id, grp2.product_id,
                 grp2.sizedefinition_id, grp2.finishingmethod_id, grp2.price, grp2.startdate
          from generalrentprice grp2
          where grp2.generalrentprice_id in
            (select min(grp1.generalrentprice_id)
            from
                 (select grp.generalpricelist_id, grp.product_id, grp.sizedefinition_id,
                         grp.finishingmethod_id, grp.price, min(grp.startdate) startdate
                  from generalrentprice grp
                  where grp.typeofrent = 2
                  group by grp.generalpricelist_id, grp.product_id, grp.sizedefinition_id,
                        grp.finishingmethod_id, grp.price
                  having count(1)> 1) t, generalrentprice grp1
            where grp1.typeofrent = 2
                and grp1.generalpricelist_id = t.generalpricelist_id
                and grp1.product_id = t.product_id
                and grp1.sizedefinition_id = t.sizedefinition_id
                and grp1.finishingmethod_id = t.finishingmethod_id
                and grp1.price = t.price
                and grp1.startdate = t.startdate
                group by grp1.generalpricelist_id, grp1.product_id, grp1.sizedefinition_id, grp1.finishingmethod_id)
            and not exists (select 1 from generalrentprice grp3
                where grp3.generalpricelist_id = grp2.generalpricelist_id
                and grp3.product_id = grp2.product_id
                and grp3.sizedefinition_id = grp2.sizedefinition_id
                and grp3.finishingmethod_id = grp2.finishingmethod_id
                and grp3.price != grp2.price
                and grp3.typeofrent = 2
                and grp3.changesperweek = -1);

  cursor c2_onSD is
          select grp2.generalrentprice_id, grp2.generalpricelist_id, grp2.product_id,
                 grp2.sizedefinition_id, grp2.finishingmethod_id, grp2.price, grp2.startdate
          from generalrentprice grp2
          where grp2.generalrentprice_id in
            (select min(grp1.generalrentprice_id) generalrentprice_id
            from
                 (select grp.generalpricelist_id, grp.product_id, grp.sizedefinition_id,
                         grp.finishingmethod_id, grp.price, grp.startdate
                  from generalrentprice grp
                  where grp.typeofrent = 2
                  group by grp.generalpricelist_id, grp.product_id, grp.sizedefinition_id,
                        grp.finishingmethod_id, grp.price, grp.startdate
                  having count(1)> 1) t, generalrentprice grp1
            where grp1.typeofrent = 2
                and grp1.generalpricelist_id = t.generalpricelist_id
                and grp1.product_id = t.product_id
                and grp1.sizedefinition_id = t.sizedefinition_id
                and grp1.finishingmethod_id = t.finishingmethod_id
                and grp1.price = t.price
                and grp1.startdate = t.startdate
                group by grp1.generalpricelist_id, grp1.product_id, grp1.sizedefinition_id, grp1.finishingmethod_id)
            and not exists (select 1 from generalrentprice grp3
                where grp3.generalpricelist_id = grp2.generalpricelist_id
                and grp3.product_id = grp2.product_id
                and grp3.sizedefinition_id = grp2.sizedefinition_id
                and grp3.finishingmethod_id = grp2.finishingmethod_id
                and grp3.price != grp2.price
                and grp3.typeofrent = 2
                and grp3.changesperweek = -1);

  cursor toBeDeleted(v_gplid number, v_prod number, v_sd number, v_fm number, v_price generalrentprice.price%type, v_startdate date) is
          select grp.*, gpl.code gplcode, p.code productcode, sd.code sizecode, fm.code fmcode
          from
            generalrentprice grp, generalpricelist gpl,
            product p, sizedefinition sd, finishingmethod fm
          where
            grp.generalpricelist_id = gpl.generalpricelist_id
            and grp.product_id = p.product_id
            and grp.sizedefinition_id = sd.sizedefinition_id
            and grp.finishingmethod_id = fm.finishingmethod_id
            and grp.generalpricelist_id = v_gplid
            and grp.product_id = v_prod
            and grp.sizedefinition_id = v_sd
            and grp.finishingmethod_id = v_fm
            and grp.price = v_price
            and grp.startdate >= nvl(v_startdate, to_date('01/01/1900', 'dd/mm/yyyy'))
            and grp.startdate <= nvl(v_startdate, to_date('31/12/9999', 'dd/mm/yyyy'))
            and grp.typeofrent = 2;
  tbExists number := 0;
  tableName varchar2(50);
  refRec toBeDeleted%rowtype;   -- will keep the reference record to copy values from into the new record for price *
  curentIndex number := 0;      -- each run of the procedure will insert into the backup table
                                -- a new lastindex value, so that we can make an consistent
                                -- recover of only the last deleted data
  begin
     if (compactOnStartDate) then
        tableName := 'GENERALRENTPRICE_CPW_DATE';
        for rec in c2_onSD loop
          if (tbExists = 0 and not testRun) then -- create back-up table if doesn't exists/retrieve next lastindex number
              curentIndex := create_table(tableName);
              tbExists := 1;
          end if;

          for toDelRec in toBeDeleted(rec.generalpricelist_id, rec.product_id, rec.sizedefinition_id, rec.finishingmethod_id, rec.price, rec.startdate) loop
              if (toDelRec.Generalrentprice_Id = rec.generalrentprice_id) then
                 refRec := toDelRec;
              end if;
              -- log the record to be deleted
              write_log('general pricelist code = ' || toDelRec.Gplcode
              || ', product code = ' || toDelRec.Productcode || ', size code = ' || toDelRec.Sizecode
              || ', finishing method code = ' || toDelRec.Fmcode || ', changes per week = ' || toDelRec.Changesperweek
              || ', start date = ' || toDelRec.Startdate || ', price = ' || toDelRec.Price,
              1, 'GRP');
              if (not testRun) then
                 -- insert the record to be deleted into the back-up table
                 execute immediate 'insert into GENERALRENTPRICE_CPW_DATE (select grp.*,' || curentIndex
                        || ' from GENERALRENTPRICE grp
                        where grp.generalrentprice_Id = ' || toDelRec.Generalrentprice_Id || ')' ;
                 -- delete record
                 delete from GENERALRENTPRICE grp
                        where grp.generalrentprice_id = toDelRec.Generalrentprice_Id;
              end if;
          end loop; -- end delete loop

          if (not testRun) then
              -- insert new record for price *
              insert into GENERALRENTPRICE(GENERALRENTPRICE_ID,GENERALPRICELIST_ID,PRODUCT_ID,SIZEDEFINITION_ID,FINISHINGMETHOD_ID,TIMESTAMP,SYSTEMUSER_ID,PRICE,STARTDATE,CHANGESPERWEEK,TYPEOFRENT,INVOICEFREQUENCYNUMBER,RATIFICATIONSTARTDATE,CREATIONUSER_ID,CREATIONTIMESTAMP,RATIFICATIONUSER_ID,RATIFICATIONTIMESTAMP,SIZEBILLINGGROUP_ID)
                     values
                     (refRec.Generalrentprice_Id,
                     refRec.Generalpricelist_Id,
                     refRec.Product_Id,
                     refRec.Sizedefinition_Id,
                     refRec.Finishingmethod_Id,
                     sysdate,
                     refRec.Systemuser_Id,
                     refRec.Price,
                     refRec.Startdate,
                     -1,
                     refRec.Typeofrent,
                     refRec.Invoicefrequencynumber,
                     refRec.Ratificationstartdate,
                     refRec.Creationuser_Id,
                     refRec.Creationtimestamp,
                     refRec.Ratificationuser_Id,
                     refRec.Ratificationtimestamp,
                     refRec.Sizebillinggroup_Id);
          end if;
        end loop; -- end insert new rec. loop
     else
        tableName := 'GENERALRENTPRICE_CPW_NODATE';
        for rec in c1_offSD loop
          if (tbExists = 0 and not testRun) then -- create back-up table if doesn't exists/retrieve next lastindex number
             curentIndex := create_table(tableName);
             tbExists := 1;
          end if;

          for toDelRec in toBeDeleted(rec.generalpricelist_id, rec.product_id, rec.sizedefinition_id, rec.finishingmethod_id, rec.price, null) loop
              if (toDelRec.Generalrentprice_Id = rec.generalrentprice_id) then
                 refRec := toDelRec;
              end if;
              -- log the record to be deleted
              write_log('general pricelist code = ' || toDelRec.Gplcode
              || ', product code = ' || toDelRec.Productcode || ', size code = ' || toDelRec.Sizecode
              || ', finishing method code = ' || toDelRec.Fmcode || ', changes per week = ' || toDelRec.Changesperweek
              || ', start date = ' || toDelRec.Startdate || ', price = ' || toDelRec.Price,
              1, 'GRP');
              if (not testRun) then
                 -- insert the record to be deleted into the back-up table
                 execute immediate 'insert into GENERALRENTPRICE_CPW_NODATE (select grp.*,' || curentIndex
                        || ' from GENERALRENTPRICE grp
                        where grp.generalrentprice_Id = ' || toDelRec.Generalrentprice_Id || ')' ;
                 -- delete record
                 delete from GENERALRENTPRICE grp
                        where grp.generalrentprice_Id = toDelRec.Generalrentprice_Id;
              end if;
          end loop; -- end delete loop

          if (not testRun) then
              -- insert in CRP new record for price *
              insert into GENERALRENTPRICE(GENERALRENTPRICE_ID,GENERALPRICELIST_ID,PRODUCT_ID,SIZEDEFINITION_ID,FINISHINGMETHOD_ID,TIMESTAMP,SYSTEMUSER_ID,PRICE,STARTDATE,CHANGESPERWEEK,TYPEOFRENT,INVOICEFREQUENCYNUMBER,RATIFICATIONSTARTDATE,CREATIONUSER_ID,CREATIONTIMESTAMP,RATIFICATIONUSER_ID,RATIFICATIONTIMESTAMP,SIZEBILLINGGROUP_ID)
                     values
                     (refRec.Generalrentprice_Id,
                     refRec.Generalpricelist_Id,
                     refRec.Product_Id,
                     refRec.Sizedefinition_Id,
                     refRec.Finishingmethod_Id,
                     sysdate,
                     refRec.Systemuser_Id,
                     refRec.Price,
                     refRec.Startdate,
                     -1,
                     refRec.Typeofrent,
                     refRec.Invoicefrequencynumber,
                     refRec.Ratificationstartdate,
                     refRec.Creationuser_Id,
                     refRec.Creationtimestamp,
                     refRec.Ratificationuser_Id,
                     refRec.Ratificationtimestamp,
                     refRec.Sizebillinggroup_Id);
          end if;

        end loop; -- end insert new rec. loop
     end if;
     -- write in sqlscripts table
     if (not testRun) then
       begin
          insert into sqlscript (scriptname, issuccessful, createddate, modifieddate) values ('CompressGeneralCWPrice', 'Y', sysdate, null);
       exception
          when dup_val_on_index then
               update sqlscript ss set ss.modifieddate = sysdate where ss.scriptname like 'CompressGeneralCWPrice';
       end;
     end if;
     commit;
  end CompressGeneralCWPrice;

  procedure UndoCompressGeneralCWPrice(compactOnStartDate boolean) is
  table_not_exists exception;
  pragma exception_init(table_not_exists, -00942);
  tableName varchar2(50);
  lastIndex number := 1;
  begin
    if (compactOnStartDate) then
      tableName := 'GENERALRENTPRICE_CPW_DATE';
    else
      tableName := 'GENERALRENTPRICE_CPW_NODATE';
    end if;

    -- determine the last moved records
    execute immediate 'select max(LASTINDEX) from ' || tableName into lastIndex;
    if (lastIndex is null) then
      execute immediate 'drop table ' || tableName;
    else
      -- delete from GRP last inserted records
      execute immediate 'delete from GENERALRENTPRICE grp
             where grp.changesperweek = -1
             and grp.generalrentprice_id in
             (select cpw.generalrentprice_id from ' || tableName || ' cpw
                     where cpw.lastindex = ' || lastIndex || ')';

      -- restore in GRP last moved records
      execute immediate 'insert into GENERALRENTPRICE
      (select cpw.generalrentprice_id,
              cpw.generalpricelist_id,
              cpw.product_id,
              cpw.sizedefinition_id,
              cpw.finishingmethod_id,
              sysdate,
              cpw.systemuser_id,
              cpw.price,
              cpw.startdate,
              cpw.changesperweek,
              cpw.typeofrent,
              cpw.invoicefrequencynumber
      from ' || tableName || ' cpw where cpw.lastindex = ' || lastIndex || ')';

      -- delete from back-up table last moved records
      execute immediate 'delete from ' || tableName || ' cpw where cpw.lastindex = ' || lastIndex;


      -- write in sqlscripts table
      begin
        insert into sqlscript (scriptname, issuccessful, createddate, modifieddate) values ('UndoCompressGeneralCWPrice', 'Y', sysdate, null);
      exception
        when dup_val_on_index then
             update sqlscript ss set ss.modifieddate = sysdate where ss.scriptname like 'UndoCompressGeneralCWPrice';
      end;
      commit;
      -- drop temporary table if empty
      drop_table(tableName);
    end if;
  exception
    when table_not_exists then
      null;
  end UndoCompressGeneralCWPrice;

end PACK_COMPRESSCWPRICE;

/
create or replace package pack_contract is
  /*
  Pack_Contract
  Version 0.3c
  */
  procedure replacepurchaseorder(fpi_oldcpo_id     in contractpurchaseorder.contractpurchaseorder_id%type,
                                 fpi_newcpo_id     in contractpurchaseorder.contractpurchaseorder_id%type,
                                 fpi_systemuser_id in systemuser.systemuser_id%type);
  function getpurchaseorder(fpi_invoicelinetype_id in invoicelinetype.invoicelinetype_id%type,
                            fpi_customer_id        in customer.customer_id%type,
                            fpi_ref_date           in date,
                            fpi_plpc_id            in productlistpercustomer.productlistpercustomer_id%type, --null allowed
                            fpi_activity_id        in activity.activity_id%type, --null allowed
                            fpo_cpo_id             out nocopy contractpurchaseorder.contractpurchaseorder_id%type,
                            fpo_cpol_id            out nocopy contractpurchaseorderline.contractpurchaseorderline_id%type,
                            fpo_ponumber           out nocopy contractpurchaseorder.purchaseordernumber%type)
    return number;
  /*
  Return values function getpurchaseorder
  -1 = OK, No PO needed
  0 = OK, PO is determined
  1 = Warning: Used up but continuing
  2 = Error: no PO found
  3 = Error: PO is expired
  4 = Error: PO is used up
  5 = Error: Others see log
  */
end pack_contract;
/
create or replace package body pack_contract is
  ----------------------------------------------------------------------------
  --internal variables:
  ge_user___exception exception;
  ge_includpochck     exception;
  gv_message      abslog.message%type;
  gv_program      varchar2(64);
  gv_systemuserid systemuser.systemuser_id%type := 0;
  gv_plantid      plant.plant_id%type;
  ----------------------------------------------------------------------------
  --internal functions
  procedure write_log(fpi_message in abslog.message%type, fpi_priority in abslog.priority%type) is
  begin
    --write_log
    abslogwrite.abslog_write(5, 'pack_contract', gv_plantid, fpi_priority,
                             gv_program || ' ' || fpi_message, gv_systemuserid);
  end write_log;

  procedure replacepurchaseorder(fpi_oldcpo_id     in contractpurchaseorder.contractpurchaseorder_id%type,
                                 fpi_newcpo_id     in contractpurchaseorder.contractpurchaseorder_id%type,
                                 fpi_systemuser_id in systemuser.systemuser_id%type) is
    lv_rec_new_contractpo contractpurchaseorder%rowtype;
    fpi_oldpo_expdate contractpurchaseorder.expirationdate%type;

    procedure initialize is
    begin
      --initialize
      gv_program := 'replacepurchaseorder';
      gv_plantid := null;
      if fpi_oldcpo_id is null then
        begin
          gv_message := 'None of the parameters (fpi_oldcpo_id/fpi_newcpo_id) can be left blank';
          raise ge_user___exception;
        end;
      end if;
      if fpi_oldcpo_id = fpi_newcpo_id then
        begin
          gv_message := 'parameters (fpi_oldcpo_id/fpi_newcpo_id) cannot be the same ' ||
                        to_char(fpi_oldcpo_id);
          raise ge_user___exception;
        end;
      end if;
      if fpi_systemuser_id is null then
        begin
          gv_message := 'parameter (fpi_systemuser_id) cannot be left blank';
          raise ge_user___exception;
        end;
      end if;
    end initialize;
  begin
    --ReplacePurchaseOrder
    initialize;
    gv_message := 'select new contractpurchaseorder id (fpi_newcpo_id) ' || to_char(fpi_newcpo_id);
    select *
    into   lv_rec_new_contractpo
    from   contractpurchaseorder cpo
    where  cpo.contractpurchaseorder_id = fpi_newcpo_id;
    --copy into new contractpocustomer, only copied when it does not yet exist
    gv_message := 'copy old contractpocustomer id (fpi_oldcpo_id) ' || to_char(fpi_oldcpo_id) ||
                  ' into new contractpocustomer id (fpi_newcpo_id) ' || to_char(fpi_newcpo_id);
    insert into contractpocustomer
      (contractpocustomer_id, contractpurchaseorder_id, contractcustomer_id, startdate, enddate,
       systemuser_id, timestamp)
      select seq_contractpocustomer.nextval, fpi_newcpo_id, cpo.contractcustomer_id,
             case
               when lv_rec_new_contractpo.startdate < cpo.startdate then
                cpo.startdate
               else
                lv_rec_new_contractpo.startdate
             end, lv_rec_new_contractpo.expirationdate, fpi_systemuser_id, sysdate
      from   contractpocustomer cpo
      where  cpo.contractpurchaseorder_id = fpi_oldcpo_id
      and    cpo.enddate > lv_rec_new_contractpo.startdate
      and    not exists (select 1
              from   contractpocustomer cpx
              where  cpx.contractpurchaseorder_id = fpi_newcpo_id
              and    cpx.contractcustomer_id = cpo.contractpocustomer_id);
              commit;
    --Put an end date for the old PO, remark only put end date when copied above
    gv_message := 'put an end date to old contractpocustomer id (fpi_oldcpo_id) ' ||
                  to_char(fpi_oldcpo_id);
    update contractpocustomer cpo
    set    cpo.enddate = case
                           when lv_rec_new_contractpo.startdate < cpo.startdate then
                            cpo.startdate
                           else
                            lv_rec_new_contractpo.startdate
                         end
    where  cpo.contractpurchaseorder_id = fpi_oldcpo_id
    and    cpo.enddate > lv_rec_new_contractpo.startdate
    and    exists (select 1
            from   contractpocustomer cpx
            where  cpx.contractpurchaseorder_id = fpi_newcpo_id
            --> after rework
            --and    cpx.contractpocustomer_id = cpo.contractpocustomer_id
            --and    cpx.systemuser_id = fpi_systemuser_id
            --and    cpx.timestamp > sysdate - 0.01
            );

   -->After customer test: update also expiration date of contractPO, only when Exp_Date>replacement date.

            select po.expirationdate
            into fpi_oldpo_expdate
            from contractpurchaseorder po
            where po.contractpurchaseorder_id = fpi_oldcpo_id;

       if (fpi_oldpo_expdate > trunc(sysdate)) then
           update contractpurchaseorder po
           set  po.expirationdate = case
                           when lv_rec_new_contractpo.startdate < po.startdate then
                            po.startdate
                           else
                            lv_rec_new_contractpo.startdate
                         end
    where  po.contractpurchaseorder_id = fpi_oldcpo_id;
    --<
  end if;
    if sql%rowcount = 0 then
      begin
        gv_message := 'nothing found for updating based on old contractpocustomer id (fpi_oldcpo_id) ' ||
                      to_char(fpi_oldcpo_id);
        raise ge_user___exception;
      end;
    end if;
    --commit
    commit;
  exception
    when ge_user___exception then
      begin
        rollback;
        write_log(gv_message, 3);
      end;
    when no_data_found then
      begin
        rollback;
        write_log(gv_message || ' no data found!', 3);
      end;
    when others then
      begin
        rollback;
        write_log(gv_message || ' ' || sqlerrm, 3);
      end;
  end replacepurchaseorder;

  function getpurchaseorder(fpi_invoicelinetype_id in invoicelinetype.invoicelinetype_id%type,
                            fpi_customer_id        in customer.customer_id%type,
                            fpi_ref_date           in date,
                            fpi_plpc_id            in productlistpercustomer.productlistpercustomer_id%type, --null allowed
                            fpi_activity_id        in activity.activity_id%type, --null allowed
                            fpo_cpo_id             out nocopy contractpurchaseorder.contractpurchaseorder_id%type,
                            fpo_cpol_id            out nocopy contractpurchaseorderline.contractpurchaseorderline_id%type,
                            fpo_ponumber           out nocopy contractpurchaseorder.purchaseordernumber%type)
    return number is
    /*
    Return value
    0 = OK, PO is determined
    1 = Warning: Used up but continuing
    2 = Error: no PO found
    3 = Error: PO is expired
    4 = Error: PO is used up
    5 = Error: Others see log
    */
    lv_rec_contractpurchaseorder contractpurchaseorder%rowtype;

    procedure initialize is
      lv_includepocheck invoicelinetype.includepocheck%type;
    begin
      --initialize
      gv_program   := 'getpurchaseorder';
      fpo_cpo_id   := null;
      fpo_ponumber := null;
      fpo_cpol_id  := null;
      if fpi_invoicelinetype_id is null then
        begin
          gv_message := 'parameter fpi_invoicelinetype_id cannot be left blank';
          raise ge_user___exception;
        end;
      else
        --lookup value includepocheck for fpi_invoicelinetype_id
        gv_message := 'parameter fpi_invoicelinetype_id ' || to_char(fpi_invoicelinetype_id);
        select ilt.includepocheck
        into   lv_includepocheck
        from   invoicelinetype ilt
        where  ilt.invoicelinetype_id = fpi_invoicelinetype_id;
        if lv_includepocheck = 'N' then
          begin
            raise ge_includpochck; --will return -1
          end;
        end if;
      end if;
      if fpi_customer_id is null then
        begin
          gv_message := 'parameter fpi_customer_id cannot be left blank';
          raise ge_user___exception;
        end;
      end if;
      if fpi_ref_date is null then
        begin
          gv_message := 'parameter fpi_ref_date cannot be left blank';
          raise ge_user___exception;
        end;
      end if;
    end initialize;
  begin
    --initialize
    initialize;
    --find plpc
    if fpi_plpc_id is not null then
      begin
        --lookup plpc
        gv_message := 'lookup plpc id (fpi_plpc_id) ' || to_char(fpi_plpc_id);
        select l.contractpurchaseorder_id, l.contractpurchaseorderline_id
        into   lv_rec_contractpurchaseorder.contractpurchaseorder_id, fpo_cpol_id
        from   productlistpercustomer l
        where  l.productlistpercustomer_id = fpi_plpc_id;
        if lv_rec_contractpurchaseorder.contractpurchaseorder_id is not null then
          begin
            --get cpo
            gv_message := 'get cpo id ' ||
                          to_char(lv_rec_contractpurchaseorder.contractpurchaseorder_id);
            select cpo.*
            into   lv_rec_contractpurchaseorder
            from   contractpurchaseorder cpo
            where  cpo.contractpurchaseorder_id =
                   lv_rec_contractpurchaseorder.contractpurchaseorder_id;
            --fill parameters with that what has been found
            fpo_ponumber := lv_rec_contractpurchaseorder.purchaseordernumber;
            fpo_cpo_id   := lv_rec_contractpurchaseorder.contractpurchaseorder_id;
            if ((lv_rec_contractpurchaseorder.startdate > fpi_ref_date) or
               (lv_rec_contractpurchaseorder.expirationdate <= fpi_ref_date)) then
              begin
                fpo_cpol_id := null;
                return 3; --Error: PO is expired
              end;
            elsif (lv_rec_contractpurchaseorder.value <> 0 and lv_rec_contractpurchaseorder.value <= lv_rec_contractpurchaseorder.invoicedamount) then
              begin
                if (lv_rec_contractpurchaseorder.closeaction = 0 or
                   (lv_rec_contractpurchaseorder.closeaction = 2 and
                   lv_rec_contractpurchaseorder.value * 100 >
                   lv_rec_contractpurchaseorder.maxpercentage)) then
                  begin
                    fpo_cpol_id := null;
                    return 4; --Error: PO is used up
                  end;
                else
                  return 1; --Warning: Used up but continuing
                end if;
              end;
            else
              begin
                return 0; --OK, PO is determined
              end;
            end if; -- if ((lv_rec_contractpurchaseorder.startdate...
          end;
        end if; --if lv_contractpurchaseorder_id is not null
      end;
    end if; --if fpi_plpc_id is not null
    --Step 2: Determine all possible PO's and take the one with the highest priority
    gv_message := 'Step 2: Determine all possible POs and take the one with the highest priority';
    for x in (select cpo.contractpurchaseorder_id, cpo.purchaseordernumber, cpoc.startdate,
                     (case
                       when cpo.invoicelinetypesperpo = 'Y' then
                        1
                       when cpo.businessunit_id is not null then
                        2
                       when (cpo.value = 0 or cpo.value > cpo.invoicedamount) then
                        3
                       else
                        4
                     end) as priority
              from   contractcustomer cc
              join   contractpocustomer cpoc
              on     cpoc.contractcustomer_id = cc.contractcustomer_id
              join   contractpurchaseorder cpo
              on     cpo.contractpurchaseorder_id = cpoc.contractpurchaseorder_id
              join   customer cus
              on     cus.customer_id = cc.customer_link_id
              where  cc.customer_link_id = fpi_customer_id
              and    cc.startdate <= fpi_ref_date
              and    cc.enddate > fpi_ref_date
              and    cpoc.startdate <= fpi_ref_date
              and    cpoc.enddate > fpi_ref_date
              and    cpo.contract_id = cc.contract_id
              and    cpo.startdate <= fpi_ref_date
              and    cpo.expirationdate > fpi_ref_date
              and    cpo.manualpo = 'N'
              and    ((cpo.invoicelinetypesperpo = 'N') or
                    (exists (select 1
                               from   contractpoinvoicelinetype cpoilt
                               where  cpoilt.contractpurchaseorder_id = cpo.contractpurchaseorder_id
                               and    cpoilt.invoicelinetype_id = fpi_invoicelinetype_id)))
              and    ((cpo.value > cpo.invoicedamount) or (cpo.closeaction = 1) or
                    (lv_rec_contractpurchaseorder.closeaction = 2 and
                    lv_rec_contractpurchaseorder.value * 100 <
                    lv_rec_contractpurchaseorder.maxpercentage))
              and    ((cpo.businessunit_id is null) or
                    ((fpi_activity_id is null) and
                    (cpo.businessunit_id = cus.defaultbusinessunit_id)) or
                    ((fpi_activity_id is not null) and exists
                     (select 1
                        from   customeractivities ca
                        where  ca.customer_id = cc.customer_link_id
                        and    ca.activity_id = fpi_activity_id
                        and    ca.processbusinessunit_id = cpo.businessunit_id)))
              order  by priority asc, cpo.closeaction asc, cpoc.startdate asc, cpo.purchaseordernumber asc) loop
      begin
        fpo_cpo_id   := x.contractpurchaseorder_id;
        fpo_ponumber := x.purchaseordernumber;
        if x.priority = 4 then
          return 1; --Warning: Used up but continuing
        else
          return 0; --OK, PO is determined
        end if;
      end;
    end loop; --x
    --not found return 2
    return 2; --Error: no PO found
  exception
    when ge_includpochck then
      begin
        return - 1; -- OK, No PO needed.
      end;
    when ge_user___exception then
      begin
        write_log(gv_message, 3);
        return 5;
      end;
    when no_data_found then
      begin
        write_log(gv_message || ' no data found!', 3);
        return 5;
      end;
    when others then
      begin
        write_log(gv_message || ' ' || sqlerrm, 3);
        return 5;
      end;
  end getpurchaseorder;

end pack_contract;
/
create or replace package pack_dbconsistencycheck is

  /*******************************************************\
  * Author  : PVD                                         *
  * Created : 28-4-2009                                   *
  * Purpose : Check the consistency of the database       *
  *           Based on the table dbconsistencycheck       *
  \*******************************************************/

  type ref_cur_t is ref cursor;

  procedure fill_array(fpcounter number, fpstring varchar2);
  function ref_cur return ref_cur_t;
  procedure check_db;

end pack_dbconsistencycheck;
/
create or replace package body pack_dbconsistencycheck is
  --global variable declaration
  type t_char_data is table of varchar2(4000) index by binary_integer;
  gv_char_data t_char_data;
  gv_query     varchar2(32000);
  gv_count     number;
  gv_desc_tab  dbms_sql.desc_tab;
  gv_columns   varchar2(1000);
  varchar2_type constant pls_integer := 1;
  number_type   constant pls_integer := 2;
  date_type     constant pls_integer := 12;
  rowid_type    constant pls_integer := 11;
  char_type     constant pls_integer := 96;

  --write log
  procedure write_log(fpserrormsg abslog.message%type, fpnpriority abslog.priority%type default 1) is
  begin
    abslogwrite.abslog_write(5, 'pack_dbconsistencycheck', null, fpnpriority, fpserrormsg);
  end write_log;

  --fill array with data
  procedure fill_array(fpcounter number, fpstring varchar2) is
  begin
    gv_char_data(fpcounter) := fpstring;
  end fill_array;

  --clear the array of data
  procedure empty_array is
  begin
    gv_char_data.delete;
  end empty_array;

  --determine number of columns of sql-select
  procedure describe_columns is
    l_cur integer;
  begin
    gv_columns := null;
    l_cur      := dbms_sql.open_cursor;
    dbms_sql.parse(l_cur, gv_query, dbms_sql.native);
    dbms_sql.describe_columns(l_cur, gv_count, gv_desc_tab);
    dbms_sql.close_cursor(l_cur);
    if gv_count >= 1 then
      for i in 1 .. gv_count loop
        gv_columns := gv_columns || ',' || gv_desc_tab(i).col_name;
      end loop;
      gv_columns := ltrim(gv_columns, ',');
    end if;
  exception
    when others then
      if dbms_sql.is_open(l_cur) then
        dbms_sql.close_cursor(l_cur);
      end if;
      raise;
  end describe_columns;

  --determine type of the columns of sql-select
  function record_def return varchar2 is
    l_record_def  varchar2(32000);
    l_type        varchar2(100);
    l_col_type    pls_integer;
    l_col_max_len pls_integer;
  begin
    for i in 1 .. gv_count loop
      l_col_type    := gv_desc_tab(i).col_type;
      l_col_max_len := gv_desc_tab(i).col_max_len;
      if l_col_type = varchar2_type then
        l_type := 'VARCHAR2(' || l_col_max_len || ')';
      elsif l_col_type = number_type then
        l_type := 'NUMBER';
      elsif l_col_type = date_type then
        l_type := 'DATE';
      elsif l_col_type = rowid_type then
        l_type := 'ROWID';
      elsif l_col_type = char_type then
        l_type := 'CHAR(' || l_col_max_len || ')';
      end if;
      l_record_def := l_record_def || ' col_' || i || ' ' || l_type || ',';
    end loop;
    l_record_def := rtrim(l_record_def, ',');
    return l_record_def;
  end record_def;

  --execute the statement after building the cursor based on the sql-select
  procedure fetch_ref_cur(p_process_def varchar2) is
    l_statement varchar2(32000);
  begin
    l_statement := 'DECLARE' || ' TYPE record_t IS RECORD (' || record_def || ');' ||
                   ' l_record  record_t;' ||
                   ' l_ref_cur pack_dbconsistencycheck.ref_cur_t; lcounter number:=0; ' || ' BEGIN' ||
                   ' l_ref_cur := pack_dbconsistencycheck.ref_cur;' || ' LOOP' ||
                   ' FETCH l_ref_cur INTO l_record;' ||
                   ' EXIT WHEN l_ref_cur%NOTFOUND; lcounter := lcounter+1; ' || p_process_def ||
                   ' END LOOP;' || ' CLOSE l_ref_cur;' || '  END;';
    execute immediate l_statement;
  end fetch_ref_cur;

  --used during execution of fetch_ref_cur to get all the values from the select
  function process_def return varchar2 is
    l_process_def varchar2(32000);
  begin
    l_process_def := ' pack_dbconsistencycheck.fill_array(lcounter,';
    for i in 1 .. gv_count loop
      l_process_def := l_process_def || ' l_record.col_' || i || ' || '','' || ';
    end loop;
    l_process_def := rtrim(l_process_def, ' || '','' || ') || ');';
    return l_process_def;
  end process_def;

  --open the cursor based on select, read query
  function ref_cur return ref_cur_t is
    l_ref_cur ref_cur_t;
  begin
    open l_ref_cur for gv_query;
    return l_ref_cur;
  end ref_cur;

  --main procedure to check the database
  procedure check_db is
  begin
    write_log('START database consistency check');
    for x in (select *
              from   dbconsistencycheck db
              where  db.active = 'Y'
              order  by db.dbconsistencycheck_id) loop
      begin
        empty_array;
        gv_query := x.sqlstatement;
        describe_columns;
        fetch_ref_cur(p_process_def => process_def);
        if x.exactlyonerow = 'Y' then
          begin
            if gv_char_data.count = 1 then
              write_log('OK ' || x.description);
            else
              write_log('ERROR ' || nvl(x.additionalerrormessage, x.errormessage), 3);
            end if;
          end;
        else
          begin
            if gv_char_data.count = 0 then
              write_log('OK ' || x.description);
            else
              write_log('ERROR ' || gv_char_data.count || ' records ' || x.errormessage, 3);
            end if;
          end;
        end if;
        if gv_char_data.count > 0 and x.exactlyonerow = 'N' then
          begin
            write_log(gv_columns, 5);
            for i in gv_char_data.first .. gv_char_data.last loop
              begin
                write_log(gv_char_data(i), 5);
              end;
            end loop;
          end;
        end if;
      end;
    end loop;
    write_log('END database consistency check');
    dbms_output.put_line('Database consistency check ran succesfully.');
  exception
    when others then
      begin
        write_log(sqlerrm, 3);
        write_log('END database consistency check with errors!');
        dbms_output.put_line(sqlerrm);
        dbms_output.put_line('Errors during database consistency, check did not run succesfully!');
      end;
  end check_db;

end pack_dbconsistencycheck;
/
create or replace package pack_deliverybasics is
  -- Version 0.2
  -- Created : 09-08-2013 New
  -- Updated : 14-08-2013 Added route restriction on delayed even exchange = 2, added check on deliveryscheme from CPL.
  --         : 07-06-2023 Determinedeldaterouteclean, extra parameter fpi_invoicesgenerated
  -- Purpose : Contains logic for pickup and delivery date and route/stop determination

procedure determinedeldateroutesoil(fpi_plant_id           in number, -- null allowed
                                    fpi_customer_id        in number, -- not null allowed
                                    fpi_delpoint_id        in number, -- null allowed
                                    fpi_department_id      in number, -- null allowed
                                    fpi_typeofmerch        in number, -- not null allowed
                                    fpi_date               in date,   -- not null allowed
                                    fpi_plpc_id            in number, -- null allowed
                                    fpi_distribpoint_id    in number, -- null allowed
                                    fpi_log                in varchar2,-- null allowed
                                    fpo_inroute_id         out number,
                                    fpo_inroutestop_id     out number,
                                    fpo_inroutecontrol_id  out number,
                                    fpo_instop_id          out number,
                                    fpo_pickupdate         out date,
                                    fpo_outroute_id        out number,
                                    fpo_outroutestop_id    out number,
                                    fpo_outroutecontrol_id out number,
                                    fpo_outstop_id         out number,
                                    fpo_outdrivingdate     out date);


procedure testdeldateroutesoil(fpi_plantcode         in varchar2, -- null allowed
                               fpi_customernumber    in number,   -- not null allowed
                               fpi_delpointcode      in varchar2, -- null allowed
                               fpi_departmentnumber  in number,   -- null allowed
                               fpi_productcode       in varchar2, -- not null allowed
                               fpi_sizecode          in varchar2, -- null allowed
                               fpi_finmethodcode     in varchar2, -- null allowed
                               fpi_date              in date,     -- not null allowed
                               fpi_distribpointnr    in number,   -- null allowed
                               fpi_log               in varchar2,  -- null allowed
                               fpo_inroutenumber     out number,
                               fpo_inroutestopnumber out number,
                               fpo_inrealroutenumber out number,
                               fpo_inrealstopnumber  out number,
                               fpo_pickupdate        out date,
                               fpo_outroutenumber    out number,
                               fpo_outstopnumber     out number,
                               fpo_outrealroutenr    out number,
                               fpo_outrealstopnr     out number,
                               fpo_outdrivingdate    out date);
-- This procedure is only used for test purposes. Customer and Product (to determine type of merchandize) are obgligated input parameters.
procedure determinedeldatepwbsoil(fpi_plant_id           in number,
                                    fpi_customer_id        in number,
                                    fpi_delpoint_id        in number,
                                    fpi_department_id      in number,
                                    fpi_date               in date,
                                    fpi_distribpoint_id    in number,
                                    fpi_log                in varchar2,
                                    fpo_inroute_id         out number,
                                    fpo_inroutestop_id     out number,
                                    fpo_inroutecontrol_id  out number,
                                    fpo_instop_id          out number,
                                    fpo_pickupdate         out date,
                                    fpo_outroute_id        out number,
                                    fpo_outroutestop_id    out number,
                                    fpo_outroutecontrol_id out number,
                                    fpo_outstop_id         out number,
                                    fpo_outdrivingdate     out date);

procedure testdeldatepwbsoil(fpi_plantcode         in varchar2,
                               fpi_customernumber    in number,
                               fpi_delpointcode      in varchar2,
                               fpi_departmentnumber  in number,
                               fpi_date              in date,
                               fpi_distribpointnr    in number,
                               fpi_log               in varchar2,
                               fpo_inroutenumber     out number,
                               fpo_inroutestopnumber out number,
                               fpo_inrealroutenumber out number,
                               fpo_inrealstopnumber  out number,
                               fpo_pickupdate        out date,
                               fpo_outroutenumber    out number,
                               fpo_outstopnumber     out number,
                               fpo_outrealroutenr    out number,
                               fpo_outrealstopnr     out number,
                               fpo_outdrivingdate    out date);
-- This procedure is only used for test purposes.

procedure determinedeldaterouteclean(fpi_plant_id        in number, -- null allowed
                                     fpi_customer_id     in number, -- not null allowed
                                     fpi_delpoint_id     in number, -- null allowed
                                     fpi_department_id   in number, -- null allowed
                                     fpi_typeofmerch     in number, -- not null allowed
                                     fpi_date            in date,   -- not null allowed
                                     fpi_plpc_id         in number, -- null allowed
                                     fpi_distribpoint_id in number, -- null allowed
                                     fpi_log             in varchar2,-- null allowed
                                     fpo_routestop_id    out number,
                                     fpo_route_id        out number,
                                     fpo_stop_id         out number,
                                     fpo_routecontrol_id out number,
                                     fpo_drivingdate     out date,
                                     fpi_invoicesgenerated in number default null); -- null allowed


procedure testdeldaterouteclean(fpi_plantcode        in varchar2, -- null allowed
                                fpi_customernumber   in number,   -- not null allowed
                                fpi_delpointcode     in varchar2, -- null allowed
                                fpi_departmentnumber in number,   -- null allowed
                                fpi_productcode      in varchar2, -- not null allowed
                                fpi_sizecode         in varchar2, -- null allowed
                                fpi_finmethodcode    in varchar2, -- null allowed
                                fpi_date             in date,     -- not null allowed
                                fpi_distribpointnr   in number,   -- null allowed
                                fpi_log              in varchar2,  -- null allowed
                                fpo_outroutenumber   out number,
                                fpo_outstopnumber    out number,
                                fpo_outrealroutenr   out number,
                                fpo_outrealstopnr    out number,
                                fpo_outdrivingdate   out date);
-- This procedure is only used for test purposes. Customer and Product (to determine type of merchandize) are obgligated input parameters.

-- This function is to determine the last in date for the customer
function  determinepickup(fpi_plant_id           in number,
                          fpi_customer_id        in number,
                          fpi_delpoint_id        in number,
                          fpi_department_id      in number,
                          fpi_typeofmerch        in number,
                          fpi_date               in date,
                          fpi_distribpoint_id    in number,
                          fpi_log                in varchar2,
                          fpi_plpc_id            in number,
                          fpo_stop_id            out number,
                          fpo_routestop_id       out number,
                          fpo_routecontrol_id    out number,
                          fpo_route_id           out number,
                          fpo_orgpickupdate      out date,
                          fpo_pickupdate         out date,
                          fpo_movetoroutestop_id out number,
                          fpo_movetoroute_id     out number,
                          fpo_movestartdate      out date,
                          fpo_movedays           out number) return boolean;

procedure determinedeldatedistribpoint(fpi_plant_id           in number,
                                    fpi_date               in date,
                                    fpi_distribpoint_id    in number,
                                    fpi_log                in varchar2,
                                    fpo_inroute_id         out number,
                                    fpo_inroutestop_id     out number,
                                    fpo_inroutecontrol_id  out number,
                                    fpo_instop_id          out number,
                                    fpo_pickupdate         out date,
                                    fpo_outroute_id        out number,
                                    fpo_outroutestop_id    out number,
                                    fpo_outroutecontrol_id out number,
                                    fpo_outstop_id         out number,
                                    fpo_outdrivingdate     out date);

-- This procedure is only used for test purposes.
procedure testdeldatedistribpoint(fpi_plantcode         in varchar2,
                               fpi_customernumber    in number,
                               fpi_departmentnumber  in number,
                               fpi_date              in date,
                               fpi_distribpointnr    in number,
                               fpi_log               in varchar2,
                               fpo_inroutenumber     out number,
                               fpo_inroutestopnumber out number,
                               fpo_inrealroutenumber out number,
                               fpo_inrealstopnumber  out number,
                               fpo_pickupdate        out date,
                               fpo_outroutenumber    out number,
                               fpo_outstopnumber     out number,
                               fpo_outrealroutenr    out number,
                               fpo_outrealstopnr     out number,
                               fpo_outdrivingdate    out date);

function  routestopvalid(fpi_routestop_id	     in number,
                         fpi_delpoint_id	     in number,
                         fpi_department_id	   in number,
                         fpi_typeofmerch	     in number,
                         fpi_date	             in date,
                         fpi_basedate          in date,
                         fpi_plpc_id	         in number,
                         fpi_distribpoint_id	 in number,
                         fpi_deeds_frequency     in number,
                         fpi_deeds_offset        in number,
                         fpi_log	             in varchar2,
                         fpi_delivery          in boolean,
                         fpo_firstnextdate     out date,
                         fpo_route_id	         out number,
                         fpo_stop_id	         out number,
                         fpo_routecontrol_id	 out number,
                         fpo_realdriving_date  out date,
                         fpi_invoicesgenerated in number default null) return boolean;


end pack_deliverybasics;
/
create or replace package body pack_deliverybasics is

  -- naming conventions parameter and variable prefixes
  -- pfi_ = function parameter in
  -- pfo_ = function parameter out
  -- gv_  = global variable
  -- m_   = local variable

  -- global variables declaration
  gv_last_error_number          NUMBER := 0;
  gv_last_error_message         VARCHAR2(2000) := '';
  gv_code_block                 VARCHAR2(100) := '';  -- defined position in procedure/function for errorlog
  gv_plant_id                   NUMBER := 0;
  gv_systemuser_id              NUMBER := 1;
  gv_max_date                   DATE;  -- initialized with 31-12-2099
  type deliveryweeks is table of number index by binary_integer;
  type stops is table of number index by binary_integer;


  ---------------------------------------------------------------------------------------------------
  procedure writeerrorlog(fpi_proc in varchar2) is
  begin
   abslogwrite.abslog_write(5,'PACK_DELIVERYBASICS',gv_plant_id,3,'Error in ' || fpi_proc || ' - '
  || gv_code_block || ' ' || to_char(gv_last_error_number) || ' ' || substr(gv_last_error_message, 1,1024),gv_systemuser_id);
  end;

  procedure writedebuglog(fpi_log in varchar2, fpi_proc in varchar2, fpi_message in varchar2) is
  begin
   if (fpi_log = 'Y') then
     abslogwrite.abslog_write(5,'PACK_DELIVERYBASICS',gv_plant_id,1,rpad(fpi_proc,30,' ') || ' - '|| fpi_message,gv_systemuser_id);
   end if;
  end;

------------------------------------------------------------------------------------
function getdeliveryweeksforyear(year      in integer,
                                 frequency in integer,
                                 offset    in integer) return deliveryweeks is
delweeks       deliveryweeks;
countdelweeks  integer;
firstweek      integer;
w              integer;
wb             integer;
currentdelweek integer;
i              integer;

begin
  firstweek      := getfirstdeliveryweekforyear(year, frequency, offset);
  w              := getweeksinyear(year);
  currentdelweek := firstweek;
  wb             := firstweek - frequency;
  i              := 1;
  while (wb > 0) loop
    begin
      delweeks(i) := wb;
      i := i + 1;
      wb := wb - frequency;
    end;
  end loop;
  countdelweeks := i;
  delweeks(countdelweeks) := currentdelweek;
  while (currentdelweek <= w) loop
    begin
      currentdelweek := currentdelweek + frequency;
      if (currentdelweek <= w) then
        begin
          countdelweeks := countdelweeks + 1;
          delweeks(countdelweeks) := currentdelweek;
        end;
      end if;
    end;
  end loop;
  return(delweeks);
end getdeliveryweeksforyear;

---------------------------------------------------------------------------------
function getnextdeldatedelscheme(fpi_startdate         in date,
                                 fpi_deliveryscheme_id in integer) return date is

weeksinyear  integer;
compareweek  integer;
compareyear  integer;
dayofweek    integer;
nextdelweekv integer;
v            deliveryweeks;
countv       integer;
m_frequency  integer;
m_offsetweek integer;

begin
  dayofweek   := getabsdaynumber(fpi_startdate);
  compareweek := getisoweek(fpi_startdate);
  compareyear := getyearofweek(fpi_startdate);
  weeksinyear := getweeksinyear(compareyear);
  begin
    select ds.frequency, ds.offsetweek
      into m_frequency, m_offsetweek
      from deliveryscheme ds
     where ds.deliveryscheme_id = fpi_deliveryscheme_id;
  exception when no_data_found then null;
  end;
  --  get delivery weeks for compare year and selected delivery scheme
  v      := getdeliveryweeksforyear(compareyear, m_frequency, m_offsetweek);
  countv := v.count;
  -- if no delivery weeks found for current year get delivery weeks for next year
  if countv = 0 then
    begin
      compareyear := compareyear + 1;
      compareweek := 1;
      v           := getdeliveryweeksforyear(compareyear, m_frequency, m_offsetweek);
    end;
  end if;
  -- determine next delivery week
  for i in v.first .. v.last loop
    if v(i) = compareweek then
      begin
        nextdelweekv := compareweek;
        exit;
      end;
    else
      nextdelweekv := 0;
    end if;
  end loop;
  if nextdelweekv = 0 then
    while (compareweek < weeksinyear) loop
      begin
        compareweek := compareweek + 1;
        for i in v.first .. v.last loop
          if v(i) = compareweek then
            begin
              nextdelweekv := compareweek;
              exit;
            end;
          else
            nextdelweekv := 0;
          end if;
        end loop;
        if nextdelweekv > 0 then
          exit;
        end if;
      end;
    end loop;
  end if;
  -- if there is no next delivery week this year then det delivery week from next year
  if nextdelweekv = 0 then
    begin
      compareyear := compareyear + 1;
      compareweek := 1;
      v           := getdeliveryweeksforyear(compareyear, m_frequency, m_offsetweek);
      while (compareweek <= m_frequency) loop
        begin
          for i in v.first .. v.last loop
            if v(i) = compareweek then
              begin
                nextdelweekv := compareweek;
                exit;
              end;
            end if;
          end loop;
          if (nextdelweekv > 0) then
            exit;
          end if;
          compareweek := compareweek + 1;
          end;
      end loop;
    end;
  end if;
  -- if there is a next delivery week this year or next year then return it
  if (nextdelweekv > 0) then
    return(getdateforweekyear(dayofweek, nextdelweekv, compareyear));
  else
    return(gv_max_date);
  end if;
end getnextdeldatedelscheme;

------------------------------------------------------------------------------------
procedure findstopforroutestop(fpi_routestop_id	    in number,
                               fpi_route_id         in number,
                               fpi_date             in date,
                               fpi_log              in varchar2,
                               fpi_invoicesgenerated in number,
                               fpo_route_id         out number,
                               fpo_stop_id          out number,
                               fpo_routecontrol_id  out number,
                               fpo_drivingdate      out date,
                               fpo_status           out number) is
m_proc             varchar2(30);
m_stop_id          number;
m_movedtostop_id   number;
m_invoicesgenerated number;

begin
  begin -- main exception block
    m_proc := '----findstopforroutestop';
    writedebuglog(fpi_log,m_proc,'inputparams: routestop=' || fpi_routestop_id || ',date=' || to_char(fpi_date,'DD-MON-YYYY'));
    gv_code_block := 'Init';

    m_stop_id          := 0;
    fpo_route_id       := fpi_route_id;
    fpo_routecontrol_id:= 0;
    fpo_drivingdate    := fpi_date;
    fpo_status         := 0;

    -- step 1: Check if the stop exists as not moved stop in the routecontrol for the specified date.
    -- there should be only 1 regular stop defined, but to avoid an exception error take the max stop_id
    gv_code_block := 'Find not moved stop';
    begin
      select nvl(max(stop.stop_id),0)
        into m_stop_id
        from stop, routecontrol rc
       where stop.routestop_id = fpi_routestop_id
         and stop.routecontrol_id = rc.routecontrol_id
         and (stop.status = 0  -- normal
         	or stop.status = 1  -- cancelled
         	or stop.status = 4) -- inactive customer
         and trunc(rc.originaldrivingdate) = trunc(fpi_date);
    end;

    if m_stop_id is null then m_stop_id := 0; end if;

    if m_stop_id = 0 then
      -- step 2: Check if the stop was moved out
      gv_code_block := 'Find moved stop';
      m_movedtostop_id := 0;
      begin
        select nvl(max(stop.movedtostop_id),0)
          into m_movedtostop_id
          from stop, routecontrol rc
         where stop.routestop_id = fpi_routestop_id
           and stop.routecontrol_id = rc.routecontrol_id
           and stop.status = 2  --moved out
           and trunc(rc.originaldrivingdate) = trunc(fpi_date);
      end;
      -- step 3: A stop can be moved more than once. so follow the chain until the end.
      gv_code_block := 'Loop moved stop';
      while m_movedtostop_id <> 0 loop
        begin
          select stop.stop_id,
                 nvl(stop.movedtostop_id, 0)
            into m_stop_id,
                 m_movedtostop_id
            from routecontrol rc, stop
           where stop.stop_id = m_movedtostop_id
             and stop.routestop_id = fpi_routestop_id
             and stop.routecontrol_id = rc.routecontrol_id
             and (stop.status = 2   -- moved out
             	or stop.status = 3); -- moved in
        exception
           when no_data_found then
        	-- To make sure the loop is ending, the stop can be moved several times and then cancelled in the end.
           	m_movedtostop_id := 0;
          	m_stop_id := 0;
        end;
      end loop;
    end if; -- m_stop_id = 0

    if m_stop_id = 0 then
    gv_code_block := 'Find moved-in stop';--consider the moved-in stop for fpi_date if a normal or moved does not exist
    begin
      select nvl(max(stop.stop_id),0)
        into m_stop_id
        from stop, routecontrol rc
       where stop.routestop_id = fpi_routestop_id
         and stop.routecontrol_id = rc.routecontrol_id
         and (stop.status = 3 )  -- moved-in
         and trunc(rc.originaldrivingdate) = trunc(fpi_date);
    end;
    end if;

    if m_stop_id > 0 then
      begin
    	-- step 4: determine the route, routecontrol and driving date from the stop
      gv_code_block := 'Load stop details';
      select rc.route_id,
             rc.routecontrol_id,
             rc.drivingdate, -- note that we load realdriving date, not original drivingdate
             stop.status,
             rc.invoicesgenerated
        into fpo_route_id,
             fpo_routecontrol_id,
             fpo_drivingdate,
             fpo_status,
             m_invoicesgenerated
        from stop
        join routecontrol rc
          on rc.routecontrol_id = stop.routecontrol_id
       where stop.stop_id = m_stop_id;
       if fpi_invoicesgenerated = 1 and m_invoicesgenerated > 1 then
         begin
           fpo_routecontrol_id := null;
           fpo_status := 5; --Routecontrol.InvoicesGenerated = 1
         end;
       end if;
       end;
    end if; -- m_stop_id > 0

  writedebuglog(fpi_log,m_proc,'outputparams: stop_id=' || m_stop_id || ' drivingdate=' || to_char(fpo_drivingdate,'DD-MON-YYYY') || ' stopstatus=' || fpo_status);

  fpo_stop_id := m_stop_id;

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; -- findstopforroutestop

--------------------------------------------------------------
function weekinperiod(
                fpi_date	          in date,
                fpi_freq              in number,
                fpi_offset            in number,
                fpi_log               in varchar2,
                fpo_firstnextdate     in out date)
return boolean is
-- returns false when fpi_date delivery is not in period week for specified fpi_freq and fpi_offset.
  m_proc                 varchar2(30);
  m_year                 number;
  m_week                 number;
  m_firstweek            number;
  m_weekinperiod         number;
--  m_firstnextdate        date;
begin
  m_proc := '----weekinperiod';
  writedebuglog(fpi_log,m_proc,'inputparams: fpi_date=' || to_char(fpi_date,'DD-MON-YYYY') || ',fpi_freq=' || fpi_freq || ',fpi_offset=' || fpi_offset || ',fpo_firstnextdate=' || to_char(fpo_firstnextdate,'DD-MON-YYYY'));
  m_year := getyearofweek(fpi_date);
  m_week := getisoweek(fpi_date);
  m_firstweek := getfirstdeliveryweekforyear(m_year, fpi_freq, fpi_offset);
  m_weekinperiod := ((m_week - m_firstweek) mod fpi_freq);
  if (m_weekinperiod < 0) then
    m_weekinperiod := m_weekinperiod + fpi_freq;
  end if;
  if (m_weekinperiod > 0) then
 -- The Date is not in a week that coincides with a week from the delivery scheme
 -- For example the customer has a 4 weekly delivery scheme, first week is week 2.
 -- Delivery weeks are 2, 6, 10, 14, 18, 22, 26, 30, 34, ?
 -- Date is in week 31. This date does not correspond with the delivery scheme
 -- because (31 - 2) mod 4 = 1.
 -- So the date is in week 1 of the period. The first delivery is
 -- (Nr of weeks in period - week number) * 7 = (4 - 1) * 7 = 21
 -- So the first next date is the date + 21 days (week 34).

/*    m_firstnextdate := fpi_date + 7 * (fpi_freq - m_weekinperiod);
    if (m_firstnextdate < fpo_firstnextdate) then
      fpo_firstnextdate := m_firstnextdate;
    end if;
*/
    fpo_firstnextdate := fpi_date + 7 * (fpi_freq - m_weekinperiod);

    writedebuglog(fpi_log,m_proc,'Not valid: Not delivered this week.  Frequency=' || fpi_freq || ' Offset=' || fpi_offset ||
                          ' Year=' || m_year || ' Week=' || m_week || ' FirstWeek=' || m_firstweek || ' FirstNextDate=' || to_char(fpo_firstnextdate,'DD-MON-YYYY'));
  end if; -- m_weekinperiod > 0
  writedebuglog(fpi_log,m_proc,'outputparams: fpo_firstnextdate=' || to_char(fpo_firstnextdate,'DD-MON-YYYY'));
  return (m_weekinperiod = 0);
end; ---- weekinperiod

--------------------------------------------------------------
function  routestopvalid(fpi_routestop_id	     in number,
                         fpi_delpoint_id	     in number,
                         fpi_department_id	   in number,
                         fpi_typeofmerch	     in number,
                         fpi_date	             in date,
                         fpi_basedate          in date,
                         fpi_plpc_id	         in number,
                         fpi_distribpoint_id	 in number,
                         fpi_deeds_frequency     in number,
                         fpi_deeds_offset        in number,
                         fpi_log	             in varchar2,
                         fpi_delivery          in boolean,
                         fpo_firstnextdate     out date,
                         fpo_route_id	         out number,
                         fpo_stop_id	         out number,
                         fpo_routecontrol_id	 out number,
                         fpo_realdriving_date  out date,
                         fpi_invoicesgenerated in number default null) return boolean is
-- returns false when route stop is not valid for delivery at specified date.
m_proc                   varchar2(30);
m_stop_id                number;
m_route_id               number;
m_routecontrol_id        number;
m_realroute_id           number;
m_customer_id            number;
m_deliverypoint_id       number;
m_drivingday_id          number;
m_stoptype               number;
m_routestop_dateactive   date;
m_routestop_dateinactive date;
m_typeofmerch            number;
m_plant_id               number;
m_routefreq              number;
m_routeoffset            number;
m_deldaytomcount         number;
m_realdrivingdate        date;
m_found                  number;
m_dummy                  number;
m_freq                   number;
m_offset                 number;
m_status                 number;
m_is_weekinperiod        boolean;
m_firstnextdate          date;
m_last_firstnextdate     date;

begin
  begin -- main exception block
    m_proc := '---routestopvalid';
    gv_code_block := 'Init';
    writedebuglog(fpi_log,m_proc,'inputparams: routestop=' || fpi_routestop_id || ',delp=' || fpi_delpoint_id ||
                  ',dep=' || fpi_department_id || ',tom=' || fpi_typeofmerch || ',date=' || to_char(fpi_date,'DD-MON-YYYY') ||
                  ',basedate=' || to_char(fpi_basedate,'DD-MON-YYYY') || ',plpc=' || fpi_plpc_id || ',dip=' || fpi_distribpoint_id);

    m_stop_id         := 0;
    m_routecontrol_id := 0;
    m_customer_id     := 0;
    m_realdrivingdate := gv_max_date;
    m_found           := 1;

    fpo_route_id	       := 0;
    fpo_stop_id	         := 0;
    fpo_routecontrol_id	 := 0;
    fpo_firstnextdate    := gv_max_date;
    fpo_realdriving_date := gv_max_date;
    m_freq               := 1;
    m_offset             := 0;
    m_is_weekinperiod    := false;
    m_firstnextdate      := fpo_firstnextdate;
    m_last_firstnextdate := fpo_firstnextdate;

    gv_code_block := 'Load routestop';
    begin
      select rs.customer_id,
             nvl(rs.deliverypoint_id, 0),
             route.drivingday_id,
             rs.stoptype,
             rs.dateactive,
             rs.dateinactive,
             route.plant_id,
             route.route_id,
             ds.frequency,
             ds.offsetweek
        into m_customer_id,
             m_deliverypoint_id,
             m_drivingday_id,
             m_stoptype,
             m_routestop_dateactive,
             m_routestop_dateinactive,
             m_plant_id,
             m_route_id,
             m_routefreq,
             m_routeoffset
        from routestop rs, route, deliveryscheme ds
       where rs.routestop_id = fpi_routestop_id
         and route.route_id = rs.route_id
         and ds.deliveryscheme_id = route.deliveryscheme_id;
    exception
        when no_data_found then
              m_found := 0;
    end;

    if m_found = 0 then
      writedebuglog(fpi_log,m_proc,'Not valid: No routestop or deliveryschemes per routestop found');
    	return(false);
    end if;

    -- get stop is for pick up, not for delivery
    if fpi_delivery and ((m_stoptype = 2) /*get*/ or (m_stoptype = 4)) /*incidental*/ then
      writedebuglog(fpi_log,m_proc,'Not valid: Not a delivery stop. Stop Type=' || m_stoptype);
    	return(false);
    else
      if not fpi_delivery then
         if m_stoptype = 1 then
            writedebuglog(fpi_log,m_proc,'Not valid: Not a delivery stop. Stop Type=' || m_stoptype);
    	      return(false);
         end if;
      end if;
    end if;

    -- stop not yet active
    if m_routestop_dateactive > fpi_date then
      writedebuglog(fpi_log,m_proc,'Not valid: Stop not yet active. Date Active=' || m_routestop_dateactive);
    	return(false);
    end if;

    -- stop is inactive
    if m_routestop_dateinactive < fpi_date then
      writedebuglog(fpi_log,m_proc,'Not valid: Stop no longer active. Date Inactive=' || m_routestop_dateinactive);
    	return(false);
    end if;

   -- delivery point does not match.
   if fpi_delpoint_id is not null	and m_deliverypoint_id <> 0	and m_deliverypoint_id <> fpi_delpoint_id then
      writedebuglog(fpi_log,m_proc,'Not valid: Wrong delivery point. Deliverypoint_id=' || m_deliverypoint_id);
    	return(false);
   end if;

   -- stop is not a delivery day for the type of merchandize
   gv_code_block := 'Check Customer Delivery Day';
   if fpi_typeofmerch = 1 or fpi_typeofmerch = 2 or fpi_typeofmerch = 5
     then m_typeofmerch := fpi_typeofmerch;
    else	m_typeofmerch := 1;
   end if;

   begin
      select count(1)
        into m_deldaytomcount
        from customerdeliveryday cdd
       where cdd.customer_id = m_customer_id
         and cdd.day_id = m_drivingday_id
         and cdd.typeofmerchadise = m_typeofmerch
         and cdd.deliverytype <> 'P';
      if nvl(m_deldaytomcount,0) = 0 then
       begin
        writedebuglog(fpi_log,m_proc,'Not valid: No Delivery day for Type of Merchandise. TOM=' || m_typeofmerch || ' Drivingday=' ||m_drivingday_id);
       	return(false);
       end;
      end if;
   end;

  -- department is excluded from delivery on the driving day of the stop.
  if fpi_department_id is not null then
    begin
      gv_code_block := 'Check Department Delivery Day';
      m_dummy := 0;
      select 1
        into m_dummy
        from deliveryday dd
       where dd.department_id = fpi_department_id
         and dd.day_id = m_drivingday_id;
    exception
        when no_data_found then null;
    end;
    if m_dummy = 1 then
      writedebuglog(fpi_log,m_proc,'Not valid: No Delivery day for Department. Department_id=' || fpi_department_id || ' Drivingday=' ||m_drivingday_id);
    	return(false);
    end if;
  end if;

  -- product is not delivered on the driving day of the stop.
  if fpi_plpc_id is not null then
    begin
      m_dummy := 0;
      gv_code_block := 'Check Product Delivery Day';
      select 1
        into m_dummy
        from productdeliveryday pdd
       where pdd.productlistpercustomer_id = fpi_plpc_id
         and pdd.day_id = m_drivingday_id
         and pdd.deliverytype = 'P';
    exception
        when no_data_found then null;
    end;
    if m_dummy = 1 then
      writedebuglog(fpi_log,m_proc,'Not valid: Product is only for pickup at this day. plpc_ID=' || fpi_plpc_id || ' Drivingday=' ||m_drivingday_id);
    	return(false);
    end if;
  end if;

  -- check Week-in-Period for both Specific and General Customer Routing schedule and frequency
  m_is_weekinperiod := false;

  -- check and use Specific DelayedEvenExchange DeliveryScheme schedule and frequency
  -- (if any dee frequency param is passed then should consider DelayedEvenExchange delivery scheme routing)
  if (fpi_deeds_frequency <> 0) then
    gv_code_block := 'Check and use Specific DelayedEvenExchange DeliveryScheme schedule and frequency';
  	-- check Week-in-Period - whether the date matches with the frequency and offset of the product.
    m_is_weekinperiod := weekinperiod(fpi_date, fpi_deeds_frequency, fpi_deeds_offset, fpi_log, fpo_firstnextdate);
  end if;

  -- check and use General Customer Routing schedule and frequency
  -- (if previously DelayedEvenExchange checking has no Week-in-Period then should consider General Customer Routing)
  if (not m_is_weekinperiod) then
    gv_code_block := 'Check and use General Customer Routing schedule and frequency';
    begin
      select min(ds.frequency)
        into m_freq
        from deliveryschemesperstop dss, deliveryscheme ds
       where dss.routestop_id = fpi_routestop_id
         and dss.customer_id = m_customer_id
         and dss.day_id = m_drivingday_id
         and dss.deliveryscheme_id = ds.deliveryscheme_id;
    exception
      when no_data_found then null;
    end;

    if m_freq < m_routefreq then
      -- the frequence of the stop can be higher than the route frequency.
      -- in this case the route frequency should be taken.
      m_freq := m_routefreq;
      m_offset := m_routeoffset;
    end if;

    -- frequency 1 can skip this check.
    if m_freq > 1 then
      gv_code_block := gv_code_block || ' - Freq > 1';
      -- check if fpi_date delivery is in period week for specified m_freq and m_offset.
      m_last_firstnextdate := fpo_firstnextdate;
      if m_offset > 0 then
        m_is_weekinperiod := weekinperiod(fpi_date, m_freq, m_offset, fpi_log, m_last_firstnextdate);
      else
        -- check Week-in-Period for all deliveryschemes having same m_freq
        for vcursor in (select ds.offsetweek
                          from deliveryschemesperstop dss, deliveryscheme ds
                        where dss.routestop_id = fpi_routestop_id
                           and dss.customer_id = m_customer_id
                           and dss.day_id = m_drivingday_id
                           and dss.deliveryscheme_id = ds.deliveryscheme_id
                           and ds.frequency = m_freq
                      order by ds.deliveryscheme_id)
        loop
          m_offset := vcursor.offsetweek;
          m_firstnextdate := fpo_firstnextdate;
          m_is_weekinperiod := weekinperiod(fpi_date, m_freq, m_offset, fpi_log, m_firstnextdate);
          if (not m_is_weekinperiod) then
            if (m_firstnextdate < m_last_firstnextdate) then
              m_last_firstnextdate := m_firstnextdate;
            end if;
          else
            m_is_weekinperiod := true;
            exit;
          end if;
        end loop;
      end if;  --m_offset > 0
      if (not m_is_weekinperiod) then
        fpo_firstnextdate := m_last_firstnextdate;
      end if;
    end if;  --m_freq > 1
  end if; --not m_is_weekinperiod

  --return false if Week-in-Period has failed for both Specific and General Customer Routing schedule and frequency
  if ((not m_is_weekinperiod) and ((fpi_deeds_frequency <> 0) or (m_freq > 1))) then
    return false;
  end if;

  -- Determine the real stop and driving date.
  findstopforroutestop(fpi_routestop_id, m_route_id, fpi_date, fpi_log, fpi_invoicesgenerated, m_realroute_id, m_stop_id, m_routecontrol_id, m_realdrivingdate, m_status);

  -- Cancelled or inactive or moved out stop
  if m_stop_id <> 0 and
     (m_status = 1 /*cancelled*/ or
      m_status = 2 /*Moved Out*/ or
      m_status = 4 /*Inactive customer*/ or
      m_status = 5 /*Routecontrol.InvoicesGenerated = 1*/)then
    begin
      if m_deldaytomcount = 1 then
      	fpo_firstnextdate := fpi_date + m_freq * 7;
      else
        fpo_firstnextdate := fpi_date + 1;
      end if;
      writedebuglog(fpi_log,m_proc,'Not valid: Stop found with wrong status Date=' || fpi_date || ' FirstNextDate=' || fpo_firstnextdate || ' Stop Status =' || m_status);
      return(false);
    end;
  end if;

  -- Stop was moved to a date prior to the production date.
  if m_stop_id <> 0 and m_realdrivingdate < trunc(sysdate)
     and fpi_delivery  -- HVH only for delivery do this check
   then
    if m_deldaytomcount = 1 then
    	fpo_firstnextdate := fpi_date + m_freq * 7;
    else
      fpo_firstnextdate := fpi_date + 1;
    end if;
    writedebuglog(fpi_log,m_proc,'Not valid: Stop found moved to before search date Realdrivingdate=' || m_realdrivingdate || ' BaseDate=' || sysdate);
  	return(false);
  end if;

-- Driving date is a non-business day
-- Note that the REAL driving date is used to check.
-- Most customers will move a route or stop to another date in case of a non-business day.
    gv_code_block := 'Non Businessday checks';
    if fpi_department_id is not null then
      begin
        gv_code_block := 'Deparment Non Businessday';
        m_dummy := 0;
        select 1
          into m_dummy
          from nonbusinessday nbd
         where trunc(nbd.nonbusinessday) = trunc(m_realdrivingdate)
           and nbd.department_id = fpi_department_id
           and nbd.closestatus <> 3; --open
      exception
          when no_data_found then null;
      end;
      if m_dummy = 1 then
        if m_deldaytomcount = 1 then
        	fpo_firstnextdate := fpi_date + m_freq * 7;
        else
          fpo_firstnextdate := fpi_date + 1;
        end if;
        writedebuglog(fpi_log,m_proc,'Not valid: Non businessday for Deparment=' || fpi_department_id || ' at ' || m_realdrivingdate ||  ' FirstNextDate=' || fpo_firstnextdate);
      	return(false);
      end if;
    end if;

    -- Customer non business day
    begin
      gv_code_block := 'Customer Non Businessday';
      m_dummy := 0;
      select 1
        into m_dummy
        from nonbusinessday nbd
       where trunc(nbd.nonbusinessday) = trunc(m_realdrivingdate)
         and nbd.customer_id = m_customer_id
         and nbd.department_id is null
         and nbd.closestatus <> 3 --open
        and not exists
            (select 1
               from nonbusinessday nbd2
              where trunc(nbd2.nonbusinessday) = trunc(m_realdrivingdate)
                and fpi_department_id is not null
                and nbd2.department_id = fpi_department_id
                and nbd.closestatus = 3); -- open
    exception
        when no_data_found then null;
    end;
    if m_dummy = 1 then
        if m_deldaytomcount = 1 then
        	fpo_firstnextdate := fpi_date + m_freq * 7;
        else
          fpo_firstnextdate := fpi_date + 1;
        end if;
        writedebuglog(fpi_log,m_proc,'Not valid: Non businessday for Customer=' || m_customer_id || ' at ' || m_realdrivingdate ||  ' FirstNextDate=' || fpo_firstnextdate);
      	return(false);
    end if;

    -- Plant non business day
    begin
      gv_code_block := 'Plant Non Businessday';
      m_dummy := 0;
      select 1
        into m_dummy
        from nonbusinessday nbd
       where trunc(nbd.nonbusinessday) = trunc(m_realdrivingdate)
         and nbd.plant_id = m_plant_id
         and nbd.customer_id is null
         and nbd.department_id is null
         and nbd.closestatus <> 3 --open
      	 and not exists
             (select 1
                from nonbusinessday nbd2
               where trunc(nbd2.nonbusinessday) = trunc(m_realdrivingdate)
                 and nbd2.customer_id = m_customer_id
                 and nbd.department_id is null
                 and nbd2.closestatus = 3) -- open
         and not exists
             (select 1
                from nonbusinessday nbd2
               where trunc(nbd2.nonbusinessday) = trunc(m_realdrivingdate)
                 and fpi_department_id is not null
                 and nbd2.department_id = fpi_department_id
                 and nbd.closestatus = 3); -- open
    exception
        when no_data_found then null;
    end;
    if m_dummy = 1 then
      if m_deldaytomcount = 1 then
      	fpo_firstnextdate := fpi_date + m_freq * 7;
      else
        fpo_firstnextdate := fpi_date + 1;
      end if;
      writedebuglog(fpi_log,m_proc,'Not valid: Non businessday for Plant=' || m_plant_id || ' at ' || m_realdrivingdate ||  ' FirstNextDate=' || fpo_firstnextdate);
    	return(false);
    end if;

  fpo_route_id := m_realroute_id;
  fpo_stop_id := m_stop_id;
  fpo_routecontrol_id := m_routecontrol_id;
  fpo_realdriving_date := m_realdrivingdate;

  writedebuglog(fpi_log,m_proc,'outputparams: true  stop_id=' || m_stop_id || ' realdrivingdate=' || to_char(m_realdrivingdate,'DD-MON-YYYY'));
  -- If all conditions are valid then the Routestop is valid
  Return(true);

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; -- routestopvalid

--------------------------------------------------------------
function  getfirstdeliverydateforstop(fpi_routestop_id	   in number,
                                      fpi_delpoint_id	     in number,
                                      fpi_department_id	   in number,
                                      fpi_typeofmerch	     in number,
                                      fpi_date	           in date,
                                      fpi_plpc_id	         in number,
                                      fpi_distribpoint_id	 in number,
                                      fpi_deeds_frequency    in number,
                                      fpi_deeds_offset       in number,
                                      fpi_log	             in varchar2,
                                      fpo_route_id	       out number,
                                      fpo_stop_id	         out number,
                                      fpo_routecontrol_id	 out number,
                                      fpo_realdriving_date out date,
                                      fpi_invoicesgenerated in number) return date is
-- returns 31-12-2099  if no visit date
m_proc             varchar2(30);
m_route_id         number;
m_stop_id          number;
m_routecontrol_id  number;
m_realdrivingdate  date;
m_firstvisitdate   date;
m_nextdate         date;
m_found            boolean;

begin
  begin -- main exception block
    m_proc := '--getfirstdeliverydateforstop';
    gv_code_block := 'Init';
    writedebuglog(fpi_log,m_proc,'inputparams: routestop=' || fpi_routestop_id || ',delp=' || fpi_delpoint_id ||
                  ',dept=' || fpi_department_id || ',tom=' || fpi_typeofmerch || ',date=' || to_char(fpi_date,'DD-MON-YYYY') ||
                  ',plpc=' || fpi_plpc_id || ',dip=' || fpi_distribpoint_id);

    m_route_id := 0;
    m_stop_id := 0;
    m_routecontrol_id := 0;
    m_realdrivingdate := gv_max_date;
    m_firstvisitdate := fpi_date;
    m_found := false;
    gv_code_block := 'While loop';
    while not m_found and m_firstvisitdate <> gv_max_date loop
      writedebuglog(fpi_log,m_proc,'loop: trydate=' || to_char(m_firstvisitdate,'DD-MON-YYYY'));

      -- fpi_date is passed as the base date, which remains unchanged.
      m_found := routestopvalid(fpi_routestop_id, fpi_delpoint_id, fpi_department_id, fpi_typeofmerch,
                                           m_firstvisitdate, fpi_date, fpi_plpc_id, fpi_distribpoint_id,
                                           fpi_deeds_frequency, fpi_deeds_offset, fpi_log,true,
                                           m_nextdate, m_route_id, m_stop_id, m_routecontrol_id, m_realdrivingdate, fpi_invoicesgenerated);

      writedebuglog(fpi_log,m_proc,'loop: firstvisitdate=' || to_char(m_firstvisitdate,'DD-MON-YYYY') || ' nextdate=' || to_char(m_nextdate,'DD-MON-YYYY'));
      if not m_found then
      		-- m_nextdate returns either the following possible date or 31-12-2099
      		-- if there is no valid date for this stop.
      		m_firstvisitdate := m_nextdate;
     	end if; -- (m_found)
    end loop;

    fpo_route_id := m_route_id;
    fpo_stop_id := m_stop_id;
    fpo_routecontrol_id := m_routecontrol_id;
    fpo_realdriving_date := m_realdrivingdate;

    if m_realdrivingdate <> gv_max_date
      then m_nextdate := m_realdrivingdate;
      else m_nextdate := m_firstvisitdate;
    end if;

    writedebuglog(fpi_log,m_proc,'outputparams: deldate=' || to_char(m_nextdate,'DD-MON-YYYY') || ' stop_id=' || fpo_stop_id);

    return(m_nextdate);

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; -- getfirstdeliverydateforstop


--------------------------------------------------------------
procedure firstnextroutestop(fpi_plant_id          in number,
                             fpi_customer_id       in number,
                             fpi_delpoint_id       in number,
                             fpi_department_id     in number,
                             fpi_typeofmerch       in number,
                             fpi_date              in date,
                             fpi_plpc_id           in number,
                             fpi_distribpoint_id   in number,
                             fpi_deliveryscheme_id in number,
                             fpi_onlyroute_id      in number,
                             fpi_log               in varchar2,
                             fpo_routestop_id      out number,
                             fpo_route_id          out number,
                             fpo_stop_id           out number,
                             fpo_routecontrol_id   out number,
                             fpo_realdrivingdate   out date,
                             fpi_invoicesgenerated in number default null) is

-- local variables
m_proc                  varchar2(30);
m_day                   number;
m_date                  date;
m_prev_date             date;
m_firstvisitdate        date;
m_firstnextdate         date;
m_deeds_frequency       number;
m_deeds_offset          number;
m_route_id              number;
m_stop_id               number;
m_routecontrol_id       number;
m_realdrivingdate       date;
m_found                 boolean;
begin -- firstnextroutestop
  begin -- main exception block
    m_proc := '-firstnextroutestop';
    gv_code_block := 'Init';
    writedebuglog(fpi_log,m_proc,'inputparams: plant=' || fpi_plant_id || ',cust=' || fpi_customer_id || ',delp=' || fpi_delpoint_id ||
                  ',dep=' || fpi_department_id || ',tom=' || fpi_typeofmerch || ',date=' || to_char(fpi_date,'DD-MON-YYYY') ||
                  ',plpc=' || fpi_plpc_id || ',dip=' || fpi_distribpoint_id || ',delsch=' || fpi_deliveryscheme_id || ',onlyroute=' || fpi_onlyroute_id);

    m_day                   := getabsdaynumber(fpi_date);
    m_firstnextdate         := gv_max_date;
    m_deeds_frequency       := 0;
    m_deeds_offset          := 0;
    m_found                 := false;
    fpo_routestop_id        := 0;
    fpo_route_id            := 0;
    fpo_stop_id             := 0;
    fpo_routecontrol_id     := 0;
    fpo_realdrivingdate     := gv_max_date;
    m_prev_date             := gv_max_date;

    -- first check for the days including and following the requested day.
    -- for example, if checked for a wednesday, first is checked wednesday,
    -- then thursday, friday, saturday and sunday, monday and tuesday.

    --get the frequency and offset of the delayedEvenExchage deliveryScheme
    if (fpi_deliveryscheme_id is not null and fpi_deliveryscheme_id <> 0) then
       begin
         gv_code_block := 'Frequency';
         select ds.frequency,
  	          	ds.offsetweek
           into m_deeds_frequency,
         	    m_deeds_offset
           from deliveryscheme ds
       	  where ds.deliveryscheme_id = fpi_deliveryscheme_id;
       exception
         when no_data_found then null;
       end;
    end if;

   gv_code_block := 'Cursor';

   FOR vcursor IN (select rs.routestop_id,
                      		rs.route_id,
                      		route.drivingday_id,
                          case when route.drivingday_id < m_day
                               then route.drivingday_id + 7
                               else route.drivingday_id
                          end sortday
                     from routestop rs, route, customerdeliveryday cdd, deliveryscheme ds
                    where rs.route_id = route.route_id
                      and ds.deliveryscheme_id=route.deliveryscheme_id
                      and ((fpi_onlyroute_id is null)
                       or (fpi_onlyroute_id = 0)
                     	 or (rs.route_id = fpi_onlyroute_id))
                      and rs.customer_id = fpi_customer_id
                      and ((fpi_plant_id is null)
                       or (route.plant_id = fpi_plant_id))
                      and ((fpi_delpoint_id is null)
                       or (rs.deliverypoint_id is null)
                       or (rs.deliverypoint_id = fpi_delpoint_id))
                      and rs.stoptype <> 2 --get
                      and rs.stoptype <> 4 --incidental
                      and trunc(rs.dateinactive) > trunc(fpi_date)
                      and route.active = 'Y'
                      and cdd.customer_id = rs.customer_id
                      and cdd.day_id = route.drivingday_id
                      and cdd.typeofmerchadise = fpi_typeofmerch
                      and route.drivingday_id not in  (select dd.day_id from deliveryday dd where dd.department_id= fpi_department_id)
                    order by sortday, rs.deliverypoint_id nulls last, ds.frequency, route.routenumber, rs.stopnumber, rs.routestop_id)
   LOOP
    	if vcursor.drivingday_id < m_day
       then	m_date := fpi_date + 7 - m_day + vcursor.drivingday_id;
    	 else m_date := fpi_date - m_day + vcursor.drivingday_id;
      end if;
      if m_firstvisitdate <> gv_max_date and m_date > m_prev_date and m_date > m_firstnextdate
        then m_found := true; -- do not need to look if the scheduled date for the next stop is later then the already found date
        else
          writedebuglog(fpi_log,m_proc,'loop: routestop_id=' || vcursor.routestop_id || ' trydate=' || to_char(m_date,'DD-MON-YYYY'));
         	m_firstvisitdate := getfirstdeliverydateforstop(vcursor.routestop_id, fpi_delpoint_id, fpi_department_id, fpi_typeofmerch, m_date, fpi_plpc_id, fpi_distribpoint_id,
                                                          m_deeds_frequency,m_deeds_offset, fpi_log,m_route_id,m_stop_id,m_routecontrol_id, m_realdrivingdate, fpi_invoicesgenerated);
          writedebuglog(fpi_log,m_proc,'loop: routestop_id=' || vcursor.routestop_id || ' resultdate=' || to_char(m_date,'DD-MON-YYYY') || ' firstvisitdate=' || to_char(m_firstvisitdate,'DD-MON-YYYY'));
          if m_firstvisitdate <> gv_max_date and
             m_firstvisitdate < m_firstnextdate then
      			-- the found date is the first date sofar. however, it is possible that there are
      			-- routestops that are visited before this date. so we need to search further.
      			m_firstnextdate     := m_firstvisitdate;
            fpo_routestop_id    := vcursor.routestop_id;
            fpo_route_id        := m_route_id;
            fpo_stop_id         := m_stop_id;
            fpo_routecontrol_id := m_routecontrol_id;
            fpo_realdrivingdate := m_realdrivingdate;
        	end if; --m_firstnextdate <> gv_max_date and m_firstvisitdate < m_firstnextdate
          m_prev_date := m_date;
      end if; -- m_firstvisitdate <> gv_max_date and m_date > m_prev_date and m_date > m_firstnextdate
      exit when m_found;
   END LOOP;

  writedebuglog(fpi_log,m_proc,'outputparams: routestop_id=' || fpo_routestop_id || ' firstdeldate=' || to_char(fpo_realdrivingdate,'DD-MON-YYYY'));

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; -- firstnextroutestop

--------------------------------------------------------------
procedure checkoutmovedstopsforstop(
                            fpi_stop_id	            in out number,
                            fpi_stop_status	        in number,
                            fpi_log                 in varchar2,
                            fpo_originaldrivingdate in out date) is
m_proc           varchar2(30);
m_moved          number;

begin
  m_proc := '--checkoutmovedstopsforstop';
  writedebuglog(fpi_log,m_proc,'inputparams: fpi_stop_id=' || fpi_stop_id || ',fpi_stop_status=' || fpi_stop_status || ',fpo_originaldrivingdate=' || to_char(fpo_originaldrivingdate,'DD-MON-YYYY'));
  -- if the stop was moved in the original pick up date needs to be determined via the moved out stop.
  -- NOTE: a stop can be moved multiple times.
  if fpi_stop_status = 3 /*moved in*/ then
    fpo_originaldrivingdate := GV_MAX_DATE;
    m_moved := 1;
    while m_moved = 1 loop
      m_moved := 0;
      begin
        select   rc.originaldrivingdate,
                 stop.stop_id,
                 1
        into     fpo_originaldrivingdate,
                 fpi_stop_id,
                 m_moved
        from     routecontrol rc, stop
        where    rc.routecontrol_id = stop.routecontrol_id
        and      stop.movedtostop_id = fpi_stop_id
        and      stop.status = 2; --moved out
      exception
        when no_data_found then null;
      end;
    end loop;
    writedebuglog(fpi_log,m_proc,'moved in stop orgpickupdate=' || fpo_originaldrivingdate);
  end if;
  writedebuglog(fpi_log,m_proc,'outputparams: fpi_stop_id=' || fpi_stop_id || ',fpo_originaldrivingdate=' || to_char(fpo_originaldrivingdate,'DD-MON-YYYY'));
end; -- checkoutmovedstopsforstop

------------------------------------------------------------------------------------
function  determinepickup(fpi_plant_id           in number,
                          fpi_customer_id        in number,
                          fpi_delpoint_id        in number,
                          fpi_department_id      in number,
                          fpi_typeofmerch        in number,
                          fpi_date               in date,
                          fpi_distribpoint_id    in number,
                          fpi_log                in varchar2,
                          fpi_plpc_id            in number,
                          fpo_stop_id            out number,
                          fpo_routestop_id       out number,
                          fpo_routecontrol_id    out number,
                          fpo_route_id           out number,
                          fpo_orgpickupdate      out date,
                          fpo_pickupdate         out date,
                          fpo_movetoroutestop_id out number,
                          fpo_movetoroute_id     out number,
                          fpo_movestartdate      out date,
                          fpo_movedays           out number) return boolean is
m_proc             varchar2(30);
m_lastdate         date;
m_stop_id          number;
m_status           number;
m_found            boolean;
m_nextdate         date;
m_day              number;
m_routecontrol_id  number;
m_realdrivingdate  date;
m_route_id         number;
m_routestop_id     number;

l_deldate          date;
l_deldatenew       date;
l_stops            stops;
l_stops_counter    number;
i                  number;
l_stops_selected   varchar2(255);

begin
  begin -- main exception block
    m_proc := '-determinepickup';
    writedebuglog(fpi_log,m_proc,'inputparams: plant=' || fpi_plant_id || ',cust=' || fpi_customer_id || ',delp=' || fpi_delpoint_id ||
                  ',dept=' ||  fpi_department_id || ',tom=' || fpi_typeofmerch || ',date=' || to_char(fpi_date,'DD-MON-YYYY'));
    gv_code_block := 'Init';
    -- initialize all output parameters
    fpo_stop_id := 0;
    fpo_routestop_id := 0;
    fpo_routecontrol_id := 0;
    fpo_route_id := 0;
    fpo_orgpickupdate := gv_max_date;
    fpo_pickupdate := gv_max_date;
    fpo_movetoroutestop_id := 0;
    fpo_movetoroute_id := 0;
    fpo_movestartdate := gv_max_date;
    fpo_movedays := 0;

    -- step 1 determine the last date for which this customer had a stop.
    gv_code_block := 'Step 1';

    m_lastdate := gv_max_date;

    begin
      if FPI_PLANT_ID is null then
        select max(RC.DRIVINGDATE)
          into M_LASTDATE
          from ROUTECONTROL RC
          join STOP ST
            on RC.ROUTECONTROL_ID = ST.ROUTECONTROL_ID
          join ROUTESTOP RS
            on RS.ROUTESTOP_ID = NVL(ST.ROUTESTOP_ID, 0)
          join ROUTE RT
            on RS.ROUTE_ID = RT.ROUTE_ID
         where ST.CUSTOMER_LINK_ID = FPI_CUSTOMER_ID
           and  ST.CUSTOMER_LINK_ID = RS.CUSTOMER_ID
           and RC.Plant_Id = RT.Plant_Id
           and nvl(st.deliverypoint_id,0) = nvl(rs.deliverypoint_id,0)
           and ST.STATUS not in (1, 2) -- canceled, moved out
           and NVL(ST.STOPTYPE, 0) not in (1, 4) -- bring, incidental
           and ST.SERVICES = 0 -- all services, include regular services
           and TRUNC(RC.DRIVINGDATE) <= TRUNC(FPI_DATE)
           and (FPI_DELPOINT_ID is null or ST.DELIVERYPOINT_ID is null or
               ST.DELIVERYPOINT_ID = FPI_DELPOINT_ID)
           and RT.DRIVINGDAY_ID in
               ((select CDD.DAY_ID
                  from CUSTOMERDELIVERYDAY CDD
                 where CDD.CUSTOMER_ID = ST.CUSTOMER_LINK_ID
                   and CDD.TYPEOFMERCHADISE = FPI_TYPEOFMERCH)
                minus
               (select DD.DAY_ID
                  from DELIVERYDAY DD
                 where DD.DEPARTMENT_ID = FPI_DEPARTMENT_ID));
      else
        select max(RC.DRIVINGDATE)
          into M_LASTDATE
          from ROUTECONTROL RC
          join STOP ST
            on RC.ROUTECONTROL_ID = ST.ROUTECONTROL_ID
          join ROUTESTOP RS
            on RS.ROUTESTOP_ID = NVL(ST.ROUTESTOP_ID, 0)
          join ROUTE RT
            on RS.ROUTE_ID = RT.ROUTE_ID
         where ST.CUSTOMER_LINK_ID = FPI_CUSTOMER_ID
           and RC.PLANT_ID = FPI_PLANT_ID
           and ST.CUSTOMER_LINK_ID = RS.CUSTOMER_ID
           and RC.Plant_Id = RT.Plant_Id
           and nvl(st.deliverypoint_id,0) = nvl(rs.deliverypoint_id,0)
           and ST.STATUS not in (1, 2) -- cancelled, moved out
           and NVL(ST.STOPTYPE, 0) not in (1, 4) -- bring, incidental
           and ST.SERVICES = 0 -- all services, include regular services
           and TRUNC(RC.DRIVINGDATE) <= TRUNC(FPI_DATE)
           and (FPI_DELPOINT_ID is null or ST.DELIVERYPOINT_ID is null or
               ST.DELIVERYPOINT_ID = FPI_DELPOINT_ID)
           and RT.DRIVINGDAY_ID in
               ((select CDD.DAY_ID
                  from CUSTOMERDELIVERYDAY CDD
                 where CDD.CUSTOMER_ID = ST.CUSTOMER_LINK_ID
                   and CDD.TYPEOFMERCHADISE = FPI_TYPEOFMERCH)
           minus
               (select DD.DAY_ID
                  from DELIVERYDAY DD
                 where DD.DEPARTMENT_ID = FPI_DEPARTMENT_ID));
      end if;
    exception
      when NO_DATA_FOUND then
        null;
    end;

    if m_lastdate <> gv_max_date then
      writedebuglog(fpi_log,m_proc,'lastdate=' || m_lastdate);

      gv_code_block := 'Step 2';
      -- step 2: determine the stop number for the last date. there can be more than one stop for
      -- the customer on the same day. if there is an exact match on delivery point then this has the first priority.

      l_stops.DELETE();
      l_stops_counter := 0;

      -- first priority look for exact match on delivery point
      if (fpi_delpoint_id is not null) then
        BEGIN
          l_deldate := GV_MAX_DATE;
          FOR VCURSOR IN (SELECT STOP.STOP_ID,
                                 RC.DRIVINGDATE,
                                 NVL(STOP.ROUTESTOP_ID, 0) ROUTESTOP_ID
                            FROM ROUTECONTROL RC, STOP, ROUTE
                           WHERE STOP.ROUTECONTROL_ID = RC.ROUTECONTROL_ID
                             AND STOP.CUSTOMER_LINK_ID = fpi_customer_id
                             AND (fpi_plant_id IS NULL OR RC.PLANT_ID = fpi_plant_id)
                             AND STOP.STATUS <> 1 -- cancelled
                             AND STOP.STATUS <> 2 -- moved out
                             AND STOP.STOPTYPE <> 1 -- bring
                             AND STOP.STOPTYPE <> 4 -- incidental
                             AND STOP.SERVICES = 0 -- all services, include regular services
                             AND TRUNC(RC.DRIVINGDATE) = TRUNC(m_lastdate)
                             AND STOP.DELIVERYPOINT_ID = fpi_delpoint_id
                             AND ROUTE.ROUTE_ID = RC.ROUTE_ID) LOOP
            firstnextroutestop(fpi_plant_id,
                             fpi_customer_id,
                             fpi_delpoint_id,
                             fpi_department_id,
                             fpi_typeofmerch,
                             fpi_date,
                             fpi_plpc_id,
                             fpi_distribpoint_id,
                             null,
                             0,
                             fpi_log,
                             m_routestop_id,
                             m_route_id,
                             m_stop_id,
                             m_routecontrol_id,
                             l_deldatenew);
/*            IF (VCURSOR.ROUTESTOP_ID <> 0) THEN
              l_deldatenew := GETFIRSTDELIVERYDATEFORSTOP(VCURSOR.ROUTESTOP_ID,
                                                       FPI_DELPOINT_ID,
                                                       FPI_DEPARTMENT_ID,
                                                       FPI_TYPEOFMERCH,
                                                       VCURSOR.DRIVINGDATE,
                                                       FPI_PLPC_ID,
                                                       FPI_DISTRIBPOINT_ID,
                                                       0,
                                                       0,
                                                       FPI_LOG,
                                                       m_route_id,
                                                       m_stop_id,
                                                       m_routecontrol_id,
                                                       m_realdrivingdate);
            ELSE
              l_deldatenew := GV_MAX_DATE;
            END IF;*/

			IF (l_deldatenew < l_deldate) THEN
               l_stops.DELETE();
               l_stops_counter := 1;
               l_stops(l_stops_counter) := VCURSOR.STOP_ID;
               l_deldate := l_deldatenew;
            ELSIF ((l_deldate != GV_MAX_DATE) AND (l_deldatenew = l_deldate)) THEN
              l_stops_counter := l_stops_counter + 1;
              l_stops(l_stops_counter) := VCURSOR.STOP_ID;
            END IF;
          END LOOP;
        END;
      end if; -- param_delpoint_id is not null

      -- if exact match on delivery point not found: determine the stop without restriction on delivery point.
      if (l_stops.COUNT = 0) then
        begin
          l_deldate := GV_MAX_DATE;
          FOR VCURSOR IN (SELECT STOP.STOP_ID,
                                 RC.DRIVINGDATE,
                                 NVL(STOP.ROUTESTOP_ID, 0) ROUTESTOP_ID
                            FROM ROUTECONTROL RC, STOP, ROUTE
                           WHERE STOP.ROUTECONTROL_ID = RC.ROUTECONTROL_ID
                             AND STOP.CUSTOMER_LINK_ID = fpi_customer_id
                             AND (fpi_plant_id IS NULL OR RC.PLANT_ID = fpi_plant_id)
                             AND STOP.STATUS <> 1 -- cancelled
                             AND STOP.STATUS <> 2 -- moved out
                             AND STOP.STOPTYPE <> 1 -- bring
                             AND STOP.STOPTYPE <> 4 -- incidental
                             AND STOP.SERVICES = 0 -- all services, include regular services
                             AND TRUNC(RC.DRIVINGDATE) = TRUNC(m_lastdate)
                             AND STOP.DELIVERYPOINT_ID IS NULL
                             AND ROUTE.ROUTE_ID = RC.ROUTE_ID) LOOP
/*            IF (VCURSOR.ROUTESTOP_ID <> 0) THEN
              l_deldatenew := GETFIRSTDELIVERYDATEFORSTOP(VCURSOR.ROUTESTOP_ID,
                                                       FPI_DELPOINT_ID,
                                                       FPI_DEPARTMENT_ID,
                                                       FPI_TYPEOFMERCH,
                                                       VCURSOR.DRIVINGDATE,
                                                       FPI_PLPC_ID,
                                                       FPI_DISTRIBPOINT_ID,
                                                       0,
                                                       0,
                                                       FPI_LOG,
                                                       m_route_id,
                                                       m_stop_id,
                                                       m_routecontrol_id,
                                                       m_realdrivingdate);
            ELSE
              l_deldatenew := GV_MAX_DATE;
            END IF;*/
            firstnextroutestop(fpi_plant_id,
                             fpi_customer_id,
                             fpi_delpoint_id,
                             fpi_department_id,
                             fpi_typeofmerch,
                             fpi_date,
                             fpi_plpc_id,
                             fpi_distribpoint_id,
                             null,
                             0,
                             fpi_log,
                             m_routestop_id,
                             m_route_id,
                             m_stop_id,
                             m_routecontrol_id,
                             l_deldatenew);

			IF (l_deldatenew < l_deldate) THEN
               l_stops.DELETE();
               l_stops_counter := 1;
               l_stops(l_stops_counter) := VCURSOR.STOP_ID;
               l_deldate := l_deldatenew;
            ELSIF ((l_deldate != GV_MAX_DATE) AND (l_deldatenew = l_deldate)) THEN
              l_stops_counter := l_stops_counter + 1;
              l_stops(l_stops_counter) := VCURSOR.STOP_ID;
            END IF;
          END LOOP;
        end;
      end if; -- l_stops.COUNT = 0

      if (l_stops.COUNT > 0) then
     -- step 3 select the data from the found stop_id
        gv_code_block := 'Step 3';

     -- determine in selected stop list the stop having the closest deldate
        l_stops_counter := 0;
        l_deldate := NULL;
        l_stops_selected := '';

        for i in l_stops.FIRST .. l_stops.LAST loop
          m_stop_id:= l_stops(i);
          l_stops_selected := l_stops_selected || ' stop_id=' || m_stop_id || ';';

          begin
            select rc.drivingdate,
                   nvl(stop.status, 0)
              into l_deldatenew,
                   m_status
              from routecontrol rc,
                   stop,
                   routestop rs
             where stop.stop_id = m_stop_id
               and rc.routecontrol_id = stop.routecontrol_id
               and rs.routestop_id = stop.routestop_id;
          exception
            when no_data_found then null;
          end;

       -- the stop could be a moved one
          CHECKOUTMOVEDSTOPSFORSTOP(m_stop_id, m_status, fpi_log, l_deldatenew);

          if ((l_deldate IS NULL) OR ((l_deldate IS NOT NULL) and (l_deldatenew < l_deldate))) then
            l_stops_counter := i;
            l_deldate := l_deldatenew;
          end if;
        end loop;
        writedebuglog(fpi_log,m_proc,'for selected same deldate stops=' || l_stops_selected);

        m_stop_id := l_stops(l_stops_counter);
        writedebuglog(fpi_log,m_proc,'has determined stop_id=' || m_stop_id);

     -- finally, load the data the procedure should return for the determined stop_id
        begin
          select rc.originaldrivingdate,
                 rc.drivingdate,
          			 nvl(stop.stop_id, 0),
                 nvl(stop.routestop_id, 0),
                 nvl(stop.routecontrol_id, 0),
                 nvl(rc.route_id, 0),
                 nvl(stop.status, 0),
                 nvl(rs1.movedroutestop_id, 0),
                 case when rs1.movedroutestop_id is null
                 then 0
                 else nvl((select rs2.route_id
                               from routestop rs2
                               where rs2.routestop_id = rs1.movedroutestop_id), 0)
                 end,
                 nvl(rs1.dateinactive,gv_max_date),
                 case when rs1.movedroutestop_id is null
                   then 0
                   else nvl((select r1.drivingday_id - r2.drivingday_id
                               from routestop rs2,
                                    route r2
                              where rs2.routestop_id = rs1.movedroutestop_id
                                and r2.route_id = rs2.route_id),0)
                 end
            into fpo_orgpickupdate,
                 fpo_pickupdate,
                 fpo_stop_id,
                 fpo_routestop_id,
                 fpo_routecontrol_id,
                 fpo_route_id,
                 m_status,
                 fpo_movetoroutestop_id,
                 fpo_movetoroute_id,
                 fpo_movestartdate,
                 fpo_movedays
         from routecontrol rc,
               stop,
               routestop rs1,
               route r1
         where stop.stop_id = m_stop_id
           and rc.routecontrol_id = stop.routecontrol_id
           and rs1.routestop_id = stop.routestop_id
           and r1.route_id = rc.route_id;
        exception
          when no_data_found then null;
        end;

     -- the stop could be a moved one
        CHECKOUTMOVEDSTOPSFORSTOP(m_stop_id, m_status, fpi_log, fpo_orgpickupdate);

      end if; -- l_stops.COUNT > 0

    else
      -- M_LastDate = 31-12-2099
	  -- In case of first delivery then the route and date are determined based on the route schedule
      m_day := getabsdaynumber(fpi_date);

      FOR vcursor IN (select rs.routestop_id,
                      		   rs.route_id,
                      		   route.drivingday_id,
                             case when route.drivingday_id > m_day -- HVH  changed < into >
                                  then route.drivingday_id - 7   -- HVH change plus into minus
                                  else route.drivingday_id
                              end sortday
                        from routestop rs, route, customerdeliveryday cdd
                       where rs.route_id = route.route_id
                         and rs.customer_id = fpi_customer_id
                         and ((fpi_plant_id is null)
                          or (route.plant_id = fpi_plant_id))
                         and ((fpi_delpoint_id is null)
                          or (rs.deliverypoint_id is null)
                       or (rs.deliverypoint_id = fpi_delpoint_id))
                      and trunc(rs.dateinactive) > trunc(fpi_date)
                      and trunc(rs.dateactive) <= trunc(fpi_date)
                      and rs.stoptype <> 1 --bring
                      and route.active = 'Y'
                      and cdd.customer_id = rs.customer_id
                      and cdd.day_id = route.drivingday_id
                      and cdd.typeofmerchadise = fpi_typeofmerch
                     order by sortday desc, rs.deliverypoint_id nulls last, route.routenumber, rs.stopnumber, rs.routestop_id)
      LOOP
/* HVH */
         m_lastdate := fpi_date - m_day + vcursor.sortday;
/*
         if vcursor.drivingday_id > m_day
         then	m_lastdate := fpi_date + 7 - m_day + vcursor.drivingday_id;
    	   else m_lastdate := fpi_date - m_day + vcursor.drivingday_id;
         end if;
*/
         m_found := routestopvalid(vcursor.routestop_id, fpi_delpoint_id, fpi_department_id, fpi_typeofmerch,
                                   m_lastdate, fpi_date, /*fpi_typeofmerch*/ null, fpi_distribpoint_id, -- HVH not pass tom to plpc_id
                                   0, 0, fpi_log,false, m_nextdate, m_route_id, m_stop_id, m_routecontrol_id,
                                   m_realdrivingdate);

         writedebuglog(fpi_log,m_proc,'loop: routestop_id=' || vcursor.routestop_id || ' resultdate=' || to_char(fpi_date,'DD-MON-YYYY') || ' firstvisitdate=' || to_char(m_lastdate,'DD-MON-YYYY'));
         if m_found then
      	 -- the found date is the first date sofar. however, it is possible that there are
      	 -- routestops that are visited before this date. so we need to search further.
      	    fpo_routestop_id    := vcursor.routestop_id;
            fpo_route_id        := m_route_id;
            fpo_stop_id         := m_stop_id;
            fpo_routecontrol_id := m_routecontrol_id;
            fpo_pickupdate      := m_realdrivingdate;
            fpo_orgpickupdate   := m_realdrivingdate;
         end if; --m_firstnextdate <> gv_max_date and m_firstvisitdate < m_firstnextdate
        exit when m_found;
      end loop;
      return(fpo_routestop_id <> 0);
    end if; -- m_lastdate <> gv_max_date (31-12-2099)

    writedebuglog(fpi_log,m_proc,'outputparams: stop_id=' || fpo_stop_id || ',orgpickupdate=' || fpo_orgpickupdate || ',realpickupdate=' || fpo_pickupdate);

    return(fpo_stop_id <> 0);

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
      return(false);
    end;
  end;
end; -- determinepickup

--------------------------------------------------------------------------------------------
procedure determinedeldateroutesoil(fpi_plant_id           in number,
                                    fpi_customer_id        in number,
                                    fpi_delpoint_id        in number,
                                    fpi_department_id      in number,
                                    fpi_typeofmerch        in number,
                                    fpi_date               in date,
                                    fpi_plpc_id            in number,
                                    fpi_distribpoint_id    in number,
                                    fpi_log                in varchar2,
                                    fpo_inroute_id         out number,
                                    fpo_inroutestop_id     out number,
                                    fpo_inroutecontrol_id  out number,
                                    fpo_instop_id          out number,
                                    fpo_pickupdate         out date,
                                    fpo_outroute_id        out number,
                                    fpo_outroutestop_id    out number,
                                    fpo_outroutecontrol_id out number,
                                    fpo_outstop_id         out number,
                                    fpo_outdrivingdate     out date) is
m_proc                    varchar2(30);
m_log                     varchar2(1);
m_stop_id                 number;
m_routestop_id            number;
m_routecontrol_id         number;
m_route_id                number;
m_pickupdate              date;
m_realpickupdate          date;
m_movedtoroutestop_id     number;
m_movedtoroute_id         number;
m_movedstartdate          date;
m_movedays                number;
m_delayedevenexchange     number;
m_realdrivingdate         date;
m_dee_deliveryscheme_id       number;
m_onlyroute_id            number;
m_date                    date;
m_movestartdate           date;
m_days                    number;
m_daynr                   number;
m_returnroutestop_id      number;
m_movedroutestop_id       number;
m_startdate                    date;

begin
  begin -- main exception block
    m_log := nvl(fpi_log, 'N');
    -- uncomment this line of code to temporarely set DEBUG ON --
--  m_log := 'Y';
    --
    gv_plant_id := fpi_plant_id;
    m_proc := 'DETERMINEDELDATEROUTESOIL';
    gv_code_block := 'Initialize';
    writedebuglog(m_log,m_proc,'inputparams: plant=' || fpi_plant_id || ',cust=' || fpi_customer_id || ',delp=' || fpi_delpoint_id ||
                  ',dept=' ||  fpi_department_id || ',tom=' || fpi_typeofmerch || ',date=' || to_char(fpi_date,'DD-MON-YYYY') ||
                  ',plpc=' ||  fpi_plpc_id || ',dip=' || fpi_distribpoint_id);


    -- initialize the out parameters
    fpo_inroute_id := 0;
    fpo_inroutestop_id := 0;
    fpo_inroutecontrol_id := 0;
    fpo_instop_id := 0;
    fpo_pickupdate := gv_max_date;
    fpo_outroute_id := 0;
    fpo_outroutestop_id := 0;
    fpo_outroutecontrol_id := 0;
    fpo_outstop_id := 0;
    fpo_outdrivingdate := gv_max_date;

    gv_code_block := 'Determine Pickup';

    -- step 1: determine the incoming route:
    if determinepickup(fpi_plant_id,
                       fpi_customer_id,
                       fpi_delpoint_id,
                       fpi_department_id,
                       fpi_typeofmerch,
                       fpi_date,
                       fpi_distribpoint_id,
                       m_log,
                       fpi_plpc_id,
                       m_stop_id,
                       m_routestop_id,
                       m_routecontrol_id,
                       m_route_id,
                       m_pickupdate,
                       m_realpickupdate,
                       m_movedtoroutestop_id,
                       m_movedtoroute_id,
                       m_movedstartdate,
                       m_movedays) then

    	-- fill the incoming route output parameters.
      fpo_inroute_id := m_route_id;
      fpo_inroutestop_id := m_routestop_id;
      fpo_inroutecontrol_id := m_routecontrol_id;
      fpo_instop_id := m_stop_id;
      fpo_pickupdate := m_realpickupdate;

      m_route_id := 0;
      m_dee_deliveryscheme_id := 0;
      m_onlyroute_id := 0;

      -- step 2: determine the corresponding outgoing route
      -- note that m_pickupdate is the original pick up date, not necessarily the real pick up date.
      gv_code_block := 'Delayed even exchange';

    	m_delayedevenexchange := 0;
    	if fpi_plpc_id is not null then
          --check the deliveryscheme's for delayedevenexchange plpc having according to deliveryscheme
  	      begin
              select plpc.delayedevenexchange,
                 case when plpc.delayedevenexchange = 7
                   then plpc.deedeliveryscheme_id
                   else 0
                     end
              into m_delayedevenexchange,
                   m_dee_deliveryscheme_id
              from productlistpercustomer plpc
              where plpc.productlistpercustomer_id = fpi_plpc_id;
          exception
            when no_data_found then null;
          end;

          --check the deliveryscheme's for delayedevenexchange plpc having deedeliveryfrequency
  	      begin
            if (m_delayedevenexchange > 0 and m_dee_deliveryscheme_id = 0) then
              select *
              into   m_dee_deliveryscheme_id
              from (
                select sdl.deliveryscheme_id
                  from productlistpercustomer plpc
                  join productlistperdistribpoint pldp on pldp.product_id = plpc.product_id
                   and pldp.sizedefinition_id = plpc.sizedefinition_id
                   and pldp.finishingmethod_id = plpc.finishingmethod_id
                  join standarddeliveryline sdl on sdl.productlistpercustomer_id = plpc.productlistpercustomer_id
                   and sdl.productlistperdistribpoint_id = pldp.productlistperdistribpoint_id
                  join deliveryscheme ds on ds.deliveryscheme_id = sdl.deliveryscheme_id
                 where trunc(sdl.dateactive) <= trunc(fpi_date)
                   and trunc(sdl.dateinactive) > trunc(fpi_date)
                   and pldp.distributionpoint_id = fpi_distribpoint_id
                   and plpc.productlistpercustomer_id = fpi_plpc_id
                   and plpc.deedeliveryfrequency = 1
                 order by ds.frequency asc)
               where rownum = 1;
             end if;
          exception
            when no_data_found then null;
          end;
      end if;   -- fpi_plpc_id is not null

      case m_delayedevenexchange
      when 1 then -- next delivery
               	m_date := m_pickupdate + 1;
                if (m_dee_deliveryscheme_id > 0) then
                   m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                end if;
      when 2 then-- next week same day
              	m_date := m_pickupdate + 7;
                if (m_dee_deliveryscheme_id > 0) then
                   m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                end if;
                m_onlyroute_id := fpo_inroute_id;
              	-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                  m_onlyroute_id := m_movedtoroute_id;
                end if;
      when 3 then -- 10 day delay
              	-- needs to be worked out more in the future.
              	m_date := m_pickupdate + 10;
              	-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                end if;
      when 4 then -- return route from route schedule
              	-- only the routes for the return route are checked. this is done by adding a restriction
              	-- using m_onlyroute_id. when a route is moved then also the returnroute of the
              	-- moved stop is considered.
              	-- step 1: determine the return route and driving date
              	m_days := 7;
              	m_daynr := getabsdaynumber(m_pickupdate);
                begin
              		select route.drivingday_id,
              		       route.route_id
              		  into m_daynr,
              		       m_onlyroute_id
              		  from route, routestop rs
              		 where rs.routestop_id = m_routestop_id
              		   and route.route_id = rs.returnroute_id;
                exception
                  when no_data_found then m_onlyroute_id := 0;
                end;
              	if m_onlyroute_id = 0 then
              			-- no return route defined, route is considered its own return route
              			m_onlyroute_id := fpo_inroute_id;
                        m_date := m_pickupdate + 7;
                        if (m_dee_deliveryscheme_id > 0) then
              			   m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                        end if;
              	else
              			-- calculate the next date for the return route
              		  if m_daynr > getabsdaynumber(m_pickupdate)
                      then m_days := m_daynr - getabsdaynumber(m_pickupdate);
              		  else m_days := m_daynr + 7 - getabsdaynumber(m_pickupdate);
                      end if;
                      m_date := m_pickupdate + m_days;
                      if (m_dee_deliveryscheme_id > 0) then
                         m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                      end if;
              	end if; -- m_onlyroute_id = 0

              	-- step 2: check if there is an active routestop for the customer / deliverypoint in the
              	-- return route
              	m_returnroutestop_id := 0;
                begin
              	select nvl(max(rs.routestop_id),0)
               	  into m_returnroutestop_id
                	from routestop rs
              	 where rs.route_id = m_onlyroute_id
              	   and rs.customer_id = fpi_customer_id
              	   and (fpi_delpoint_id is null
              			or rs.deliverypoint_id is null
              			or rs.deliverypoint_id = fpi_delpoint_id)
              	   and trunc(rs.dateactive) <= trunc(m_date)
              	   and trunc(rs.dateinactive) > trunc(m_date);
                end;

              	if m_returnroutestop_id = 0 then
              			-- there is no (active) stop for the customer in the return route
              			-- step 3: check if the stop was moved
              			m_movedroutestop_id := 0;
                    begin
              			select max(rs.movedroutestop_id)
                			into m_movedroutestop_id
                			from routestop rs
                		 where rs.route_id = m_onlyroute_id
              	    	and rs.customer_id = fpi_customer_id
              			  and (fpi_delpoint_id is null
              			   or rs.deliverypoint_id is null
              				 or rs.deliverypoint_id = fpi_delpoint_id)
              			  and trunc(rs.dateinactive) <= trunc(m_date);
                    exception
                      when no_data_found then null;
                    end;

                    m_movedtoroutestop_id := m_movedroutestop_id;

              			-- step 4: go to the end of the chain of moved stops.
              			while m_movedtoroutestop_id <> 0 loop
              				begin
                        select rs.routestop_id,
                					nvl(rs.movedroutestop_id, 0),
                					rs.route_id,
                					route.drivingday_id
                				into m_returnroutestop_id,
                					m_movedtoroutestop_id,
                					m_onlyroute_id,
                					m_daynr
                				from routestop rs, route
                				where rs.routestop_id = m_movedtoroutestop_id
                				and route.route_id = rs.route_id;
              				exception when no_data_found then
              					m_movedtoroutestop_id := 0;
              					m_returnroutestop_id := 0;
              					m_daynr := 0;
              				end;
              				if m_daynr > getabsdaynumber(m_pickupdate)
                       then m_days := m_daynr - getabsdaynumber(m_pickupdate);
              				 else m_days := m_daynr + 7 - getabsdaynumber(m_pickupdate);
                      end if;
              				m_date := m_date + m_days;
                      --if found date is too far, try to find an earlier date, around sysdate
                      if m_date - 7 > sysdate
                       then m_date := m_date -7;
                      end if;
              			end loop;
              	end if; -- m_returnreturnroutestop_id = 0

              	if m_returnroutestop_id = 0 then
              			-- customer is not in the return route and there is no moved stop
              			-- will be handled in the same way as next week same day
              			m_onlyroute_id := 0;
              			m_date := m_pickupdate + 7;
              			-- if stop was moved then add correction for the new route day
              			if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
                 			m_date := m_date + m_movedays;
                    end if;
                end if; -- m_returnroutestop_id = 0
      when 5 then -- 14 day delay
              	-- determine first next route stop 14 days from pick up date
              	m_date := m_pickupdate + 14;
              	-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                end if;
      when 6 then -- 28 day delay
                -- determine first next route stop 28 days from pick up date
              	m_date := m_pickupdate + 28;
              	-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                end if;
      when 7 then -- according to the delivery scheme
                -- m_dee_deliveryscheme_id is populated in this case
                m_date := getnextdeldatedelscheme(m_pickupdate+7, m_dee_deliveryscheme_id);
              	-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                end if;
      when 8 then -- next delivery including same day
              	-- same as 1 except m_pickupdate instead of m_pickupdate + 1
              	m_date := m_pickupdate;
                if (m_dee_deliveryscheme_id > 0) then
                   m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                end if;
             		-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                end if;
      else -- take the first next route
              	m_date := fpi_date;
      end case;

      writedebuglog(m_log,m_proc,'determined theoretical deliverydate=' || to_char(m_date,'DD-MON-YYYY') || ',plpc_id=' || fpi_plpc_id || ',dee=' || m_delayedevenexchange);

      gv_code_block := 'Determine return route';

      m_startdate := m_date;
      if (trunc(m_startdate) < trunc(sysdate)) then
        m_startdate := trunc(sysdate);
        m_dee_deliveryscheme_id:= 0;
        m_onlyroute_id :=0;
        m_routestop_id:=0;
      end if;

      firstnextroutestop(fpi_plant_id,
                         fpi_customer_id,
                         fpi_delpoint_id,
                         fpi_department_id,
                         fpi_typeofmerch,
                         m_startdate,
                         fpi_plpc_id,
                         fpi_distribpoint_id,
                         m_dee_deliveryscheme_id,
                         m_onlyroute_id,
                         m_log,
                         m_routestop_id,
                         m_route_id,
                         m_stop_id,
                         m_routecontrol_id,
                         m_realdrivingdate);

      -- fill the incoming route output parameters verify if values are correct.
      if m_routestop_id = 0 then
        fpo_outroutestop_id :=null;
      else
        fpo_outroutestop_id := m_routestop_id;
      end if;

      if m_route_id = 0 then
        fpo_outroute_id :=null;
      else
        fpo_outroute_id := m_route_id;
      end if;

      if m_routecontrol_id = 0 then
        fpo_outroutecontrol_id :=null;
      else
        fpo_outroutecontrol_id := m_routecontrol_id;
      end if;

      if m_stop_id = 0 then
        fpo_outstop_id :=null;
      else
        fpo_outstop_id := m_stop_id;
      end if;

      if m_realdrivingdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_outdrivingdate :=null;
      else
        fpo_outdrivingdate := m_realdrivingdate;
      end if;
    end if; -- determinepickup


    	-- fill the incoming route output parameters verify if values are correct.
      if fpo_inroute_id = 0 then
        fpo_inroute_id := null;
      end if;
      if fpo_inroutestop_id = 0 then
        fpo_inroutestop_id := null;
      end if;
      if fpo_inroutecontrol_id = 0 then
        fpo_inroutecontrol_id := null;
      end if;
      if fpo_instop_id = 0 then
        fpo_instop_id := null;
      end if;
      if fpo_pickupdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_pickupdate :=null;
      end if;

    --	step 3: when the date could not be determined or is a date in the past. in this case take the first next visit.
    if m_routestop_id = 0 or m_realdrivingdate < fpi_date THEN

      m_startdate := fpi_date;
      if (trunc(m_startdate) < trunc(sysdate)) then
        m_startdate := trunc(sysdate);
      end if;

      firstnextroutestop(fpi_plant_id,
                         fpi_customer_id,
                         fpi_delpoint_id,
                         fpi_department_id,
                         fpi_typeofmerch,
                         m_startdate,  -- so not m_date
                         fpi_plpc_id,
                         fpi_distribpoint_id,
                         null,  -- delivery scheme
                         null,  -- only route
                         m_log,
                         m_routestop_id,
                         m_route_id,
                         m_stop_id,
                         m_routecontrol_id,
                         m_realdrivingdate);

      -- fill the incoming route output parameters verify if values are correct.
      if m_routestop_id = 0 then
        fpo_outroutestop_id :=null;
      else
        fpo_outroutestop_id := m_routestop_id;
      end if;

      if m_route_id = 0 then
        fpo_outroute_id :=null;
      else
        fpo_outroute_id := m_route_id;
      end if;

      if m_routecontrol_id = 0 then
        fpo_outroutecontrol_id :=null;
      else
        fpo_outroutecontrol_id := m_routecontrol_id;
      end if;

      if m_stop_id = 0 then
        fpo_outstop_id :=null;
      else
        fpo_outstop_id := m_stop_id;
      end if;

      if m_realdrivingdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_outdrivingdate :=null;
      else
        fpo_outdrivingdate := m_realdrivingdate;
      end if;
    end if; -- m_routestop_id = 0 or m_drivingdate < param_date
    writedebuglog(m_log,m_proc,'outputparams: routestop_id=' || m_routestop_id || ',drivingdate=' ||  to_char(fpo_outdrivingdate,'DD-MON-YYYY'));

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; --determinedeldateroutesoil
--------------------------------------------------------------------------------------------
procedure determinedeldatepwbsoil(fpi_plant_id           in number,
                                    fpi_customer_id        in number,
                                    fpi_delpoint_id        in number,
                                    fpi_department_id      in number,
                                    fpi_date               in date,
                                    fpi_distribpoint_id    in number,
                                    fpi_log                in varchar2,
                                    fpo_inroute_id         out number,
                                    fpo_inroutestop_id     out number,
                                    fpo_inroutecontrol_id  out number,
                                    fpo_instop_id          out number,
                                    fpo_pickupdate         out date,
                                    fpo_outroute_id        out number,
                                    fpo_outroutestop_id    out number,
                                    fpo_outroutecontrol_id out number,
                                    fpo_outstop_id         out number,
                                    fpo_outdrivingdate     out date) is
m_proc                    varchar2(30);
m_log                     varchar2(1);
m_stop_id                 number;
m_routestop_id            number;
m_routecontrol_id         number;
m_route_id                number;
m_pickupdate              date;
m_realpickupdate          date;
m_movedtoroutestop_id     number;
m_movedtoroute_id         number;
m_movedstartdate          date;
m_movedays                number;
m_returnitems             number;
m_realdrivingdate         date;
m_deliveryscheme_id       number;
m_onlyroute_id            number;
m_date                    date;
m_movestartdate           date;
m_days                    number;
m_daynr                   number;
m_returnroutestop_id      number;
m_movedroutestop_id       number;
m_startdate                    date;

begin
  begin -- main exception block
    m_log := nvl(fpi_log, 'N');
    -- uncomment this line of code to temporarely set DEBUG ON --
--  m_log := 'Y';
    --
    gv_plant_id := fpi_plant_id;
    m_proc := 'DETERMINEDELDATEPWBSOIL';
    gv_code_block := 'Initialize';
    writedebuglog(m_log,m_proc,'inputparams: plant=' || fpi_plant_id || ',cust=' || fpi_customer_id || ',delp=' || fpi_delpoint_id ||
                  ',dept=' ||  fpi_department_id || ',tom=' || 'residential' || ',date=' || to_char(fpi_date,'DD-MON-YYYY') ||
                  ',dip=' || fpi_distribpoint_id);


    -- initialize the out parameters
    fpo_inroute_id := 0;
    fpo_inroutestop_id := 0;
    fpo_inroutecontrol_id := 0;
    fpo_instop_id := 0;
    fpo_pickupdate := gv_max_date;
    fpo_outroute_id := 0;
    fpo_outroutestop_id := 0;
    fpo_outroutecontrol_id := 0;
    fpo_outstop_id := 0;
    fpo_outdrivingdate := gv_max_date;

    gv_code_block := 'Determine Pickup';

    -- step 1: determine the incoming route:
    if determinepickup(fpi_plant_id,
                       fpi_customer_id,
                       fpi_delpoint_id,
                       fpi_department_id,
                       5,--fpi_typeofmerch,
                       fpi_date,
                       fpi_distribpoint_id,
                       m_log,
                      -1,
                       m_stop_id,
                       m_routestop_id,
                       m_routecontrol_id,
                       m_route_id,
                       m_pickupdate,
                       m_realpickupdate,
                       m_movedtoroutestop_id,
                       m_movedtoroute_id,
                       m_movedstartdate,
                       m_movedays) then

    	-- fill the incoming route output parameters.
      fpo_inroute_id := m_route_id;
      fpo_inroutestop_id := m_routestop_id;
      fpo_inroutecontrol_id := m_routecontrol_id;
      fpo_instop_id := m_stop_id;
      fpo_pickupdate := m_realpickupdate;

      m_route_id := 0;
      m_deliveryscheme_id := 0;
      m_onlyroute_id := 0;

      -- step 2: determine the corresponding outgoing route
      -- note that m_pickupdate is the original pick up date, not necessarily the real pick up date.
      gv_code_block := 'Delayed even exchange';

    	m_returnitems := 0;
    	if fpi_customer_id  is not null then
        begin
           select crs.returnitems
           into m_returnitems
           from customerresidentialsettings crs
           where crs.customer_id=fpi_customer_id ;
             exception
          when no_data_found then null;
        end;
      end if;   -- fpi_customer_id

      case m_returnitems
      when 1 then -- next delivery
               	m_date := m_pickupdate + 1;
      when 2 then-- next week same day
              	m_date := m_pickupdate + 7;
                m_onlyroute_id := fpo_inroute_id;
              	-- if stop was moved then add correction for the new route day
              	if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
              		m_date := m_date + m_movedays;
                  m_onlyroute_id := m_movedtoroute_id;
                end if;
      when 3 then -- return route from route schedule
              	-- only the routes for the return route are checked. this is done by adding a restriction
              	-- using m_onlyroute_id. when a route is moved then also the returnroute of the
              	-- moved stop is considered.
              	-- step 1: determine the return route and driving date
              	m_days := 7;
              	m_daynr := getabsdaynumber(m_pickupdate);
                begin
              		select route.drivingday_id,
              		       route.route_id
              		  into m_daynr,
              		       m_onlyroute_id
              		  from route, routestop rs
              		 where rs.routestop_id = m_routestop_id
              		   and route.route_id = rs.returnroute_id;
                exception
                  when no_data_found then m_onlyroute_id := 0;
                end;
              	if m_onlyroute_id = 0 then
              			-- no return route defined, route is considered its own return route
              			m_onlyroute_id := fpo_inroute_id;
              			m_date := m_pickupdate + 7;
              	else
              			-- calculate the next date for the return route
              			if m_daynr > getabsdaynumber(m_pickupdate)
                      then m_days := m_daynr - getabsdaynumber(m_pickupdate);
              			  else m_days := m_daynr + 7 - getabsdaynumber(m_pickupdate);
                    end if;
              			m_date := m_pickupdate + m_days;
              	end if; -- m_onlyroute_id = 0

              	-- step 2: check if there is an active routestop for the customer / deliverypoint in the
              	-- return route
              	m_returnroutestop_id := 0;
                begin
              	select nvl(max(rs.routestop_id),0)
               	  into m_returnroutestop_id
                	from routestop rs
              	 where rs.route_id = m_onlyroute_id
              	   and rs.customer_id = fpi_customer_id
              	   and (fpi_delpoint_id is null
              			or rs.deliverypoint_id is null
              			or rs.deliverypoint_id = fpi_delpoint_id)
              	   and trunc(rs.dateactive) <= trunc(m_date)
              	   and trunc(rs.dateinactive) > trunc(m_date);
                end;
              	if m_returnroutestop_id = 0 then
              			-- there is no (active) stop for the customer in the return route
              			-- step 3: check if the stop was moved
              			m_movedroutestop_id := 0;
                    begin
              			select max(rs.movedroutestop_id)
                			into m_movedroutestop_id
                			from routestop rs
                		 where rs.route_id = m_onlyroute_id
              	    	and rs.customer_id = fpi_customer_id
              			  and (fpi_delpoint_id is null
              			   or rs.deliverypoint_id is null
              				 or rs.deliverypoint_id = fpi_delpoint_id)
              			  and trunc(rs.dateinactive) <= trunc(m_date);
                    exception
                      when no_data_found then null;
                    end;
                    m_movedtoroutestop_id := m_movedroutestop_id;
              			-- step 4: go to the end of the chain of moved stops.
              			while m_movedtoroutestop_id <> 0 loop
              				begin
                        select rs.routestop_id,
                					nvl(rs.movedroutestop_id, 0),
                					rs.route_id,
                					route.drivingday_id
                				into m_returnroutestop_id,
                					m_movedtoroutestop_id,
                					m_onlyroute_id,
                					m_daynr
                				from routestop rs, route
                				where rs.routestop_id = m_movedtoroutestop_id
                				and route.route_id = rs.route_id;
              				exception when no_data_found then
              					m_movedtoroutestop_id := 0;
              					m_returnroutestop_id := 0;
              					m_daynr := 0;
              				end;
              				if m_daynr > getabsdaynumber(m_pickupdate)
                       then m_days := m_daynr - getabsdaynumber(m_pickupdate);
              				 else m_days := m_daynr + 7 - getabsdaynumber(m_pickupdate);
                      end if;
              				m_date := m_date + m_days;
                      --if found date is too far, try to find an earlier date, around sysdate
                      if m_date - 7 > sysdate
                       then m_date := m_date -7;
                      end if;
              			end loop;
              	end if; -- m_returnreturnroutestop_id = 0

              	if m_returnroutestop_id = 0 then
              			-- customer is not in the return route and there is no moved stop
              			-- will be handled in the same way as next week same day
              			m_onlyroute_id := 0;
              			m_date := m_pickupdate + 7;
              			-- if stop was moved then add correction for the new route day
              			if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
                 			m_date := m_date + m_movedays;
                    end if;
                end if; -- m_returnroutestop_id = 0
      else -- take the first next route
              	m_date := fpi_date;
      end case;

      writedebuglog(m_log,m_proc,'determined theoretical deliverydate=' || to_char(m_date,'DD-MON-YYYY') || ',returnitems=' || m_returnitems);

      gv_code_block := 'Determine return route';

      m_startdate := m_date;
      if (trunc(m_startdate) < trunc(sysdate)) then
        m_startdate := trunc(sysdate);
        m_deliveryscheme_id:= 0;
        m_onlyroute_id :=0;
        m_routestop_id:=0;
      end if;

      firstnextroutestop(fpi_plant_id,
                         fpi_customer_id,
                         fpi_delpoint_id,
                         fpi_department_id,
                         5,--fpi_typeofmerch,
                         m_startdate,
                         -1 ,--fpi_plpc_id,
                         fpi_distribpoint_id,
                         m_deliveryscheme_id,
                         m_onlyroute_id,
                         m_log,
                         m_routestop_id,
                         m_route_id,
                         m_stop_id,
                         m_routecontrol_id,
                         m_realdrivingdate);

      -- fill the incoming route output parameters verify if values are correct.
      if m_routestop_id = 0 then
        fpo_outroutestop_id :=null;
      else
        fpo_outroutestop_id := m_routestop_id;
      end if;
      if m_route_id = 0 then
        fpo_outroute_id :=null;
      else
        fpo_outroute_id := m_route_id;
      end if;
      if m_routecontrol_id = 0 then
        fpo_outroutecontrol_id :=null;
      else
        fpo_outroutecontrol_id := m_routecontrol_id;
      end if;
      if m_stop_id = 0 then
        fpo_outstop_id :=null;
      else
        fpo_outstop_id := m_stop_id;
      end if;

      if m_realdrivingdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_outdrivingdate :=null;
      else
        fpo_outdrivingdate := m_realdrivingdate;
      end if;
    end if; -- determinepickup
    	-- fill the incoming route output parameters verify if values are correct.
      if fpo_inroute_id = 0 then
        fpo_inroute_id := null;
      end if;
      if fpo_inroutestop_id = 0 then
        fpo_inroutestop_id := null;
      end if;
      if fpo_inroutecontrol_id = 0 then
        fpo_inroutecontrol_id := null;
      end if;
      if fpo_instop_id = 0 then
        fpo_instop_id := null;
      end if;
      if fpo_pickupdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_pickupdate :=null;
      end if;

    --	step 3: when the date could not be determined or is a date in the past. in this case take the first next visit.
    if m_routestop_id = 0 or m_realdrivingdate < fpi_date THEN

      m_startdate := fpi_date;
      if (trunc(m_startdate) < trunc(sysdate)) then
        m_startdate := trunc(sysdate);
      end if;

      firstnextroutestop(fpi_plant_id,
                         fpi_customer_id,
                         fpi_delpoint_id,
                         fpi_department_id,
                         5,--fpi_typeofmerch,
                         m_startdate,  -- so not m_date
                         -1, --fpi_plpc_id,
                         fpi_distribpoint_id,
                         null,  -- delivery scheme
                         null,  -- only route
                         m_log,
                         m_routestop_id,
                         m_route_id,
                         m_stop_id,
                         m_routecontrol_id,
                         m_realdrivingdate);

      -- fill the incoming route output parameters verify if values are correct.
      if m_routestop_id = 0 then
        fpo_outroutestop_id :=null;
      else
        fpo_outroutestop_id := m_routestop_id;
      end if;

      if m_route_id = 0 then
        fpo_outroute_id :=null;
      else
        fpo_outroute_id := m_route_id;
      end if;

      if m_routecontrol_id = 0 then
        fpo_outroutecontrol_id :=null;
      else
        fpo_outroutecontrol_id := m_routecontrol_id;
      end if;

      if m_stop_id = 0 then
        fpo_outstop_id :=null;
      else
        fpo_outstop_id := m_stop_id;
      end if;

      if m_realdrivingdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_outdrivingdate :=null;
      else
        fpo_outdrivingdate := m_realdrivingdate;
      end if;
    end if; -- m_routestop_id = 0 or m_drivingdate < param_date
    writedebuglog(m_log,m_proc,'outputparams: routestop_id=' || m_routestop_id || ',drivingdate=' ||  to_char(fpo_outdrivingdate,'DD-MON-YYYY'));

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; --determinedeldatepwbsoil
--------------------------------------------------------------------------------------------
procedure determinedeldaterouteclean(fpi_plant_id        in number,
                                     fpi_customer_id     in number,
                                     fpi_delpoint_id     in number,
                                     fpi_department_id   in number,
                                     fpi_typeofmerch     in number,
                                     fpi_date            in date,
                                     fpi_plpc_id         in number,
                                     fpi_distribpoint_id in number,
                                     fpi_log             in varchar2,
                                     fpo_routestop_id    out number,
                                     fpo_route_id        out number,
                                     fpo_stop_id         out number,
                                     fpo_routecontrol_id out number,
                                     fpo_drivingdate     out date,
                                     fpi_invoicesgenerated in number default null) is
m_log   varchar2(1);
m_proc  varchar2(30);
begin
  begin -- main exception block
    m_log := nvl(fpi_log, 'N');
    -- uncomment this line of code to temporarely set DEBUG ON --
--  m_log := 'Y';
    --
    gv_plant_id := fpi_plant_id;
    m_proc := 'DETERMINEDELDATEROUTECLEAN';
    gv_code_block := 'Main';
    writedebuglog(m_log,m_proc,'inputparams: plant=' || fpi_plant_id || ',cust=' || fpi_customer_id || ',delp=' || fpi_delpoint_id ||
                  ',dept=' ||  fpi_department_id || ',tom=' || fpi_typeofmerch || ',date=' || to_char(fpi_date,'DD-MON-YYYY') ||
                  ',plpc=' ||  fpi_plpc_id || ',dip=' || fpi_distribpoint_id);

    firstnextroutestop(fpi_plant_id,
                       fpi_customer_id,
                       fpi_delpoint_id,
                       fpi_department_id,
                       fpi_typeofmerch,
                       fpi_date,
                       fpi_plpc_id,
                       fpi_distribpoint_id,
                       null,  -- deliveryscheme_id
                       null,  -- only route_id
                       m_log,
                       fpo_routestop_id,
                       fpo_route_id,
                       fpo_stop_id,
                       fpo_routecontrol_id,
                       fpo_drivingdate,
                       fpi_invoicesgenerated);

    -- fill the incoming route output parameters verify if values are correct.
    if fpo_routestop_id = 0 then
      fpo_routestop_id :=null;
    end if;

    if fpo_route_id = 0 then
      fpo_route_id :=null;
    end if;

    if fpo_routecontrol_id = 0 then
      fpo_routecontrol_id :=null;
    end if;

    if fpo_stop_id = 0 then
      fpo_stop_id :=null;
    end if;

    if fpo_drivingdate = to_date('31-12-2099','dd-mm-yyyy') then
      fpo_drivingdate :=null;
    end if;

    writedebuglog(m_log,m_proc,'outputparams: routestop_id=' || fpo_routestop_id || ',route_id=' || fpo_route_id  ||
                  ',stop_id=' ||  fpo_stop_id || ',routecontrol_id=' || fpo_routecontrol_id || ',drivindatedate=' || to_char(fpo_drivingdate,'DD-MON-YYYY'));

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; --determinedeldaterouteclean
----------------------------------------------------------------------------------------------------
procedure determinedeldatedistribpoint(fpi_plant_id           in number,
                                    fpi_date               in date,
                                    fpi_distribpoint_id    in number,
                                    fpi_log                in varchar2,
                                    fpo_inroute_id         out number,
                                    fpo_inroutestop_id     out number,
                                    fpo_inroutecontrol_id  out number,
                                    fpo_instop_id          out number,
                                    fpo_pickupdate         out date,
                                    fpo_outroute_id        out number,
                                    fpo_outroutestop_id    out number,
                                    fpo_outroutecontrol_id out number,
                                    fpo_outstop_id         out number,
                                    fpo_outdrivingdate     out date) is
m_customer_id             number;
m_department_id           number;
m_deliverypoint_id        number;
m_proc                    varchar2(30);
m_log                     varchar2(1);
m_stop_id                 number;
m_routestop_id            number;
m_routecontrol_id         number;
m_route_id                number;
m_pickupdate              date;
m_realpickupdate          date;
m_movedtoroutestop_id     number;
m_movedtoroute_id         number;
m_movedstartdate          date;
m_movedays                number;
m_realdrivingdate         date;
m_dee_deliveryscheme_id       number;
m_onlyroute_id            number;
m_date                    date;
m_movestartdate           date;
m_days                    number;
m_daynr                   number;
m_returnroutestop_id      number;
m_movedroutestop_id       number;
m_startdate                    date;

begin
  begin -- main exception block
    m_log := nvl(fpi_log, 'N');
    -- uncomment this line of code to temporarely set DEBUG ON --
--  m_log := 'Y';
    --
    gv_plant_id := fpi_plant_id;
    m_proc := 'DETERMINEDELDATEDISTRIBPOINT';
    gv_code_block := 'Initialize';
    writedebuglog(m_log,m_proc,'inputparams: plant=' || fpi_plant_id || ',date=' || to_char(fpi_date,'DD-MON-YYYY') || ',dip=' || fpi_distribpoint_id);


    -- initialize the out parameters
    fpo_inroute_id := 0;
    fpo_inroutestop_id := 0;
    fpo_inroutecontrol_id := 0;
    fpo_instop_id := 0;
    fpo_pickupdate := gv_max_date;
    fpo_outroute_id := 0;
    fpo_outroutestop_id := 0;
    fpo_outroutecontrol_id := 0;
    fpo_outstop_id := 0;
    fpo_outdrivingdate := gv_max_date;


    select d.department_id, d.customer_id, dp.deliverypoint_id
    into m_department_id,m_customer_id,m_deliverypoint_id
    from distributionpoint dp, department d
    where dp.department_id=d.department_id
    and  dp.distributionpoint_id=fpi_distribpoint_id;

    gv_code_block := 'Determine Pickup';

    -- step 1: determine the incoming route:
    if determinepickup(fpi_plant_id,
                       m_customer_id,
                       m_deliverypoint_id,
                       m_department_id,
                       1,--fpi_typeofmerch,
                       fpi_date,
                       fpi_distribpoint_id,
                       m_log,
                       -1,--fpi_plpc_id,
                       m_stop_id,
                       m_routestop_id,
                       m_routecontrol_id,
                       m_route_id,
                       m_pickupdate,
                       m_realpickupdate,
                       m_movedtoroutestop_id,
                       m_movedtoroute_id,
                       m_movedstartdate,
                       m_movedays) then

      -- fill the incoming route output parameters.
      fpo_inroute_id := m_route_id;
      fpo_inroutestop_id := m_routestop_id;
      fpo_inroutecontrol_id := m_routecontrol_id;
      fpo_instop_id := m_stop_id;
      fpo_pickupdate := m_realpickupdate;

      m_route_id := 0;
      m_dee_deliveryscheme_id := 0;
      m_onlyroute_id := 0;

      m_dee_deliveryscheme_id:=0;
      begin
               select *
              into   m_dee_deliveryscheme_id
              from (
                  select  ds.deliveryscheme_id
                   from ROUTESTOP rs, route r, customerdeliveryscheme cds, deliveryscheme ds
                  where rs.customer_id=m_deliverypoint_id
                  and rs.route_id=m_route_id
                  and r.route_id=m_route_id
                  and r.plant_id=fpi_plant_id
                  and r.drivingday_id=cds.day_id
                  and nvl(rs.deliverypoint_id,m_deliverypoint_id)=m_deliverypoint_id
                  and cds.customer_id=rs.customer_id
                  and cds.deliveryscheme_id=ds.deliveryscheme_id
                  and cds.active='Y'
                  and rs.dateactive < trunc(fpi_date)
                  and rs.dateinactive > trunc(fpi_date)
                    order by ds.frequency asc)
               where rownum = 1;
              exception
            when no_data_found then null;
          end;

      -- step 2: determine the corresponding outgoing route
      -- note that m_pickupdate is the original pick up date, not necessarily the real pick up date.
      begin
               -- return route from route schedule from
                -- only the routes for the return route are checked. this is done by adding a restriction
                -- using m_onlyroute_id. when a route is moved then also the returnroute of the
                -- moved stop is considered.
                -- step 1: determine the return route and driving date
                m_days := 7;
                m_daynr := getabsdaynumber(m_pickupdate);
                begin
                  select route.drivingday_id,
                         route.route_id
                    into m_daynr,
                         m_onlyroute_id
                    from route, routestop rs
                   where rs.routestop_id = m_routestop_id
                     and route.route_id = rs.returnroute_id;
                exception
                  when no_data_found then m_onlyroute_id := 0;
                end;
                if m_onlyroute_id = 0 then
                    -- no return route defined, route is considered its own return route
                    m_onlyroute_id := fpo_inroute_id;
                        m_date := m_pickupdate + 7;
                        if (m_dee_deliveryscheme_id > 0) then
                       m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                        end if;
                else
                    -- calculate the next date for the return route
                    if m_daynr > getabsdaynumber(m_pickupdate)
                      then m_days := m_daynr - getabsdaynumber(m_pickupdate);
                    else m_days := m_daynr + 7 - getabsdaynumber(m_pickupdate);
                      end if;
                      m_date := m_pickupdate + m_days;
                      if (m_dee_deliveryscheme_id > 0) then
                         m_date := getnextdeldatedelscheme(m_date, m_dee_deliveryscheme_id);
                      end if;
                end if; -- m_onlyroute_id = 0

                -- step 2: check if there is an active routestop for the customer / deliverypoint in the
                -- return route
                m_returnroutestop_id := 0;
                begin
                select nvl(max(rs.routestop_id),0)
                  into m_returnroutestop_id
                  from routestop rs
                 where rs.route_id = m_onlyroute_id
                   and rs.customer_id = m_customer_id
                   and (m_deliverypoint_id is null
                    or rs.deliverypoint_id is null
                    or rs.deliverypoint_id = m_deliverypoint_id)
                   and trunc(rs.dateactive) <= trunc(m_date)
                   and trunc(rs.dateinactive) > trunc(m_date);
                end;

                if m_returnroutestop_id = 0 then
                    -- there is no (active) stop for the customer in the return route
                    -- step 3: check if the stop was moved
                    m_movedroutestop_id := 0;
                    begin
                    select max(rs.movedroutestop_id)
                      into m_movedroutestop_id
                      from routestop rs
                     where rs.route_id = m_onlyroute_id
                      and rs.customer_id = m_customer_id
                      and (m_deliverypoint_id is null
                       or rs.deliverypoint_id is null
                       or rs.deliverypoint_id = m_deliverypoint_id)
                      and trunc(rs.dateinactive) <= trunc(m_date);
                    exception
                      when no_data_found then null;
                    end;

                    m_movedtoroutestop_id := m_movedroutestop_id;

                    -- step 4: go to the end of the chain of moved stops.
                    while m_movedtoroutestop_id <> 0 loop
                      begin
                        select rs.routestop_id,
                          nvl(rs.movedroutestop_id, 0),
                          rs.route_id,
                          route.drivingday_id
                        into m_returnroutestop_id,
                          m_movedtoroutestop_id,
                          m_onlyroute_id,
                          m_daynr
                        from routestop rs, route
                        where rs.routestop_id = m_movedtoroutestop_id
                        and route.route_id = rs.route_id;
                      exception when no_data_found then
                        m_movedtoroutestop_id := 0;
                        m_returnroutestop_id := 0;
                        m_daynr := 0;
                      end;
                      if m_daynr > getabsdaynumber(m_pickupdate)
                       then m_days := m_daynr - getabsdaynumber(m_pickupdate);
                       else m_days := m_daynr + 7 - getabsdaynumber(m_pickupdate);
                      end if;
                      m_date := m_date + m_days;
                      --if found date is too far, try to find an earlier date, around sysdate
                      if m_date - 7 > sysdate
                       then m_date := m_date -7;
                      end if;
                    end loop;
                end if; -- m_returnreturnroutestop_id = 0

                if m_returnroutestop_id = 0 then
                    -- customer is not in the return route and there is no moved stop
                    -- will be handled in the same way as next week same day
                    m_onlyroute_id := 0;
                    m_date := m_pickupdate + 7;
                    -- if stop was moved then add correction for the new route day
                    if m_movedtoroutestop_id <> 0 and m_date >= m_movestartdate then
                      m_date := m_date + m_movedays;
                    end if;
                end if; -- m_returnroutestop_id = 0

           --else -- take the first next route
               if m_date is null then  m_date := fpi_date;
               end if;
     -- end case;
     end;

      writedebuglog(m_log,m_proc,'determined theoretical deliverydate for distribution point=' || to_char(m_date,'DD-MON-YYYY') );

      gv_code_block := 'Determine return route';

      m_startdate := m_date;
      if (trunc(m_startdate) < trunc(sysdate)) then
        m_startdate := trunc(sysdate);
        m_dee_deliveryscheme_id:= 0;
        m_onlyroute_id :=0;
        m_routestop_id:=0;
      end if;

      firstnextroutestop(fpi_plant_id,
                         m_customer_id,
                         m_deliverypoint_id,
                         m_department_id,
                         1,--fpi_typeofmerch,
                         m_startdate,
                         -1,--fpi_plpc_id,
                         fpi_distribpoint_id,
                         m_dee_deliveryscheme_id,
                         m_onlyroute_id,
                         m_log,
                         m_routestop_id,
                         m_route_id,
                         m_stop_id,
                         m_routecontrol_id,
                         m_realdrivingdate);

      -- fill the incoming route output parameters verify if values are correct.
      if m_routestop_id = 0 then
        fpo_outroutestop_id :=null;
      else
        fpo_outroutestop_id := m_routestop_id;
      end if;

      if m_route_id = 0 then
        fpo_outroute_id :=null;
      else
        fpo_outroute_id := m_route_id;
      end if;

      if m_routecontrol_id = 0 then
        fpo_outroutecontrol_id :=null;
      else
        fpo_outroutecontrol_id := m_routecontrol_id;
      end if;

      if m_stop_id = 0 then
        fpo_outstop_id :=null;
      else
        fpo_outstop_id := m_stop_id;
      end if;

      if m_realdrivingdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_outdrivingdate :=null;
      else
        fpo_outdrivingdate := m_realdrivingdate;
      end if;
    end if; -- determinepickup


      -- fill the incoming route output parameters verify if values are correct.
      if fpo_inroute_id = 0 then
        fpo_inroute_id := null;
      end if;
      if fpo_inroutestop_id = 0 then
        fpo_inroutestop_id := null;
      end if;
      if fpo_inroutecontrol_id = 0 then
        fpo_inroutecontrol_id := null;
      end if;
      if fpo_instop_id = 0 then
        fpo_instop_id := null;
      end if;
      if fpo_pickupdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_pickupdate :=null;
      end if;

    --  step 3: when the date could not be determined or is a date in the past. in this case take the first next visit.
    if m_routestop_id = 0 or m_realdrivingdate < fpi_date THEN

      m_startdate := fpi_date;
      if (trunc(m_startdate) < trunc(sysdate)) then
        m_startdate := trunc(sysdate);
      end if;

      firstnextroutestop(fpi_plant_id,
                         m_customer_id,
                         m_deliverypoint_id,
                         m_department_id,
                         1,--fpi_typeofmerch,
                         m_startdate,  -- so not m_date
                         -1,--fpi_plpc_id,
                         fpi_distribpoint_id,
                         null,  -- delivery scheme
                         null,  -- only route
                         m_log,
                         m_routestop_id,
                         m_route_id,
                         m_stop_id,
                         m_routecontrol_id,
                         m_realdrivingdate);

      -- fill the incoming route output parameters verify if values are correct.
      if m_routestop_id = 0 then
        fpo_outroutestop_id :=null;
      else
        fpo_outroutestop_id := m_routestop_id;
      end if;

      if m_route_id = 0 then
        fpo_outroute_id :=null;
      else
        fpo_outroute_id := m_route_id;
      end if;

      if m_routecontrol_id = 0 then
        fpo_outroutecontrol_id :=null;
      else
        fpo_outroutecontrol_id := m_routecontrol_id;
      end if;

      if m_stop_id = 0 then
        fpo_outstop_id :=null;
      else
        fpo_outstop_id := m_stop_id;
      end if;

      if m_realdrivingdate = to_date('31-12-2099','dd-mm-yyyy') then
        fpo_outdrivingdate :=null;
      else
        fpo_outdrivingdate := m_realdrivingdate;
      end if;
    end if; -- m_routestop_id = 0 or m_drivingdate < param_date
    writedebuglog(m_log,m_proc,'outputparams: routestop_id=' || m_routestop_id || ',drivingdate=' ||  to_char(fpo_outdrivingdate,'DD-MON-YYYY'));

  exception
    when others then
     begin
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writeerrorlog(m_proc);
    end;
  end;
end; --determinedeldatedistribpoint
----------------------------------------------------------------------------------------------------
procedure testdeldateroutesoil(fpi_plantcode         in varchar2,
                               fpi_customernumber    in number,
                               fpi_delpointcode      in varchar2,
                               fpi_departmentnumber  in number,
                               fpi_productcode       in varchar2,
                               fpi_sizecode          in varchar2,
                               fpi_finmethodcode     in varchar2,
                               fpi_date              in date,
                               fpi_distribpointnr    in number,
                               fpi_log               in varchar2,
                               fpo_inroutenumber     out number,
                               fpo_inroutestopnumber out number,
                               fpo_inrealroutenumber out number,
                               fpo_inrealstopnumber  out number,
                               fpo_pickupdate        out date,
                               fpo_outroutenumber    out number,
                               fpo_outstopnumber     out number,
                               fpo_outrealroutenr    out number,
                               fpo_outrealstopnr     out number,
                               fpo_outdrivingdate    out date) is
m_plant_id           number;
m_customer_id        number;
m_delpoint_id        number;
m_department_id      number;
m_typeofmerch        number;
m_product_id         number;
m_size_id            number;
m_finmethod_id       number;
m_plpc_id            number;
m_distribpoint_id    number;
m_inroutestop_id     number;
m_inroute_id         number;
m_instop_id          number;
m_inroutecontrol_id  number;
m_outroutestop_id    number;
m_outroute_id        number;
m_outstop_id         number;
m_outroutecontrol_id number;

begin
  if fpi_plantcode is null then
  	m_plant_id := null;
  else
  	select plant_id
      into m_plant_id
      from plant
     where code = fpi_plantcode;
  end if;
  select customer.customer_id
    into m_customer_id
    from customer
   where customernumber = fpi_customernumber;

  if fpi_delpointcode is null then
  	m_delpoint_id := null;
  else
  	select deliverypoint_id
      into m_delpoint_id
      from deliverypoint
     where customer_id = m_customer_id
       and deliverypoint.code = fpi_delpointcode;
  end if;

  if fpi_departmentnumber is null then
  	m_department_id := null;
  else
  	select department_id
      into m_department_id
      from department
     where customer_id = m_customer_id
       and departmentnumber = fpi_departmentnumber;
  end if;

  if fpi_distribpointnr is null or m_department_id is null then
  	m_distribpoint_id := null;
  else
    select distributionpoint_id
      into m_distribpoint_id
      from distributionpoint
     where department_id = m_department_id
       and distributionpointnumber = fpi_distribpointnr;
  end if;

  select p.product_id,
         p.typeofmerchandise
    into m_product_id,
         m_typeofmerch
    from product p
   where p.code = fpi_productcode;

  if fpi_sizecode is null then
    m_size_id := null;
  else
    select s.sizedefinition_id
      into m_size_id
      from sizedefinition s
     where s.code = fpi_sizecode;
  end if;

  if fpi_finmethodcode is null then
    m_finmethod_id := null;
  else
  select f.finishingmethod_id
    into m_finmethod_id
    from finishingmethod f
   where f.code = fpi_finmethodcode;
  end if;

  if fpi_productcode is null or fpi_sizecode is null or fpi_finmethodcode is null then
  	m_plpc_id := null;
  else
    select plpc.productlistpercustomer_id
      into m_plpc_id
      from productlistpercustomer plpc
     where plpc.customer_id = m_customer_id
       and plpc.product_id = m_product_id
       and plpc.sizedefinition_id = m_size_id
       and plpc.finishingmethod_id = m_finmethod_id
       and trunc(plpc.dateactive) <= trunc(fpi_date)
       and trunc(plpc.dateinactive) > trunc(fpi_date);
  end if;

 determinedeldateroutesoil(m_plant_id, m_customer_id, m_delpoint_id, m_department_id, m_typeofmerch, fpi_date,
                           m_plpc_id, m_distribpoint_id, fpi_log,
                           m_inroute_id,m_inroutestop_id,m_inroutecontrol_id,m_instop_id,fpo_pickupdate,
                           m_outroute_id,m_outroutestop_id,m_outroutecontrol_id,m_outstop_id,fpo_outdrivingdate);

 if m_inroute_id <> 0 then
   select route.routenumber
     into fpo_inroutenumber
     from route
    where route.route_id = m_inroute_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_inroutestop_id <> 0 then
   select stopnumber
     into fpo_inroutestopnumber
     from routestop
    where routestop_id = m_inroutestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_inroutecontrol_id <> 0 then
   select route.routenumber
     into fpo_inrealroutenumber
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_inroutecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_instop_id <> 0 then
   select stop.stopnumber
     into fpo_inrealstopnumber
     from stop
    where stop.stop_id = m_instop_id;
  else fpo_outrealstopnr := 0;
  end if;


 if m_outroute_id <> 0 then
   select route.routenumber
     into fpo_outroutenumber
     from route
    where route.route_id = m_outroute_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_outroutestop_id <> 0 then
   select stopnumber
     into fpo_outstopnumber
     from routestop
    where routestop_id = m_outroutestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_outroutecontrol_id <> 0 then
   select route.routenumber
     into fpo_outrealroutenr
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_outroutecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_outstop_id <> 0 then
   select stop.stopnumber
     into fpo_outrealstopnr
     from stop
    where stop.stop_id = m_outstop_id;
  else fpo_outrealstopnr := 0;
  end if;


end; --testdeldateroutesoil
---------------------------------------------------------------------------------------------------
procedure testdeldatepwbsoil(fpi_plantcode         in varchar2,
                               fpi_customernumber    in number,
                               fpi_delpointcode      in varchar2,
                               fpi_departmentnumber  in number,
                               fpi_date              in date,
                               fpi_distribpointnr    in number,
                               fpi_log               in varchar2,
                               fpo_inroutenumber     out number,
                               fpo_inroutestopnumber out number,
                               fpo_inrealroutenumber out number,
                               fpo_inrealstopnumber  out number,
                               fpo_pickupdate        out date,
                               fpo_outroutenumber    out number,
                               fpo_outstopnumber     out number,
                               fpo_outrealroutenr    out number,
                               fpo_outrealstopnr     out number,
                               fpo_outdrivingdate    out date) is
m_plant_id           number;
m_customer_id        number;
m_delpoint_id        number;
m_department_id      number;
m_distribpoint_id    number;
m_inroutestop_id     number;
m_inroute_id         number;
m_instop_id          number;
m_inroutecontrol_id  number;
m_outroutestop_id    number;
m_outroute_id        number;
m_outstop_id         number;
m_outroutecontrol_id number;

begin
  if fpi_plantcode is null then
  	m_plant_id := null;
  else
  	select plant_id
      into m_plant_id
      from plant
     where code = fpi_plantcode;
  end if;
  select customer.customer_id
    into m_customer_id
    from customer
   where customernumber = fpi_customernumber;

  if fpi_delpointcode is null then
  	m_delpoint_id := null;
  else
  	select deliverypoint_id
      into m_delpoint_id
      from deliverypoint
     where customer_id = m_customer_id
       and deliverypoint.code = fpi_delpointcode;
  end if;

  if fpi_departmentnumber is null then
  	m_department_id := null;
  else
  	select department_id
      into m_department_id
      from department
     where customer_id = m_customer_id
       and departmentnumber = fpi_departmentnumber;
  end if;

  if fpi_distribpointnr is null or m_department_id is null then
  	m_distribpoint_id := null;
  else
    select distributionpoint_id
      into m_distribpoint_id
      from distributionpoint
     where department_id = m_department_id
       and distributionpointnumber = fpi_distribpointnr;
  end if;
  determinedeldatepwbsoil(m_plant_id, m_customer_id, m_delpoint_id, m_department_id, fpi_date,
                           m_distribpoint_id, fpi_log,
                           m_inroute_id,m_inroutestop_id,m_inroutecontrol_id,m_instop_id,fpo_pickupdate,
                           m_outroute_id,m_outroutestop_id,m_outroutecontrol_id,m_outstop_id,fpo_outdrivingdate);

 if m_inroute_id <> 0 then
   select route.routenumber
     into fpo_inroutenumber
     from route
    where route.route_id = m_inroute_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_inroutestop_id <> 0 then
   select stopnumber
     into fpo_inroutestopnumber
     from routestop
    where routestop_id = m_inroutestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_inroutecontrol_id <> 0 then
   select route.routenumber
     into fpo_inrealroutenumber
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_inroutecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_instop_id <> 0 then
   select stop.stopnumber
     into fpo_inrealstopnumber
     from stop
    where stop.stop_id = m_instop_id;
  else fpo_outrealstopnr := 0;
  end if;


 if m_outroute_id <> 0 then
   select route.routenumber
     into fpo_outroutenumber
     from route
    where route.route_id = m_outroute_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_outroutestop_id <> 0 then
   select stopnumber
     into fpo_outstopnumber
     from routestop
    where routestop_id = m_outroutestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_outroutecontrol_id <> 0 then
   select route.routenumber
     into fpo_outrealroutenr
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_outroutecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_outstop_id <> 0 then
   select stop.stopnumber
     into fpo_outrealstopnr
     from stop
    where stop.stop_id = m_outstop_id;
  else fpo_outrealstopnr := 0;
  end if;
end; --testdeldatepwbsoil
----------------------------------------------------------------------------------------------------
procedure testdeldaterouteclean(fpi_plantcode        in varchar2,
                                fpi_customernumber   in number,
                                fpi_delpointcode     in varchar2,
                                fpi_departmentnumber in number,
                                fpi_productcode      in varchar2,
                                fpi_sizecode         in varchar2,
                                fpi_finmethodcode    in varchar2,
                                fpi_date             in date,
                                fpi_distribpointnr   in number,
                                fpi_log              in varchar2,
                                fpo_outroutenumber   out number,
                                fpo_outstopnumber    out number,
                                fpo_outrealroutenr   out number,
                                fpo_outrealstopnr    out number,
                                fpo_outdrivingdate   out date) is

m_plant_id        number;
m_customer_id     number;
m_delpoint_id     number;
m_department_id   number;
m_typeofmerch     number;
m_product_id      number;
m_size_id         number;
m_finmethod_id    number;
m_plpc_id         number;
m_distribpoint_id number;
m_routestop_id    number;
m_route_id        number;
m_stop_id         number;
m_routecontrol_id number;

begin
  if fpi_plantcode is null then
  	m_plant_id := null;
  else
  	select plant_id
      into m_plant_id
      from plant
     where code = fpi_plantcode;
  end if;
  select customer.customer_id
    into m_customer_id
    from customer
   where customernumber = fpi_customernumber;

  if fpi_delpointcode is null then
  	m_delpoint_id := null;
  else
  	select deliverypoint_id
      into m_delpoint_id
      from deliverypoint
     where customer_id = m_customer_id
       and deliverypoint.code = fpi_delpointcode;
  end if;

  if fpi_departmentnumber is null then
  	m_department_id := null;
  else
  	select department_id
      into m_department_id
      from department
     where customer_id = m_customer_id
       and departmentnumber = fpi_departmentnumber;
  end if;

  if fpi_distribpointnr is null or m_department_id is null then
  	m_distribpoint_id := null;
  else
    select distributionpoint_id
      into m_distribpoint_id
      from distributionpoint
     where department_id = m_department_id
       and distributionpointnumber = fpi_distribpointnr;
  end if;

  select p.product_id,
         p.typeofmerchandise
    into m_product_id,
         m_typeofmerch
    from product p
   where p.code = fpi_productcode;

  if fpi_sizecode is null then
    m_size_id := null;
  else
    select s.sizedefinition_id
      into m_size_id
      from sizedefinition s
     where s.code = fpi_sizecode;
  end if;

  if fpi_finmethodcode is null then
    m_finmethod_id := null;
  else
  select f.finishingmethod_id
    into m_finmethod_id
    from finishingmethod f
   where f.code = fpi_finmethodcode;
  end if;

  if fpi_productcode is null or fpi_sizecode is null or fpi_finmethodcode is null then
  	m_plpc_id := null;
  else
    select plpc.productlistpercustomer_id
      into m_plpc_id
      from productlistpercustomer plpc
     where plpc.customer_id = m_customer_id
       and plpc.product_id = m_product_id
       and plpc.sizedefinition_id = m_size_id
       and plpc.finishingmethod_id = m_finmethod_id
       and trunc(plpc.dateactive) <= trunc(fpi_date)
       and trunc(plpc.dateinactive) > trunc(fpi_date);
  end if;

 determinedeldaterouteclean(m_plant_id, m_customer_id, m_delpoint_id, m_department_id, m_typeofmerch, fpi_date,
                            m_plpc_id, m_distribpoint_id, fpi_log,
                            m_routestop_id, m_route_id, m_stop_id, m_routecontrol_id, fpo_outdrivingdate);

 if m_route_id <> 0 then
   select route.routenumber
     into fpo_outroutenumber
     from route
    where route.route_id = m_route_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_routestop_id <> 0 then
   select stopnumber
     into fpo_outstopnumber
     from routestop
    where routestop_id = m_routestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_routecontrol_id <> 0 then
   select route.routenumber
     into fpo_outrealroutenr
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_routecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_stop_id <> 0 then
   select stop.stopnumber
     into fpo_outrealstopnr
     from stop
    where stop.stop_id = m_stop_id;
  else fpo_outrealstopnr := 0;
  end if;

end; --testdeldaterouteclean
------------------------------------------------------------------------------------
procedure testdeldatedistribpoint(fpi_plantcode         in varchar2,
                               fpi_customernumber    in number,
                               fpi_departmentnumber  in number,
                               fpi_date              in date,
                               fpi_distribpointnr    in number,
                               fpi_log               in varchar2,
                               fpo_inroutenumber     out number,
                               fpo_inroutestopnumber out number,
                               fpo_inrealroutenumber out number,
                               fpo_inrealstopnumber  out number,
                               fpo_pickupdate        out date,
                               fpo_outroutenumber    out number,
                               fpo_outstopnumber     out number,
                               fpo_outrealroutenr    out number,
                               fpo_outrealstopnr     out number,
                               fpo_outdrivingdate    out date) is
m_plant_id           number;
m_distribpoint_id    number;
m_inroutestop_id     number;
m_inroute_id         number;
m_instop_id          number;
m_inroutecontrol_id  number;
m_outroutestop_id    number;
m_outroute_id        number;
m_outstop_id         number;
m_outroutecontrol_id number;

begin
  if fpi_plantcode is null then
  	m_plant_id := null;
  else
  	select plant_id
      into m_plant_id
      from plant
     where code = fpi_plantcode;
  end if;

  select dp.distributionpoint_id
  into m_distribpoint_id
 from distributionpoint dp, department d, customer c
where dp.department_id=d.department_id
and  d.customer_id=c.customer_id
and c.customernumber=fpi_customernumber
and d.departmentnumber=fpi_departmentnumber
and dp.distributionpointnumber=fpi_distribpointnr;

determinedeldatedistribpoint(m_plant_id, fpi_date, m_distribpoint_id, fpi_log,
                           m_inroute_id,m_inroutestop_id,m_inroutecontrol_id,m_instop_id,fpo_pickupdate,
                           m_outroute_id,m_outroutestop_id,m_outroutecontrol_id,m_outstop_id,fpo_outdrivingdate);

 if m_inroute_id <> 0 then
   select route.routenumber
     into fpo_inroutenumber
     from route
    where route.route_id = m_inroute_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_inroutestop_id <> 0 then
   select stopnumber
     into fpo_inroutestopnumber
     from routestop
    where routestop_id = m_inroutestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_inroutecontrol_id <> 0 then
   select route.routenumber
     into fpo_inrealroutenumber
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_inroutecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_instop_id <> 0 then
   select stop.stopnumber
     into fpo_inrealstopnumber
     from stop
    where stop.stop_id = m_instop_id;
  else fpo_outrealstopnr := 0;
  end if;


 if m_outroute_id <> 0 then
   select route.routenumber
     into fpo_outroutenumber
     from route
    where route.route_id = m_outroute_id;
  else fpo_outroutenumber := 0;
 end if;

 if m_outroutestop_id <> 0 then
   select stopnumber
     into fpo_outstopnumber
     from routestop
    where routestop_id = m_outroutestop_id;
  else fpo_outstopnumber := 0;
 end if;

 if m_outroutecontrol_id <> 0 then
   select route.routenumber
     into fpo_outrealroutenr
     from route, routecontrol rc
    where route.route_id = rc.route_id
      and rc.routecontrol_id = m_outroutecontrol_id;
  else fpo_outrealroutenr := 0;
 end if;

  if m_outstop_id <> 0 then
   select stop.stopnumber
     into fpo_outrealstopnr
     from stop
    where stop.stop_id = m_outstop_id;
  else fpo_outrealstopnr := 0;
  end if;
end; --testdeldatedistribpoint
-------------------------------------------------------------------------------------
begin
 gv_max_date := getABSMaxDate;
end pack_deliverybasics;
/
create or replace PACKAGE PACK_DELIVERYDAY is

procedure CFbReorganize (
        FPnCUSTOMER_ID                            in     CUSTOMER.CUSTOMER_ID%type);


end PACK_DELIVERYDAY;









/
create or replace PACKAGE BODY PACK_DELIVERYDAY is


-- used in conversion to delete unnecessary data from DeliveryDay table
-- (after CustomerDeliveryDays were imported)
procedure CFbReorganize (
        FPnCUSTOMER_ID                            in     CUSTOMER.CUSTOMER_ID%type
) is
begin
	for vCursor in (select department_id from department where customer_id = FPnCUSTOMER_ID) loop
		delete from deliveryday
			where department_id = vCursor.department_id and day_id not in (
								select day_id from deliveryday where department_id = vCursor.department_id
								intersect
								select day_id from customerdeliveryday where customer_id = FPnCUSTOMER_ID and typeofmerchadise = 1);
  end loop;
end;


end PACK_DELIVERYDAY;









/
create or replace PACKAGE PACK_DELIVERYHISTORY is

procedure CFbStoreOrCreate (
        FPnDELIVERYHISTORY_ID                     in out DELIVERYHISTORY.DELIVERYHISTORY_ID%type,
        FPdtDELIVERYDATE                          in out DELIVERYHISTORY.DELIVERYDATE%type,
        FPnCUSTOMER_LINK_ID                       in out DELIVERYHISTORY.CUSTOMER_LINK_ID%type,
        FPnDEPARTMENT_LINK_ID                     in out DELIVERYHISTORY.DEPARTMENT_LINK_ID%type,
        FPnWEEK                                   in out DELIVERYHISTORY.WEEK%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out DELIVERYHISTORY.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnPRODUCT_LINK_ID                        in out DELIVERYHISTORY.PRODUCT_LINK_ID%type,
        FPnSIZEDEFINITION_LINK_ID                 in out DELIVERYHISTORY.SIZEDEFINITION_LINK_ID%type,
        FPnYEAR                                   in out DELIVERYHISTORY.YEAR%type,
        FPnFINISHINGMETHOD_ID                     in out DELIVERYHISTORY.FINISHINGMETHOD_ID%type,
        FPnAMOUNTDELIVERED                        in out DELIVERYHISTORY.AMOUNTDELIVERED%type,
        FPnCURRENCY_ID                            in out DELIVERYHISTORY.CURRENCY_ID%type,
        FPnAMOUNTSHORTAGE                         in out DELIVERYHISTORY.AMOUNTSHORTAGE%type,
        FPnPRICE                                  in out DELIVERYHISTORY.PRICE%type,
        FPnAMOUNTORDERED                          in out DELIVERYHISTORY.AMOUNTORDERED%type,
        FPnDAYNUMBER                              in out DELIVERYHISTORY.DAYNUMBER%type,
        FPnINTERNALPRICE                          in out DELIVERYHISTORY.INTERNALPRICE%type,
        FPnDISCOUNT                               in out DELIVERYHISTORY.DISCOUNT%type,
        FPnPROCESSBUSINESSUNIT_ID                 in out DELIVERYHISTORY.PROCESSBUSINESSUNIT_ID%type,
        FPnINVOICEBUSINESSUNIT_ID                 in out DELIVERYHISTORY.INVOICEBUSINESSUNIT_ID%type,
        FPnSYSTEMUSER_ID                          in out DELIVERYHISTORY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out DELIVERYHISTORY.TIMESTAMP%type);

end PACK_DELIVERYHISTORY;









/
create or replace PACKAGE BODY PACK_DELIVERYHISTORY is


procedure CFbStoreOrCreate (
        FPnDELIVERYHISTORY_ID                     in out DELIVERYHISTORY.DELIVERYHISTORY_ID%type,
        FPdtDELIVERYDATE                          in out DELIVERYHISTORY.DELIVERYDATE%type,
        FPnCUSTOMER_LINK_ID                       in out DELIVERYHISTORY.CUSTOMER_LINK_ID%type,
        FPnDEPARTMENT_LINK_ID                     in out DELIVERYHISTORY.DEPARTMENT_LINK_ID%type,
        FPnWEEK                                   in out DELIVERYHISTORY.WEEK%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out DELIVERYHISTORY.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnPRODUCT_LINK_ID                        in out DELIVERYHISTORY.PRODUCT_LINK_ID%type,
        FPnSIZEDEFINITION_LINK_ID                 in out DELIVERYHISTORY.SIZEDEFINITION_LINK_ID%type,
        FPnYEAR                                   in out DELIVERYHISTORY.YEAR%type,
        FPnFINISHINGMETHOD_ID                     in out DELIVERYHISTORY.FINISHINGMETHOD_ID%type,
        FPnAMOUNTDELIVERED                        in out DELIVERYHISTORY.AMOUNTDELIVERED%type,
        FPnCURRENCY_ID                            in out DELIVERYHISTORY.CURRENCY_ID%type,
        FPnAMOUNTSHORTAGE                         in out DELIVERYHISTORY.AMOUNTSHORTAGE%type,
        FPnPRICE                                  in out DELIVERYHISTORY.PRICE%type,
        FPnAMOUNTORDERED                          in out DELIVERYHISTORY.AMOUNTORDERED%type,
        FPnDAYNUMBER                              in out DELIVERYHISTORY.DAYNUMBER%type,
        FPnINTERNALPRICE                          in out DELIVERYHISTORY.INTERNALPRICE%type,
        FPnDISCOUNT                               in out DELIVERYHISTORY.DISCOUNT%type,
        FPnPROCESSBUSINESSUNIT_ID                 in out DELIVERYHISTORY.PROCESSBUSINESSUNIT_ID%type,
        FPnINVOICEBUSINESSUNIT_ID                 in out DELIVERYHISTORY.INVOICEBUSINESSUNIT_ID%type,
        FPnSYSTEMUSER_ID                          in out DELIVERYHISTORY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out DELIVERYHISTORY.TIMESTAMP%type
) is
	nPackIndication				int;
	nParentPackProductID	product_link.product_link_id%type;
	nParentProductID			product_link.product_link_id%type;
	isPack								product.pack%type;
begin

	nPackIndication:=1;
	nParentPackProductID:=FPnPRODUCT_LINK_ID;
	begin
		select a.parentproduct_id into nParentProductID
			from product a where a.product_id = FPnPRODUCT_LINK_ID;
	exception	when no_data_found then
		nParentProductID:=FPnPRODUCT_LINK_ID;
	end;

    insert into DELIVERYHISTORY(
        DELIVERYHISTORY_ID,
        DELIVERYDATE,
        CUSTOMER_LINK_ID,
        DEPARTMENT_LINK_ID,
        WEEK,
        DISTRIBUTIONPOINT_LINK_ID,
        PRODUCT_LINK_ID,
        SIZEDEFINITION_LINK_ID,
        YEAR,
        FINISHINGMETHOD_ID,
        AMOUNTDELIVERED,
        CURRENCY_ID,
        AMOUNTSHORTAGE,
        PRICE,
        AMOUNTORDERED,
        DAYNUMBER,
        INTERNALPRICE,
        DISCOUNT,
        PROCESSBUSINESSUNIT_ID,
        SYSTEMUSER_ID,
        INVOICEBUSINESSUNIT_ID,
        TIMESTAMP,
        PARENTPACKPRODUCT_LINK_ID, PACKINDICATION, PARENTPRODUCT_LINK_ID, Amountstandard
    )
    values (
        SEQ_DELIVERYHISTORY.nextval,
        FPdtDELIVERYDATE,
        FPnCUSTOMER_LINK_ID,
        FPnDEPARTMENT_LINK_ID,
        FPnWEEK,
        FPnDISTRIBUTIONPOINT_LINK_ID,
        FPnPRODUCT_LINK_ID,
        FPnSIZEDEFINITION_LINK_ID,
        FPnYEAR,
        FPnFINISHINGMETHOD_ID,
        FPnAMOUNTDELIVERED,
        FPnCURRENCY_ID,
        FPnAMOUNTSHORTAGE,
        FPnPRICE,
        FPnAMOUNTORDERED,
        FPnDAYNUMBER,
        FPnINTERNALPRICE,
        FPnDISCOUNT,
        FPnPROCESSBUSINESSUNIT_ID,
        FPnSYSTEMUSER_ID,
        FPnINVOICEBUSINESSUNIT_ID,
        FPdtTIMESTAMP,
				nParentPackProductID, nPackIndication, nParentProductID, 0
    ) returning DELIVERYHISTORY_ID into FPnDELIVERYHISTORY_ID;
  exception
  	when dup_val_on_index then

    update DELIVERYHISTORY
    set
        DELIVERYDATE = FPdtDELIVERYDATE,
        CUSTOMER_LINK_ID = FPnCUSTOMER_LINK_ID,
        DEPARTMENT_LINK_ID = FPnDEPARTMENT_LINK_ID,
        WEEK = FPnWEEK,
        DISTRIBUTIONPOINT_LINK_ID = FPnDISTRIBUTIONPOINT_LINK_ID,
        PRODUCT_LINK_ID = FPnPRODUCT_LINK_ID,
        SIZEDEFINITION_LINK_ID = FPnSIZEDEFINITION_LINK_ID,
        YEAR = FPnYEAR,
        FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID,
        AMOUNTDELIVERED = FPnAMOUNTDELIVERED,
        CURRENCY_ID = FPnCURRENCY_ID,
        AMOUNTSHORTAGE = FPnAMOUNTSHORTAGE,
        PRICE = FPnPRICE,
        AMOUNTORDERED = FPnAMOUNTORDERED,
        DAYNUMBER = FPnDAYNUMBER,
        INTERNALPRICE = FPnINTERNALPRICE,
        DISCOUNT = FPnDISCOUNT,
        PROCESSBUSINESSUNIT_ID = FPnPROCESSBUSINESSUNIT_ID,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        INVOICEBUSINESSUNIT_ID = FPnINVOICEBUSINESSUNIT_ID,
        TIMESTAMP = FPdtTIMESTAMP,
				PARENTPRODUCT_LINK_ID = nParentProductID
    where CUSTOMER_LINK_ID = FPnCUSTOMER_LINK_ID and
          DEPARTMENT_LINK_ID = FPnDEPARTMENT_LINK_ID and
          DISTRIBUTIONPOINT_LINK_ID = FPnDISTRIBUTIONPOINT_LINK_ID and
          PRODUCT_LINK_ID = FPnPRODUCT_LINK_ID and
          SIZEDEFINITION_LINK_ID = FPnSIZEDEFINITION_LINK_ID and
          FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID and
          DELIVERYDATE = FPdtDELIVERYDATE and
          PROCESSBUSINESSUNIT_ID = FPnPROCESSBUSINESSUNIT_ID and
	        PARENTPACKPRODUCT_LINK_ID = nParentPackProductID and
  	      PACKINDICATION = nPackIndication
		returning DELIVERYHISTORY_ID into FPnDELIVERYHISTORY_ID;

end;

end PACK_DELIVERYHISTORY;









/
create or replace PACKAGE PACK_DELIVERYVARIATIONS is
  -- Updated : 29-09-2020 DLA ABS-108518 Delivery variations processbusinessunit_id and internalprocessingbu_id are not filled when creating DV from Pack_multiread

procedure CFbStoreOrCreate (
        FPnDELIVERYVARIATIONS_ID                  in out DELIVERYVARIATIONS.DELIVERYVARIATIONS_ID%type,
        FPnPRODUCT_ID                             in out DELIVERYVARIATIONS.PRODUCT_ID%type,
        FPdtDELIVERYDATE                          in out DELIVERYVARIATIONS.DELIVERYDATE%type,
        FPnORIGIN                                 in out DELIVERYVARIATIONS.ORIGIN%type,
        FPnAMOUNT                                 in out DELIVERYVARIATIONS.AMOUNT%type,
        FPnFINISHINGMETHOD_ID                     in out DELIVERYVARIATIONS.FINISHINGMETHOD_ID%type,
        FPsFIXEDAMOUNT                            in out DELIVERYVARIATIONS.FIXEDAMOUNT%type,
        FPnDISTRIBUTIONPOINT_ID                   in out DELIVERYVARIATIONS.DISTRIBUTIONPOINT_ID%type,
        FPnPACKINGNOTE_ID                         in out DELIVERYVARIATIONS.PACKINGNOTE_ID%type,
        FPnSIZEDEFINITION_ID                      in out DELIVERYVARIATIONS.SIZEDEFINITION_ID%type,
        FPsREFERENCE                              in out DELIVERYVARIATIONS.REFERENCE%type,
        FPsPROCESSED                              in out DELIVERYVARIATIONS.PROCESSED%type,
        FPsUPDATERENTQTY                          in out DELIVERYVARIATIONS.UPDATERENTQTY%type,
        FPnADJUSTMENTREASON_ID                    in out DELIVERYVARIATIONS.ADJUSTMENTREASON_ID%type,
        FPnSYSTEMUSER_ID                          in out DELIVERYVARIATIONS.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out DELIVERYVARIATIONS.TIMESTAMP%type);

end PACK_DELIVERYVARIATIONS;

/
create or replace PACKAGE BODY PACK_DELIVERYVARIATIONS is

procedure CFbStoreOrCreate (
        FPnDELIVERYVARIATIONS_ID                  in out DELIVERYVARIATIONS.DELIVERYVARIATIONS_ID%type,
        FPnPRODUCT_ID                             in out DELIVERYVARIATIONS.PRODUCT_ID%type,
        FPdtDELIVERYDATE                          in out DELIVERYVARIATIONS.DELIVERYDATE%type,
        FPnORIGIN                                 in out DELIVERYVARIATIONS.ORIGIN%type,
        FPnAMOUNT                                 in out DELIVERYVARIATIONS.AMOUNT%type,
        FPnFINISHINGMETHOD_ID                     in out DELIVERYVARIATIONS.FINISHINGMETHOD_ID%type,
        FPsFIXEDAMOUNT                            in out DELIVERYVARIATIONS.FIXEDAMOUNT%type,
        FPnDISTRIBUTIONPOINT_ID                   in out DELIVERYVARIATIONS.DISTRIBUTIONPOINT_ID%type,
        FPnPACKINGNOTE_ID                         in out DELIVERYVARIATIONS.PACKINGNOTE_ID%type,
        FPnSIZEDEFINITION_ID                      in out DELIVERYVARIATIONS.SIZEDEFINITION_ID%type,
        FPsREFERENCE                              in out DELIVERYVARIATIONS.REFERENCE%type,
        FPsPROCESSED                              in out DELIVERYVARIATIONS.PROCESSED%type,
        FPsUPDATERENTQTY                          in out DELIVERYVARIATIONS.UPDATERENTQTY%type,
        FPnADJUSTMENTREASON_ID                    in out DELIVERYVARIATIONS.ADJUSTMENTREASON_ID%type,
        FPnSYSTEMUSER_ID                          in out DELIVERYVARIATIONS.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out DELIVERYVARIATIONS.TIMESTAMP%type
) is
businessunitid BUSINESSUNIT.BUSINESSUNIT_ID%type;
begin
     select CA.PROCESSBUSINESSUNIT_ID into businessunitid 
            from CUSTOMERACTIVITIES ca join DEPARTMENT DT on CA.CUSTOMER_ID = DT.CUSTOMER_ID
                 join DISTRIBUTIONPOINT DP on DT.DEPARTMENT_ID = DP.DEPARTMENT_ID 
                 join PRODUCTGROUP PG on CA.ACTIVITY_ID = PG.ACTIVITY_ID
                 join PRODUCT P on P.PRODUCTGROUP_ID = PG.PRODUCTGROUP_ID
            where DP.DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID    
            and P.PRODUCT_ID = FPnPRODUCT_ID
            and rownum < 2;
    insert into DELIVERYVARIATIONS(
        DELIVERYVARIATIONS_ID,
        PRODUCT_ID,
        DELIVERYDATE,
        ORIGIN,
        AMOUNT,
        FINISHINGMETHOD_ID,
        FIXEDAMOUNT,
        DISTRIBUTIONPOINT_ID,
        PACKINGNOTE_ID,
        SIZEDEFINITION_ID,
        REFERENCE,
    		PROCESSED,
        UPDATERENTQTY,
        ADJUSTMENTREASON_ID,
        SYSTEMUSER_ID,
        TIMESTAMP,
        PROCESSBUSINESSUNIT_ID,
        INTERNALPROCESSINGBU_ID
    )
    values (
        SEQ_DELIVERYVARIATIONS.nextval,
        FPnPRODUCT_ID,
        FPdtDELIVERYDATE,
        FPnORIGIN,
        FPnAMOUNT,
        FPnFINISHINGMETHOD_ID,
        FPsFIXEDAMOUNT,
        FPnDISTRIBUTIONPOINT_ID,
        FPnPACKINGNOTE_ID,
        FPnSIZEDEFINITION_ID,
        FPsREFERENCE,
		    FPsPROCESSED,
        FPsUPDATERENTQTY,
        FPnADJUSTMENTREASON_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
        businessunitid,
        businessunitid
    );
    select SEQ_DELIVERYVARIATIONS.currval into FPnDELIVERYVARIATIONS_ID from dual;

    exception
  	 when dup_val_on_index then
      if(FPnPACKINGNOTE_ID is null) then
        update DELIVERYVARIATIONS
        set
          PRODUCT_ID = FPnPRODUCT_ID,
          DELIVERYDATE = FPdtDELIVERYDATE,
          ORIGIN = FPnORIGIN,
          AMOUNT = FPnAMOUNT,
          FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID,
          FIXEDAMOUNT = FPsFIXEDAMOUNT,
          DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID,
          PACKINGNOTE_ID = FPnPACKINGNOTE_ID,
          SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID,
          REFERENCE = FPsREFERENCE,
		  PROCESSED = FPsPROCESSED,
          UPDATERENTQTY = FPsUPDATERENTQTY,
          ADJUSTMENTREASON_ID = FPnADJUSTMENTREASON_ID,
          SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
          TIMESTAMP = FPdtTIMESTAMP
        where DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID and
              PRODUCT_ID = FPnPRODUCT_ID and
              SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID and
              FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID and
              PACKINGNOTE_ID is null and
              DELIVERYDATE = FPdtDELIVERYDATE and
              ORIGIN = FPnORIGIN;
      else
        update DELIVERYVARIATIONS
        set
          PRODUCT_ID = FPnPRODUCT_ID,
          DELIVERYDATE = FPdtDELIVERYDATE,
          ORIGIN = FPnORIGIN,
          AMOUNT = FPnAMOUNT,
          FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID,
          FIXEDAMOUNT = FPsFIXEDAMOUNT,
          DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID,
          PACKINGNOTE_ID = FPnPACKINGNOTE_ID,
          SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID,
          REFERENCE = FPsREFERENCE,
          UPDATERENTQTY = FPsUPDATERENTQTY,
          ADJUSTMENTREASON_ID = FPnADJUSTMENTREASON_ID,
          SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
          TIMESTAMP = FPdtTIMESTAMP
        where DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID and
              PRODUCT_ID = FPnPRODUCT_ID and
              SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID and
              FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID and
              PACKINGNOTE_ID = FPnPACKINGNOTE_ID and
              DELIVERYDATE = FPdtDELIVERYDATE and
              ORIGIN = FPnORIGIN;
      end if;
    FPnDELIVERYVARIATIONS_ID := -1;
end;

end PACK_DELIVERYVARIATIONS;

/
create or replace package PACK_DOS_CONVERSION is

procedure FillStockRoomLocationUI;
procedure MakeCorrectionsInStockQuantity;

end PACK_DOS_CONVERSION;

/
create or replace package body PACK_DOS_CONVERSION is

procedure FillStockRoomLocationUI
is
	stockRoomLocationID	stockroomlocation.stockroomlocation_id%type;
	absUserID		systemuser.systemuser_id%type;
	statusStockID		status.status_id%type;
	stockRoomID		stockroom.stockroom_id%type;
begin

	dbms_output.put_line('-------------------------------------------------------------');
	dbms_output.put_line('update uniqueitemfixed info');
	dbms_output.put_line('-------------------------------------------------------------');
	begin
		select s.systemuser_id into absUserID from systemuser s where s.username = 'ABSADM';
	exception when others then absUserID:=0;
	end;

	select s.status_id into statusStockID from status s where s.statustype = 'UI' and s.code = '10';

	for c1 in (select distinct ui.businessunit_id, bu.code
			from uniqueitem ui, uniqueitemfixedinfo uif, product p, businessunit bu
			where ui.uniqueitem_id = uif.uniqueitem_id and
				ui.product_id = p.product_id and
				ui.businessunit_id = bu.businessunit_id and
				ui.status_id = statusStockID and
				p.recordpassivestock = 'Y' and
				uif.stockroomlocation_id is null
			) loop

		dbms_output.put_line('BU '||c1.code);
		stockRoomLocationID:=null;
		for c2 in (select sl.stockroomlocation_id
				from stockroomsservicingbu sbu, stockroomlocation sl
				where sbu.stockroom_id = sl.stockroom_id and
					sl.locationcode = '-' and
					sbu.businessunit_id = c1.businessunit_id
				order by sbu.priority asc) loop
			stockRoomLocationID:=c2.stockroomlocation_id;
			exit;
		end loop;
		if (stockRoomLocationID is null) then
			dbms_output.put_line('No stock room location - found for BU '||c1.code);
			begin
				select sbu.stockroom_id into stockRoomID
				from stockroomsservicingbu sbu
				where sbu.businessunit_id = c1.businessunit_id and
					sbu.priority = (select min(x.priority) from stockroomsservicingbu x
							where x.businessunit_id = sbu.businessunit_id);
				insert into stockroomlocation (stockroomlocation_id, stockroom_id,
					rowcode, locationcode, pickingsequence, volume,
					makeempty, overflowlocation, systemuser_id, timestamp)
				values (seq_stockroomlocation.nextval, stockRoomID, '-', '-', 9999, 9999,
					'Y', 'Y', absUserID, sysdate)
				returning stockroomlocation_id into stockRoomLocationID;
				dbms_output.put_line('	Stock room location - created for BU '||c1.code);
			exception when others then null;
			end;
		end if;

		if (stockRoomLocationID is not null) then
			update uniqueitemfixedinfo uif
				set uif.stockroomlocation_id = stockRoomLocationID,
					uif.timestamp = sysdate,
					uif.systemuser_id = absUserID
				where uif.stockroomlocation_id is null and
					exists (select ui.uniqueitem_id from uniqueitem ui, product p
						where ui.uniqueitem_id = uif.uniqueitem_id and
							ui.product_id = p.product_id and
							ui.businessunit_id = c1.businessunit_id and
							p.recordpassivestock = 'Y' and
							ui.status_id = statusStockID);
			dbms_output.put_line(sql%rowcount||' unique items updated.');
		end if;
		dbms_output.new_line;
	end loop;
	commit;
end;

procedure MakeCorrectionsInStockQuantity
is
  absUserID         systemuser.systemuser_id%type;
  statusStockID     status.status_id%type;
  stockDefItemID    stockdefinitionperitem.stockdefinitionperitem_id%type;
  stockResGradeID   stockreservationpergrade.stockreservationpergrade_id%type;
  stdLocPerProdID   standardlocationperproduct.standardlocationperproduct_id%type;
  qtyUI             stockquantity.qtyunique%type;
  qtyUIM            stockquantity.qtyuniquewithmodifications%type;
  countLines        int:=0;
  newLine           boolean;
begin

  dbms_output.enable(2000000);
  dbms_output.put_line('-------------------------------------------------------------');
  dbms_output.put_line('update stockquantity');
  dbms_output.put_line('-------------------------------------------------------------');
  begin
    select s.systemuser_id into absUserID from systemuser s where s.username = 'ABSADM';
  exception when others then absUserID:=0;
  end;
  select s.status_id into statusStockID from status s where s.statustype = 'UI' and s.code = '10';


  -- make stockquantity.qtyunique = 0, qtyuniquewithmodifications = 0 if there are no items in stock
  for c in (select sq.stockreservationpergrade_id, sq.stockroomlocation_id
            from stockroomlocation sl, stockdefinitionperitem si, stockreservationpergrade sg, stockquantity sq
            where sl.stockroom_id = si.stockroom_id and
                  si.stockdefinitionperitem_id = sg.stockdefinitionperitem_id and
                  sq.stockreservationpergrade_id = sg.stockreservationpergrade_id and
                  sq.stockroomlocation_id = sl.stockroomlocation_id and
                  (sq.qtyunique != 0 or sq.qtyuniquewithmodifications != 0) and
                  not exists (select ui.uniqueitem_id
                              from uniqueitem ui, uniqueitemfixedinfo uifi
                              where ui.uniqueitem_id = uifi.uniqueitem_id and
                                    ui.status_id = statusStockID and
                                    ((ui.relatedcustomer_id = si.customer_id) or
                                     (ui.relatedcustomer_id is null and si.customer_id is null)) and
                                    ui.customerowned = si.customerowned and
                                    ui.product_id = si.product_id and
                                    ui.sizedefinition_id = si.sizedefinition_id and
                                    uifi.stockroomlocation_id = sq.stockroomlocation_id and
                                    uifi.qualitygrade_id = sg.qualitygrade_id)) loop
    update stockquantity sq
      set sq.qtyunique = 0, sq.qtyuniquewithmodifications = 0, sq.systemuser_id = absUserID, timestamp = sysdate
      where sq.stockreservationpergrade_id = c.stockreservationpergrade_id and
            sq.stockroomlocation_id = c.stockroomlocation_id;
  end loop;

  for c in (select sl.stockroom_id, sl.stockroomlocation_id, ui.product_id, ui.sizedefinition_id,
                   ui.relatedcustomer_id, ui.customerowned, uifi.qualitygrade_id, p.supplier_id, sl.overflowlocation,
                   sum((select count(*) from uniqueitem x
                        where x.uniqueitem_id = ui.uniqueitem_id and
                              not exists (select uim.uniqueitem_id from uniqueitemmodification uim, modification m
                                          where uim.uniqueitem_id = x.uniqueitem_id and
                                                uim.modification_id = m.modification_id and
                                                m.stockwithstandardsize = 'N'))) cUI,
                   sum((select count(*) from uniqueitem x
                        where x.uniqueitem_id = ui.uniqueitem_id and
                              exists (select uim.uniqueitem_id from uniqueitemmodification uim, modification m
                                      where uim.uniqueitem_id = x.uniqueitem_id and
                                            uim.modification_id = m.modification_id and
                                            m.stockwithstandardsize = 'N'))) cUIM
            from uniqueitem ui, uniqueitemfixedinfo uifi, stockroomlocation sl, product p
            where ui.uniqueitem_id = uifi.uniqueitem_id and
                  uifi.stockroomlocation_id = sl.stockroomlocation_id and
                  ui.product_id = p.product_id and
                  uifi.qualitygrade_id is not null and
                  ui.status_id = statusStockID
            group by sl.stockroom_id, sl.stockroomlocation_id, ui.product_id, ui.sizedefinition_id,
                  ui.relatedcustomer_id, ui.customerowned, uifi.qualitygrade_id, p.supplier_id, sl.overflowlocation) loop

    newLine:=false;

    -- stockdefinitionperitem_id
    begin
      if (c.relatedcustomer_id is not null) then
        select sdpi.stockdefinitionperitem_id into stockDefItemID from stockdefinitionperitem sdpi
        where sdpi.stockroom_id = c.stockroom_id and
              sdpi.product_id = c.product_id and sdpi.sizedefinition_id = c.sizedefinition_id and
              sdpi.customer_id = c.relatedcustomer_id and sdpi.customerowned = c.customerowned;
      else
        select sdpi.stockdefinitionperitem_id into stockDefItemID from stockdefinitionperitem sdpi
        where sdpi.stockroom_id = c.stockroom_id and
              sdpi.product_id = c.product_id and sdpi.sizedefinition_id = c.sizedefinition_id and
              sdpi.customer_id  is null and sdpi.customerowned = c.customerowned;
      end if;
    exception when no_data_found then
      insert into stockdefinitionperitem (
             stockdefinitionperitem_id, stockroom_id, product_id, sizedefinition_id,
             customer_id, customerowned, minqtynew, minqtyused, maxqtynew, maxqtyused,
             defaultsupplier_id, systemuser_id, timestamp)
      values (
             seq_stockdefinitionperitem.nextval, c.stockroom_id, c.product_id, c.sizedefinition_id,
             c.relatedcustomer_id, c.customerowned, 0, 0, 999, 999,
             c.supplier_id, absUserID, sysdate)
      returning stockdefinitionperitem_id into stockDefItemID;
      dbms_output.put_line('insert stockdefinitionperitem');
      newLine:=true;
    end;

    -- stockreservationpergrade
    begin
      select srpg.stockreservationpergrade_id into stockResGradeID from stockreservationpergrade srpg
      where srpg.stockdefinitionperitem_id = stockDefItemID and srpg.qualitygrade_id = c.qualitygrade_id;
    exception when no_data_found then
      insert into stockreservationpergrade (
             stockreservationpergrade_id, stockdefinitionperitem_id, qualitygrade_id, qtyuniquereserved, qtynonuniquereserved,
             qtyuniquewiithmodifreserved, qtynonunique, qtyuniqueordered, qtynonuniqueordered,
             qtyuniqueordereddirectissue, qtynonuniqueordereddirectissue, systemuser_id, timestamp)
      values (
             seq_stockreservationpergrade.nextval, stockDefItemID, c.qualitygrade_id, 0, 0,
             0, 0, 0, 0, 0, 0, absUserID, sysdate)
      returning stockreservationpergrade_id into stockResGradeID;
      dbms_output.put_line('insert stockreservationpergrade');
      newLine:=true;
    end;

    -- stockquantity
    begin
      select sq.qtyunique, sq.qtyuniquewithmodifications into qtyUI, qtyUIM
      from stockquantity sq
      where sq.stockreservationpergrade_id = stockResGradeID and sq.stockroomlocation_id = c.stockroomlocation_id;

      if (c.cUI!=qtyUI or c.cUIM!=qtyUIM) then
        update stockquantity
        set qtyunique = c.cUI, qtyuniquewithmodifications = c.cUIM, systemuser_id = absUserID, timestamp = sysdate
        where stockreservationpergrade_id = stockResGradeID and stockroomlocation_id = c.stockroomlocation_id;
        dbms_output.put_line('update stockquantity qtyUnique '||c.cUI||'/old qtyUnique '||qtyUI||' qtyUniqueModif '||c.cUIM||'/old qtyUniqueModif '||qtyUIM);
        dbms_output.put_line('stockroom_id/stockroomlocation_id/product_id/sizedefinition_id/customer_id/customerowned '||
                             c.stockroom_id||'/'||c.stockroomlocation_id||'/'||c.product_id||'/'||c.sizedefinition_id||'/'||
                             c.relatedcustomer_id||'/'||c.customerowned);
        dbms_output.put_line('stockdefinitionperitem_id/stockreservationpergrade_id/qualitygrade_id '||
                             stockDefItemID||'/'||stockResGradeID||'/'||c.qualitygrade_id);
        newLine:=true;
      end if;
    exception when no_data_found then
      insert into stockquantity(
             stockreservationpergrade_id, stockroomlocation_id, qtyunique, qtyuniquewithmodifications, systemuser_id, timestamp)
      values (stockResGradeID, c.stockroomlocation_id, c.cUI, c.cUIM, absUserID, sysdate);
      dbms_output.put_line('insert stockquantity qtyUnique '||c.cUI||' qtyUniqueModif '||c.cUIM);
      dbms_output.put_line('stockroom_id/stockroomlocation_id/product_id/sizedefinition_id/customer_id/customerowned '||
                           c.stockroom_id||'/'||c.stockroomlocation_id||'/'||c.product_id||'/'||c.sizedefinition_id||'/'||
                           c.relatedcustomer_id||'/'||c.customerowned);
      dbms_output.put_line('stockdefinitionperitem_id/stockreservationpergrade_id/qualitygrade_id '||
                           stockDefItemID||'/'||stockResGradeID||'/'||c.qualitygrade_id);
      newLine:=true;
    end;

    -- standardlocationperproduct
    if (c.overflowlocation != 'Y') then
      begin
        select slpp.standardlocationperproduct_id into stdLocPerProdID from standardlocationperproduct slpp
        where slpp.stockroomlocation_id = c.stockroomlocation_id and slpp.product_id = c.product_id;
      exception when no_data_found then
        insert into standardlocationperproduct(
               standardlocationperproduct_id, stockroomlocation_id, product_id, priority,
               customerowned, customer_id, allowedgrade, definepersize, active, systemuser_id, timestamp)
        values (
               seq_standardlocationperproduct.nextval, c.stockroomlocation_id, c.product_id, 1,
               c.customerowned, c.relatedcustomer_id, 'B', 'N', 'Y', absUserID, sysdate);
        dbms_output.put_line('insert standardlocationperproduct');
        dbms_output.put_line('stockroom_id/stockroomlocation_id/product_id/sizedefinition_id/customer_id/customerowned '||
                             c.stockroom_id||'/'||c.stockroomlocation_id||'/'||c.product_id||'/'||c.sizedefinition_id||'/'||
                             c.relatedcustomer_id||'/'||c.customerowned);
        dbms_output.put_line('stockdefinitionperitem_id/stockreservationpergrade_id/qualitygrade_id '||
                             stockDefItemID||'/'||stockResGradeID||'/'||c.qualitygrade_id);
        newLine:=true;
      end;
    end if;
    if newline then dbms_output.new_line; end if;
    countLines:=countLines+1;
  end loop;
  --dbms_output.put_line(countLines);

  commit;

end;



end PACK_DOS_CONVERSION;

/
create or replace package PACK_DWH_CATALOG_EXPORT is
  -- Author  : HVH
  -- Created : 06-03-2007
  -- Purpose : Export DWH into csv
  function DWH_Catalog_Export return boolean;
end PACK_DWH_CATALOG_EXPORT;

/
create or replace package body PACK_DWH_CATALOG_EXPORT is
  --internal declarations
  utlfiledir       varchar2(32) := 'C:\TEMP\';
  exportfilename   varchar2(32) := 'DWH_CATALOG_TRANSLATIONS.CSV';
  exportfilehandle utl_file.file_type;
procedure open_exportfile is
  begin
    --create and open the file that will contain the export
    if utl_file.is_open(exportfilehandle) = false then
      begin
        exportfilehandle := utl_file.fopen(utlfiledir, exportfilename, 'w');
      end;
    end if;
  exception
    when others then
      begin
        --messages for user in output mode
        dbms_output.put_line('Error during open_exportfile.');
        dbms_output.put_line('      file directory ' || utlfiledir);
        dbms_output.put_line('      file name      ' || exportfilename);
        dbms_output.put_line(substr(sqlerrm, 1, 200));
      end;
  end open_exportfile;
  procedure close_exportfile is
  begin
    --close the export file
    if utl_file.is_open(exportfilehandle) = true then
      begin
        utl_file.fclose(exportfilehandle);
      end;
    end if;
  exception
    when others then
      begin
        --messages for user in output mode
        dbms_output.put_line('Error during close_exportfile.');
        dbms_output.put_line('      file directory ' || utlfiledir);
        dbms_output.put_line('      file name      ' || exportfilename);
        dbms_output.put_line(substr(sqlerrm, 1, 200));
      end;
  end close_exportfile;
procedure dump_to_csv(p_query varchar2) is
    l_thecursor   integer default dbms_sql.open_cursor;
    l_columnvalue varchar2(4000);
    l_status      integer;
    l_colcnt      number := 0;
    l_separator   varchar2(1);
    l_desctbl     dbms_sql.desc_tab;
  begin
    --initialize, create export file, open/describe cursor
    dbms_sql.parse(l_thecursor, p_query, dbms_sql.native);
    dbms_sql.describe_columns(l_thecursor, l_colcnt, l_desctbl);
    --gather columns to be exported in sql statement
    for i in 1 .. l_colcnt loop
      begin
        dbms_sql.define_column(l_thecursor, i, l_columnvalue, 4000);
        l_separator := ';';
      end;
    end loop;
    --start the cursor with sql statement for export
    l_status := dbms_sql.execute(l_thecursor);
    --loop through all records for export
    while (dbms_sql.fetch_rows(l_thecursor) > 0) loop
      begin
        l_separator := '';
        for i in 1 .. l_colcnt loop
          begin
            dbms_sql.column_value(l_thecursor, i, l_columnvalue);
            utl_file.put(exportfilehandle,
                         l_separator || to_char(l_columnvalue));
            l_separator := ';';
          end;
        end loop;
        utl_file.put(exportfilehandle, l_separator);
        utl_file.new_line(exportfilehandle);
      end;
    end loop;
    --finalize close cursor and file
    dbms_sql.close_cursor(l_thecursor);
  exception
    when utl_file.invalid_path then
      raise_application_error(-20100, 'Invalid Path');
    when utl_file.invalid_mode then
      raise_application_error(-20101, 'Invalid Mode');
    when utl_file.invalid_operation then
      raise_application_error(-20102, 'Invalid Operation');
    when utl_file.invalid_filehandle then
      raise_application_error(-20103, 'Invalid FileHandle');
    when utl_file.write_error then
      raise_application_error(-20104, 'Write Error');
    when utl_file.read_error then
      raise_application_error(-20105, 'Read Error');
    when utl_file.internal_error then
      raise_application_error(-20106, 'Internal Error');
    when others then
      begin
        dbms_output.put_line('Error during export ' || exportfilename ||
                             ' in : ' || utlfiledir);
        dbms_output.put_line('Export line: ' || substr(p_query, 0, 200));
        dbms_output.put_line('Status : ' || to_char(l_status));
        raise;
      end;
  end dump_to_csv;
function DWH_Catalog_Export return boolean is
  begin
        --start export
        open_exportfile;
        --collect the data to be exported
        dbms_output.put_line('Export from table DWH_PRESENTATION_CATALOG_DESC');
        dump_to_csv('select pd.languagecode, p.businessname, pd.displayname from dwh_presentationcatalog p, dwh_presentationcatalog_desc pd where
pd.dwh_presentationcatalog_id = p.dwh_presentationcatalog_id');
        close_exportfile;
        --messages for user in output mode
        dbms_output.put_line('      file directory ' || utlfiledir);
        dbms_output.put_line('      file name      ' || exportfilename);
        dbms_output.put_line('Succesfully exported.');
    return true;
  exception
    when others then
      begin
        rollback;
        --messages for user in output mode
        dbms_output.put_line('Export error!');
        dbms_output.put_line(substr(sqlerrm, 1, 200));
        return false;
      end;
  end;
end PACK_DWH_CATALOG_EXPORT;

/
create or replace package pack_dwh_price_history is

  --Version 2.0
  --First run upd_dwh_price_history_settings, for the setup, with right parallel degree
  --Then run fill_dwh_price_history, with the right number of historical levels and optional future prices
  --28-May-2024 First release

  --Setup, run first upd_dwh_price_history_settings
  procedure upd_dwh_price_history_settings(fp_parallel_degree in number default 8);

  --Fills dwh_price_history for each active PLPC
  procedure fill_dwh_price_history(fp_hist_lvl      in number default 1,
                                   fp_future_prices in varchar2 default 'N');

end pack_dwh_price_history;
/
create or replace package body pack_dwh_price_history is

  procedure write_log(fp_message in varchar2, fp_priority in number) is
  begin
    /* Logging: write message in ABSLOG with these priorities:
    1 = Message
    2 = Warning
    3 = Error */
    abslogwrite.abslog_write(5, 'pack_dwh_price_history', null, fp_priority, fp_message);
    begin
      dbms_output.put_line(fp_message);
    exception
      when others then
        null; --ok no output does not matter
    end;
  end write_log;

  procedure upd_dwh_price_history_settings(fp_parallel_degree in number default 8) is
    lv_wash_log_cog_sql varchar2(1000);
    lv_fm_sql           varchar2(1000);
    lv_bm_sql_wash      varchar2(1000);
  begin
    lv_wash_log_cog_sql := 'case plpc.chargewashesonlyforcog
                                  when 2 then 1
                                  when 3 then 2
                                  else 0
                                end';
    lv_fm_sql           := 'plpc.finishingmethod_id,';
    lv_bm_sql_wash      := 'and not (plpc.billingmethod = 3 and plpc.priceusage = 2)';
    --cleanup current data
    execute immediate 'truncate table dwh_price_history_settings';
    --fill again
    insert into dwh_price_history_settings
      (price_type, parallel_degree, price_type_pck_call, price_type_desc, price_type_sql,
       price_type_hist_sql, price_type_split_sql)
      select iltd.invoicelinetype_id, nvl(fp_parallel_degree, 8),
             decode(ilt.factorydescription, 'Delivery (wash)', 'pack_price.wash_price_details',
                     'Rent', 'pack_price.rent_price_details', 'Replacement charge',
                     'pack_price.replacement_price_details', 'Sales', 'pack_price.sales_price_details',
                     'n/a') price_type_pck_call, nvl(iltd.description, ilt.factorydescription), null,
             null, null
      from   invoicelinetype ilt
      left   outer join invoicelinetype_desc iltd
      on     iltd.invoicelinetype_id = ilt.invoicelinetype_id
      where  iltd.language_id = (select min(pla.language_id) from plant pla)
      and    iltd.invoicelinetype_id in (2, 1);
    commit;
    --update settings
    update dwh_price_history_settings t
    set    t.price_type_sql = 'select /*+enable_parallel_dml parallel(' ||
                               nvl(fp_parallel_degree, 8) || ')*/ ' || t.price_type || ' price_type,
  plpc.productlistpercustomer_id,
  plpc.customer_id,
  plpc.product_id,
  plpc.sizedefinition_id,
  plpc.finishingmethod_id,
  plpc.chargewashesonlyforcog,
  nvl(plpc.specificweighingcategory_id, p.weighingcategory_id) weighingcategory_id,
  p.typeofmerchandise,
  cu.decimals currencydecimals,
  plpc.costpriceinclwashsalesprice,
  plpc.costpriceinclrentprice,
  plpc.costpriceinclweightprice,
  plpc.costpriceinclcostreportprice,
  null price_type_code,
  null price_type_description,
  ''' || t.price_type_desc || ''' line_type_description,
  ' || t.price_type_pck_call ||
                               '(plpc.customer_id,
                                plpc.product_id,
                                plpc.sizedefinition_id,' || case
                                 when t.price_type <> 5 then
                                  '
                                ' || lv_fm_sql || '
                                '
                                 else
                                  null
                               end || ':2' || case
                                 when t.price_type = 2 then
                                  ',
                                ' || lv_wash_log_cog_sql
                                 else
                                  null
                               end || ') price_details,
  null price,
  1 price_level,
  null price_chf,
  null price_gc,
  null price_start_date,
  null price_list_code,
  null price_result_code,
  null price_result_description,
  null price_list_description,
  null insert_time_stamp,
  null price_found
from productlistpercustomer plpc
  join customer c on c.customer_id = plpc.customer_id
  join currency cu on cu.currency_id = c.currency_id
  join product p on p.product_id = plpc.product_id
where trunc(sysdate) between plpc.dateactive and plpc.dateinactive
and c.active = ''Y'' ' || case
                                 when t.price_type = 2 then
                                  lv_bm_sql_wash
                                 else
                                  null
                               end;
    commit;
    --
    update dwh_price_history_settings t
    set    t.price_type_hist_sql = 'select /*+enable_parallel_dml parallel(' ||
                                    nvl(fp_parallel_degree, 8) || ')*/ ' || t.price_type || ' price_type,
  plpc.productlistpercustomer_id,
  plpc.customer_id,
  plpc.product_id,
  plpc.sizedefinition_id,
  plpc.finishingmethod_id,
  plpc.chargewashesonlyforcog,
  plpc.weighingcategory_id,
  plpc.typeofmerchandise,
  plpc.currencydecimals,
  plpc.costpriceinclwashsalesprice,
  plpc.costpriceinclrentprice,
  plpc.costpriceinclweightprice,
  plpc.costpriceinclcostreportprice,
  plpc.price_type_code,
  plpc.price_type_description,
  plpc.line_type_description,
  ' || t.price_type_pck_call ||
                                    '(plpc.customer_id,
                                plpc.product_id,
                                plpc.sizedefinition_id, ' || case
                                      when t.price_type <> 5 then
                                       '
                                ' || lv_fm_sql || '
                                '
                                      else
                                       null
                                    end || 'plpc.price_start_date - 1' || case
                                      when t.price_type = 2 then
                                       ',
                                ' || lv_wash_log_cog_sql
                                      else
                                       null
                                    end || ') price_details,
  null price,
  :1 price_level,
  null price_chf,
  null price_gc,
  null price_start_date,
  null price_list_code,
  null price_result_code,
  null price_result_description,
  null price_list_description,
  null insert_time_stamp,
  null price_found
from dwh_price_history plpc
where plpc.price_level = :2
and plpc.price_found = ''Y''
and plpc.price_type = ' || t.price_type;
    commit;
    --
    update dwh_price_history_settings t
    set    t.price_type_split_sql = 'update /*+enable_parallel_dml parallel(' ||
                                     nvl(fp_parallel_degree, 8) ||
                                     ')*/ dwh_price_history t
  set t.price = substr(t.price_details, 1, 12),
  t.price_start_date = to_date(substr(t.price_details, 14, 8), ''yyyymmdd''),
  t.price_gc = substr(t.price_details, 22, 1),
  t.price_list_code = trim(substr(t.price_details, 23, 6) || substr(t.price_details, 181, 9)),
  t.price_list_description = trim(substr(t.price_details, 29, 40)),
  t.price_result_code = substr(t.price_details, 69, 1),
  t.price_result_description = trim(substr(t.price_details, 70, 80)),
  t.price_type_code = substr(t.price_details, 150, 1),
  t.price_type_description = trim(substr(t.price_details, 151, 30))
where t.price_start_date is null and t.price_found = ''Y'''
    where  t.price_type in (2);
    commit;
    --
    update dwh_price_history_settings t
    set    t.price_type_split_sql = 'update /*+enable_parallel_dml parallel(' ||
                                     nvl(fp_parallel_degree, 8) ||
                                     ')*/ dwh_price_history t set t.price = substr(t.price_details, 1, 12),
  t.price_start_date = to_date(substr(t.price_details, 14, 8), ''yyyymmdd''),
  t.price_gc = substr(t.price_details, 22, 1),
  t.price_list_code = trim(substr(t.price_details, 23, 6) || substr(t.price_details, 203, 9)),
  t.price_list_description = trim(substr(t.price_details, 29, 40)),
  t.price_result_code = substr(t.price_details, 69, 1),
  t.price_result_description = trim(substr(t.price_details, 70, 80)),
  t.price_type_code = substr(t.price_details, 150, 1),
  t.price_type_description = trim(substr(t.price_details, 151, 30))
where t.price_start_date is null and t.price_found = ''Y'''
    where  t.price_type in (1);
    commit;
    write_log('Finished upd_dwh_price_history_settings', 1);
  exception
    when others then
      begin
        write_log(sqlerrm, 3);
      end;
  end upd_dwh_price_history_settings;

  procedure fill_dwh_price_history(fp_hist_lvl      in number default 1,
                                   fp_future_prices in varchar2 default 'N') is
    gv_message            varchar2(2000);
    gv_user_exception     exception;
    gv_cursor             sys_refcursor;
    gv_commit_num         number := 8000;
    gv_numberofrows       number;
    gv_numberofrows_total number;
    type array is table of dwh_price_history%rowtype;
    gv_data              array;
    gv_hist_lvl          number;
    gv_hist_start_date   varchar2(8);
    gv_hist_start_date_d date;

    procedure initialize is
    begin
      --analyze tables
      execute immediate('analyze table productlistpercustomer estimate statistics');
      execute immediate('analyze table generalpricelist estimate statistics');
      execute immediate('analyze table generalwashprice estimate statistics');
      execute immediate('analyze table generalrentprice estimate statistics');
      ----------------
      if nvl(fp_hist_lvl, 1) between 0 and 4 then
        gv_hist_lvl := nvl(fp_hist_lvl, 1);
      else
        gv_hist_lvl := 0; --no history
      end if;
      if nvl(upper(fp_future_prices), 'N') = 'Y' then
        gv_hist_start_date := '20991231';
      else
        gv_hist_start_date := to_char(sysdate, 'yyyymmdd');
      end if;
      gv_numberofrows       := 0;
      gv_numberofrows_total := 0;
      gv_message            := 'Truncate table dwh_price history';
      execute immediate 'truncate table dwh_price_history';
    end initialize;

    procedure insert_prices is
      gv_parallel_degree number;

      procedure run_query(gv_query in clob) is
      begin
        --for each record split the price_details into separate columns
        execute immediate gv_query;
        commit;
      end run_query;

      procedure insert_hist_prices(fp_price_type_desc      in varchar,
                                   fp_price_type_hist_sql  in clob,
                                   fp_price_type_split_sql in clob) is
        lv_curr_lvl number;
        lv_prev_lvl number;
      begin
        -- fill historic levels
        for y in 2 .. gv_hist_lvl + 1 loop
          begin
            gv_numberofrows_total := gv_numberofrows_total + gv_numberofrows;
            gv_numberofrows       := 0;
            lv_curr_lvl           := y;
            lv_prev_lvl           := y - 1;
            gv_message            := 'Load price_details for price_type: ' || fp_price_type_desc ||
                                     ' level: ' || to_char(y);
            open gv_cursor for fp_price_type_hist_sql
              using lv_curr_lvl, lv_prev_lvl;
            loop
              fetch gv_cursor bulk collect
                into gv_data limit gv_commit_num;
              forall i in 1 .. gv_data.count
                insert into dwh_price_history values gv_data (i);
              gv_numberofrows := gv_numberofrows + gv_data.count;
              commit;
              exit when gv_cursor%notfound;
            end loop;
            close gv_cursor;
            commit;
            gv_message := 'Load price_details for price_type: ' || fp_price_type_desc || ' level: ' ||
                          to_char(y) || '. Total number of rows processed: ' ||
                          to_char(gv_numberofrows);
            write_log(gv_message, 1);
            --After filling each level delete the records where no price was found
            gv_message := 'Updating records without price for level: ' || y;
            run_query('update /*+enable_parallel_dml parallel(' || gv_parallel_degree ||
                      ')*/ dwh_price_history
          set    price_found = case
                                 when substr(price_details, 12, 1) = '' '' then
                                  ''N''
                                 else
                                  ''Y''
                               end
          where  price_found is null');
            run_query(fp_price_type_split_sql);
          end;
        end loop;
      end insert_hist_prices;

      procedure chk_price_found is
      begin
        --clear the records where no price was found, no need to search further
        gv_message := 'Update the records to check if price was found';
        run_query('update /*+enable_parallel_dml parallel(' || gv_parallel_degree ||
                  ')*/ dwh_price_history
          set    price_found = case
                                 when substr(price_details, 12, 1) = '' '' then
                                  ''N''
                                 else
                                  ''Y''
                               end
          where  price_found is null');
      end chk_price_found;

      procedure pricenotrelevant is
      begin
        --Pricenotrelevant
        gv_message := 'Remove when Price not relevant';
        run_query('delete /*+enable_parallel_dml parallel(' || gv_parallel_degree ||
                  ')*/ from dwh_price_history where substr(price_details,70,18) = ''Price not relevant''');
      end pricenotrelevant;

      procedure set_price_chf is
      begin
        --set current price value F = future price, C = current price, H = historical price
        --need to check not correct for history lvl = 1
        if (fp_future_prices = 'Y' or gv_hist_lvl > 0) then
          begin
            --for plpc records with a future price set C for the active price with the most recent start date
            update dwh_price_history dx
            set    dx.price_chf = 'C', dx.insert_time_stamp = sysdate
            where  exists (select 1
                    from   (select row_number() over(partition by t.productlistpercustomer_id, t.price_type order by t.productlistpercustomer_id, t.price_type, t.price_start_date desc) row_number,
                                    t.productlistpercustomer_id, t.price_type,
                                    t.price_start_date, t.price_level
                             from   dwh_price_history t
                             where  t.price_start_date <= trunc(sysdate)) x
                    where  x.row_number = 1
                    and    x.productlistpercustomer_id = dx.productlistpercustomer_id
                    and    x.price_type = dx.price_type
                    and    x.price_level = dx.price_level
                    and    x.productlistpercustomer_id in
                           (select xz.productlistpercustomer_id
                             from   dwh_price_history xz
                             where  xz.price_start_date > trunc(sysdate)
                             group  by xz.productlistpercustomer_id));
            commit;
            --prices with a start date in the future
            run_query('update /*+enable_parallel_dml parallel(' || gv_parallel_degree ||
                      ')*/ dwh_price_history dx
          set    dx.price_chf = ''F'', dx.insert_time_stamp = sysdate
          where  dx.price_start_date > trunc(sysdate)');
          end;
        end if;
        run_query('
      update /*+enable_parallel_dml parallel(' || gv_parallel_degree ||
                  ')*/ dwh_price_history dx
      set    dx.price_chf = case
                              when dx.price_level = 1 then
                               ''C''
                              else
                               ''H''
                            end, dx.insert_time_stamp = sysdate
      where  dx.price_chf is null');
      end set_price_chf;

    begin
      --for each pricetype
      for x in (select * from dwh_price_history_settings t order by t.price_type) loop
        begin
          gv_parallel_degree    := x.parallel_degree;
          gv_numberofrows_total := gv_numberofrows_total + gv_numberofrows;
          gv_numberofrows       := 0;
          gv_message            := 'Load price_details for price_type: ' || x.price_type_desc ||
                                   ' level: 1';
          gv_hist_start_date_d  := to_date(gv_hist_start_date, 'yyyymmdd');
          --first level either future or current
          open gv_cursor for x.price_type_sql
            using gv_hist_start_date_d;
          loop
            fetch gv_cursor bulk collect
              into gv_data limit gv_commit_num;
            forall i in 1 .. gv_data.count
              insert into dwh_price_history t values gv_data (i);
            gv_numberofrows := gv_numberofrows + gv_data.count;
            commit;
            exit when gv_cursor%notfound;
          end loop;
          close gv_cursor;
          commit;
          gv_message := 'Load price_details for price_type: ' || x.price_type_desc ||
                        ' level: 1. Total number of rows processed: ' || gv_numberofrows;
          write_log(gv_message, 1);
          --chk_price_found
          chk_price_found;
          --price_type_split_sql
          run_query(x.price_type_split_sql);
          if gv_hist_lvl > 0 then
            begin
              insert_hist_prices(x.price_type_desc, x.price_type_hist_sql, x.price_type_split_sql);
            end;
          end if;
        end;
      end loop;
      --cleanup Price not relevant
      pricenotrelevant;
      --set_price_chf
      set_price_chf;
    end insert_prices;

    procedure finalize is
    begin
      write_log('Finished loading prices. Total number of rows processed: ' ||
                gv_numberofrows_total, 1);
    end finalize;
  begin
    --initialize
    initialize;
    --insert_prices
    insert_prices;
    --finalize
    finalize;
  exception
    when no_data_found then
      begin
        rollback;
        write_log('error No Data Found ' || gv_message, 3);
      end;
    when gv_user_exception then
      begin
        rollback;
        write_log(gv_message, 3);
      end;
    when others then
      begin
        rollback;
        write_log(sqlerrm || ' ' || gv_message, 3);
      end;
  end fill_dwh_price_history;

end pack_dwh_price_history;
/
create or replace PACKAGE PACK_EPC_Sgtin96 is

  function decode(sgtin96_epc VARCHAR2) return VARCHAR2;

  function encode(gtin14              VARCHAR2,
                  companyPrefixLength number,
                  serialNumberStr     VARCHAR2,
                  filter              number) return VARCHAR2;

end PACK_EPC_Sgtin96;
/
create or replace PACKAGE BODY PACK_EPC_Sgtin96 is
  SGTIN_HEADER_VALUE           varchar2(8) := '00110000';
  NO_OF_BITS_SGTIN96_FILTER    number := 3;
  NO_OF_BITS_SGTIN96_PARTITION number := 3;
  NO_OF_BITS_SGTIN96_SERIAL    number := 38;

  MAX_LENGTH_BITS number := 96;
  MAX_LENGTH_HEX  number := 24;

  type epcrec is record(
    partitionvalue  number,
    companyprefixbits     number,
    COMPANYPREFIXDIGITS      number,
    ITEMREFERENCEBITS number,
    ITEMREFERENCEDIGITS        number);

  type epcarray is table of epcrec index by binary_integer;

  epc epcarray;

  function zeroFill(inputNumber varchar2, maxLength number) return varchar2 is
  begin
    if length(inputNumber) > maxLength then
      return inputNumber;
    else
      return LPAD(inputNumber, maxLength, 0);
    end if;
  end zeroFill;

  function computeCheckDigit(thirteen varchar2) return varchar2 is
    termA number := 0;
    termB number := 0;
    chr   varchar(1);
  BEGIN
    for i in 1 .. length(thirteen) loop
      chr := SUBSTR(thirteen, i, 1);
      if MOD(i, 2) = 1 then
        termB := termB + to_number(chr);
      else
        termA := termA + to_number(chr);
      end if;
    end loop;
    return ABS(MOD(((-3 * termA) - termB), 10));
  end computeCheckDigit;

  function binaryToDecimal(binval in char) RETURN number IS
    i                 number;
    digits            number;
    result            number := 0;
    current_digit     char(1);
    current_digit_dec number;
  BEGIN
    digits := length(binval);
    for i in 1 .. digits loop
      current_digit     := SUBSTR(binval, i, 1);
      current_digit_dec := to_number(current_digit);
      result            := (result * 2) + current_digit_dec;
    end loop;
    return result;
  END binaryToDecimal;

  function decimalToBinary(N in number) RETURN varchar2 IS
    binval varchar2(1000);
    N2     number := N;
  BEGIN
    IF N = 0 THEN
      return 0;
    END IF;
    while (N2 > 0) loop
      binval := mod(N2, 2) || binval;
      N2     := trunc(N2 / 2);
    end loop;
    return binval;
  END decimalToBinary;

  function decode(sgtin96_epc VARCHAR2) return VARCHAR2 is
    binary                      varchar2(1000);
    header                      varchar2(8);
    filter_value                number;
    partition_value             number;
    company_prefix_len_bits     varchar2(500);
    company_prefix_len_digits   varchar2(500);
    long_company_prefix_value   number;
    company_prefix              varchar2(1000);
    ir_and_indicator_len_digits number;
    ir_and_indicator            number;
    ir_and_indicator_string     varchar2(1000);
    thirteen                    varchar2(1000);
    check_digit                 varchar2(1);
    gtin14                      varchar2(1000);
    serial_number               varchar2(500);
  begin
    if length(sgtin96_epc) <> MAX_LENGTH_HEX OR sgtin96_epc IS NULL THEN
      --return 'ERROR: EPC must be ' || MAX_LENGTH_HEX || ' characters long ' || length(sgtin96_epc);
      return sgtin96_epc;
    end if;
    if REGEXP_LIKE(sgtin96_epc, '[^A-Fa-f0-9]') THEN
       return sgtin96_epc; --'ERROR: EPC value must be HEX compatible'
    end if;
    binary := zeroFill(decimalToBinary(to_number(sgtin96_epc,
                                                 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')),
                       MAX_LENGTH_BITS);
    header := SUBSTR(binary, 0, 8);

    IF header not like SGTIN_HEADER_VALUE THEN
      --return 'ERROR: EPC header does not correlate to SGTIN-96. Value found: ' || header || ' ' || SGTIN_HEADER_VALUE;
      return sgtin96_epc;
    END IF;

    filter_value    := binaryToDecimal(SUBSTR(binary, 9, 3));
    partition_value := binaryToDecimal(SUBSTR(binary, 12, 3));

    IF partition_value > 6 THEN
      --return 'ERROR: Partition value cannot be greater than 6';
      return sgtin96_epc;
    END IF;

    /*select e.companyprefixbits, e.companyprefixdigits
      into company_prefix_len_bits, company_prefix_len_digits
      from epcsgtin96partition e
     where e.partitionvalue = partition_value;*/

    company_prefix_len_bits := epc(partition_value).companyprefixbits;
    company_prefix_len_digits := epc(partition_value).companyprefixdigits;

    long_company_prefix_value := binaryToDecimal(SUBSTR(binary,
                                                        15,
                                                        company_prefix_len_bits));
    IF long_company_prefix_value >= POWER(10, company_prefix_len_digits) THEN
      --return 'ERROR: Company Prefix exceeded specified length';
      return sgtin96_epc;
    END IF;

    company_prefix              := zeroFill(long_company_prefix_value,
                                            company_prefix_len_digits);
    ir_and_indicator_len_digits := 13 - company_prefix_len_digits;
    ir_and_indicator            := binaryToDecimal(SUBSTR(binary,
                                                          15 +
                                                          company_prefix_len_bits,
                                                          58 - 14 -
                                                          company_prefix_len_bits));

    IF ir_and_indicator >= POWER(10, ir_and_indicator_len_digits) THEN
      --return 'ERROR: Item Reference and Indicator exceeded specified length';
      return sgtin96_epc;
    END IF;
    ir_and_indicator_string := zeroFill(ir_and_indicator,
                                        ir_and_indicator_len_digits);
    thirteen                := SUBSTR(ir_and_indicator_string, 0, 1) ||
                               company_prefix ||
                               SUBSTR(ir_and_indicator_string, 2);
    check_digit             := computeCheckDigit(thirteen);
    gtin14                  := thirteen || check_digit;
    serial_number           := binaryToDecimal(SUBSTR(binary,59));
    return company_prefix || '.' || ir_and_indicator_string || '.' ||  serial_number;
  end decode;

  function is_number(p_string IN VARCHAR2) RETURN INT IS
    v_new_num NUMBER;
  BEGIN
    v_new_num := TO_NUMBER(p_string);
    RETURN 1;
  EXCEPTION
    WHEN VALUE_ERROR THEN
      RETURN 0;
  END is_number;

  function validateSerialNumber(serialNumberStr VARCHAR2) return number is
  begin
    IF (NVL(serialNumberStr, '') like '') THEN
      return 'ERROR: Serial Number cannot be encoded in the SGTIN-96 encoding. Reason: Serial number is empty';
    END IF;
    IF LENGTH(serialNumberStr) > 1 AND
       SUBSTR(serialNumberStr, 0, 1) like '0' THEN
      return 'ERROR: Serial Number cannot be encoded in the SGTIN-96 encoding \n' || '(because leading zeros are not permitted except in the case where the Serial Number consists of a single zero digit)';
    END IF;
    IF is_number(serialNumberStr) = 0 THEN
      return 'ERROR: Serial Number cannot be encoded in the SGTIN-96 encoding. Illegal characters found.';
    END IF;
    IF serialNumberStr > POWER(2, 38) - 1 THEN
      return 'ERROR: Serial Number cannot be encoded in the SGTIN-96 encoding. Number too big.';
    END IF;
    return serialNumberStr;
  end validateSerialNumber;

  function longToBinaryWithFill(nr number, bits number) return varchar2 is
  begin
    return zeroFill(decimalToBinary(nr), bits);
  end longToBinaryWithFill;

  function validateGtin14(gtin14 varchar2) return varchar2 is
  begin
    IF length(NVL(gtin14, '')) <> 14 OR gtin14 is NULL THEN
      return 'ERROR: GTIN must be 14 digits long';
    END IF;
    IF is_number(gtin14) = 0 THEN
      return 'ERROR: gtin14 cannot be encoded in the SGTIN-96 encoding. Illegal characters found.';
    END IF;

    IF to_number(substr(gtin14, 14, 1)) <>
       computeCheckDigit(substr(gtin14, 1, 13)) THEN
      return 'ERROR: gtin14 cannot be encoded in the SGTIN-96 encoding. Illegal check digit found.';
    END IF;
    return '';
  end validateGtin14;

  function encode(gtin14              VARCHAR2,
                  companyPrefixLength number,
                  serialNumberStr     VARCHAR2,
                  filter              number) return VARCHAR2 is
    errorOutput           varchar2(1000);
    partition_value       number;
    company_prefix_bits   number;
    ir_and_indicator_bits number;
    C_company_prefix      number;
    I_ir_and_indicator    number;
    bin_filter_value      varchar2(500);
    bin_partition_value   varchar2(500);
    bin_company_prefix    varchar2(500);
    bin_item_reference    varchar2(500);
    bin_serial_number     varchar2(500);
    bin_epc               varchar2(500);
  begin
    errorOutput := validateGtin14(gtin14);
    IF errorOutput like 'ERROR%' THEN
      return errorOutput;
    END IF;
    IF companyPrefixLength < 6 OR companyPrefixLength > 12 THEN
      return 'ERROR: Company prefix length must be <= 12 and >= 6';
    END IF;
    errorOutput := validateSerialNumber(serialNumberStr);
    IF errorOutput like 'ERROR%' THEN
      return errorOutput;
    END IF;
    IF filter < 0 OR filter > 7 THEN
      return 'ERROR: Filter must be <= 7 and >= 0';
    END IF;

    /*select e.partitionvalue, e.companyprefixbits, e.itemreferencebits
      into partition_value, company_prefix_bits, ir_and_indicator_bits
      from epcsgtin96partition e
     where e.companyprefixdigits = companyPrefixLength;*/

    for i in epc.first .. epc.last loop
        if (epc(i).companyprefixdigits = companyPrefixLength) then
          partition_value := epc(i).partitionvalue;
          company_prefix_bits := epc(i).companyprefixbits;
          ir_and_indicator_bits := epc(i).itemreferencebits;
        end if;
    end loop;

    C_company_prefix    := to_number(SUBSTR(gtin14, 2, companyPrefixLength));
    I_ir_and_indicator  := to_number(SUBSTR(gtin14, 1, 1) ||
                                     SUBSTR(gtin14,
                                            companyPrefixLength + 2,
                                            14 - companyPrefixLength - 2));
    bin_filter_value    := longToBinaryWithFill(filter,
                                                NO_OF_BITS_SGTIN96_FILTER);
    bin_partition_value := longToBinaryWithFill(partition_value,
                                                NO_OF_BITS_SGTIN96_PARTITION);
    bin_company_prefix  := longToBinaryWithFill(C_company_prefix,
                                                company_prefix_bits);
    bin_item_reference  := longToBinaryWithFill(I_ir_and_indicator,
                                                ir_and_indicator_bits);
    bin_serial_number   := longToBinaryWithFill(serialNumberStr,
                                                NO_OF_BITS_SGTIN96_SERIAL);
    bin_epc             := SGTIN_HEADER_VALUE || bin_filter_value ||
                           bin_partition_value || bin_company_prefix ||
                           bin_item_reference || bin_serial_number;

    return trim(zeroFill(to_char(binaryToDecimal(bin_epc),
                                 'XXXXXXXXXXXXXXXXXXXXXXXX'),
                         MAX_LENGTH_HEX));
  end encode;

begin
---initialize standard values for EPCSGTIN96PARTITION
      epc(0).partitionvalue := 0;
      epc(0).companyprefixbits := 40;
      epc(0).COMPANYPREFIXDIGITS := 12;
      epc(0).ITEMREFERENCEBITS := 4;
      epc(0).ITEMREFERENCEDIGITS := 1;

      epc(1).partitionvalue := 1;
      epc(1).companyprefixbits := 37;
      epc(1).COMPANYPREFIXDIGITS := 11;
      epc(1).ITEMREFERENCEBITS := 7;
      epc(1).ITEMREFERENCEDIGITS := 2;

      epc(2).partitionvalue := 2;
      epc(2).companyprefixbits := 34;
      epc(2).COMPANYPREFIXDIGITS := 10;
      epc(2).ITEMREFERENCEBITS := 10;
      epc(2).ITEMREFERENCEDIGITS := 3;

      epc(3).partitionvalue := 3;
      epc(3).companyprefixbits := 30;
      epc(3).COMPANYPREFIXDIGITS := 9;
      epc(3).ITEMREFERENCEBITS := 14;
      epc(3).ITEMREFERENCEDIGITS := 4;

      epc(4).partitionvalue := 4;
      epc(4).companyprefixbits := 27;
      epc(4).COMPANYPREFIXDIGITS := 8;
      epc(4).ITEMREFERENCEBITS := 17;
      epc(4).ITEMREFERENCEDIGITS := 5;

      epc(5).partitionvalue := 5;
      epc(5).companyprefixbits := 24;
      epc(5).COMPANYPREFIXDIGITS := 7;
      epc(5).ITEMREFERENCEBITS := 20;
      epc(5).ITEMREFERENCEDIGITS := 6;

      epc(6).partitionvalue := 6;
      epc(6).companyprefixbits := 20;
      epc(6).COMPANYPREFIXDIGITS := 6;
      epc(6).ITEMREFERENCEBITS := 24;
      epc(6).ITEMREFERENCEDIGITS := 7;

end PACK_EPC_Sgtin96;
/
create or replace package pack_exportgrowth is
/*
  Author  : HVH
  Created : January 2010
  Version : 1.1
  Changes : 21/02/2010 HVH: For transaction 8 and 10 quit wearer/wearer inventory. Take old changes / wk from SQ.
            22/06/2010 HVH: Solve issue of not generating price change transactions for wearerinventory price changes
			18/12/2020 LAC: Solved issue of inactive routestops being taken into account when determining the route number
            04/03/2021 LAC: Adjustment on retrieving the route_id (Pack_exportgrowth inactive routestops are taken into account when determining the route#)
			05/03/2021 HVH: process for revenue growth on size level
  Purpose : Generate revenue growth data for use in ABS Business Intelligence

  The revenue growth is defined as the change to the structural amount of weekly rental revenue.

  Typically this procedure is run by the ABSSolute process scheduler and is scheduled once per week in the week.
  So that it generates data for the past week.

  The revenue growth is stored per date, customer, product, wearer, growth reason in the GROWTHISTORY table.
  The procedure distinguishes the following growth reasons (transaction#'s):
   1	New Customer
   2	Quit Customer
   3	New Customer Product, plpc line for non garments
   4	Quit Customer Product, plpc line for non garments
   5	Increased Customer Product, for non garments
   6	Decreased Customer Product, for non garments
   7	New Wearer
   8	Quit Wearer
   9	New Wearer Product, new wearer inventory line
  10	Quit Wearer Product, quit wearer inventory line
  11	Increased Wearer Inventory
  12	Decreased Wearer Inventory
  13	Price Increase
  14	Price Decrease

  All changes (except price changes) are recorded as growth reason 1 'new customer' when the change (transactiondate)
  is within X days after the customer start date. X is defined by the system setting NEWCUSTOMERSTARTUPDAYS.
  All changes (except price changes) are recorded as growth reason 2 'quit customer' when the change (transactiondate)
  is after the customer end date or within 7 days before customer end date. Obviously only when the customer end date
  is known and entered in advance.

  The following billingmethods are supported:
  A) For non garments
  BM 1 flat rated rent
        This is based on the fixed rent qty in consumption point logistics.
        In order to be able to record changes, it is important that the systemsetting DELIVERYSTDHISTORY is set to 2 (automatic)
        In case the delivery frequency is not weekly, then the amount is divided by the frequency to achieve a avg weekly amount.
        Example: if qty = 1 and price is 3 and frequency is every other week (so once every 2 weeks) then amount is
        1 * 3 / 2 = 1.50.
        This is depending also on the invoice frequency, for periodical invoicing this is not applicable.
  BM 2 Rent based on minimum
        The amount is calculated by determing the minimum qty as % of circ, or based on the fixed minimum qty if defined.
        It is assumed that this minimum is per week.
  BM 3 Inventory based rent
        Only based on circulating inventory, not on real qty in circ.

  B) For garments
  BM 1 flat rated rent
        This is rent based on changes per week, or per set (depending on system setting SETPRICEPERCHANGE)
        The previous qty is taken from Status Quo sets in circulation, for the following growth reasons:
        11 and 12.  For other growth reasons the changes/week are taken directly from the wearerinventory.
        System setting SETPRICEPERCHANGE is taken into account for the quantity.
  BM 3 Inventory based rent
        For this billingmethod both real qty in circ as max qty in circ are supported.
        The previous qty is taken from Status Quo items in circulation, for the following growth reasons:
        8,10, 11,12, 13, 14

  Frequency
  The charge frequency plays a role the calculation of the weekly amount.
  When the rent is charged multiple times a week, the amount has to be multiplied.
  When the rent is charged once every X weeks, the amount has to be divided by X.
  In the latter case the X is stored as 1 / X.
  The frequency column is defined as follows:
  >1 charge is multiple times per week. For example: rent based on minimum every visit.
   1 weekly
  <1 charge is not weekly. Example: 0.5 means once every two weeks, 0.25 once every 4 weeks.
  If the visit frequency of the customer is not weekly, this is taken into acount for direct invoicing,
  by dividing the amount by the visit frequency.

  Status Quo processing dependency
  The following status quo data is required:
  - sets in circulation  (for BM 1 garments) on wearer level. System setting SQSETONWEARERLEVEL should be Y
  - items in circulation (for BM 3 garments) on wearer level  System setting SQONWEARERLEVEL should be Y
  IMPORTANT: Both status quo processes need to be run at wearer level.

  Price determination:
  Prices are determined by using the pack_price.
  This means that both customer specific and general prices are included.
  In addition to that also prices on wearer inventory level are supported when systemsetting WEARERINVENTPRICE=Y.

  Price changes are recorded against the qty valid at the start of the selected period
  Quantity changes are recorded against the price valid at the end of the selected period
  In this way if for the same customer product a price change and a qty change happen in the same period,
  their sum will match the total amount change caused by both.
  Price changes for which no new or old price could be found are excluded, as they probably cause wrong results.

  Not supported are:
  - rent specification wearer total pricing
  - rent specification wearer function pricing
  - discounts
  - free of charge quantities defined in productlist per customer
  - any other invoiceline type then rent.   So e.g. systematic replacement charges, or special charges are not supported.
  - billingmethod 5 lease
  - rent based on on-site inventory
  - change of minimum-% for billingmethod 2

*/
  procedure exportgrowth(todate date, plantid number, FpSystemUser_ID in number, Fpabslogprocessjobid in abslogprocessjob.abslogprocessjob_id%type);

end pack_exportgrowth;
/
create or replace package body pack_exportgrowth is
  --internal declarations
  gv_new_customer_days       number;
  gv_quit_customer_lead_days number := 7;  -- # days before customer date inactive transactions are assumed because of quit customer
  gv_wearer_invent_price     varchar2(1);
  gv_set_price_per_change    varchar2(1);
  gv_size_star_id            number;
  gv_system_user_id          number;

  function determine_visits_per_week(fp_productlistpercustomer_id number, fp_billingdaysonly varchar2) return number is
   lv_visits number;
  begin
    begin
     select count(1)
       into lv_visits
       from productdeliveryday pd
     where pd.productlistpercustomer_id = fp_productlistpercustomer_id
       and (pd.deliverytype = 'B' or fp_billingdaysonly = 'N')
       and pd.deliverytype <> 'P';
    if lv_visits = 0
     then return(1);
     else return(lv_visits);
    end if;
    exception
      when no_data_found
       then return(1);
    end;
  end determine_visits_per_week;

  function determine_del_scheme_freq(fp_deliveryscheme_id number) return number is
   lv_freq number;
  begin
    begin
     select d.frequency
       into lv_freq
       from deliveryscheme d
     where d.deliveryscheme_id = fp_deliveryscheme_id;
    return(lv_freq);
    if lv_freq = 0
     then return(1);
     else return(lv_freq);
    end if;
    exception
      when no_data_found
       then return(1);
    end;
  end determine_del_scheme_freq;

  function determine_frequency(fp_customer_id number, fp_freq number,
                               fp_billingmethod number, fp_minimumfrequency number,
                               fp_productlistpercustomer_id number, fp_deedeliveryscheme_id number) return number is
   lv_freq number;
   lv_cust_freq number;
  begin
    lv_freq := 0;
    if fp_billingmethod=1
      then lv_freq := fp_freq; -- already determined
    end if;
    if fp_billingmethod=2 then
      if fp_minimumfrequency = 1  -- weekly
        then lv_freq := 1;
      end if;
      if fp_minimumfrequency = 2  -- every visit when billed
        then lv_freq := determine_visits_per_week(fp_productlistpercustomer_id,'Y');
      end if;
      if fp_minimumfrequency = 3  -- monthly
        then lv_freq := 1 / 4.33;
      end if;
      if fp_minimumfrequency = 4  -- every delivery
        then lv_freq := determine_visits_per_week(fp_productlistpercustomer_id,'N');
      end if;
      if fp_minimumfrequency = 5  -- delivery scheme based
        then
          if fp_deedeliveryscheme_id is null
            then lv_freq := determine_visits_per_week(fp_productlistpercustomer_id,'N');
            else lv_freq := 1 / determine_del_scheme_freq(fp_deedeliveryscheme_id);
          end if;
      end if;
    end if;
    begin
     select min(d.frequency)
       into lv_cust_freq
       from customerdeliveryscheme cd, deliveryscheme d
     where d.deliveryscheme_id=cd.deliveryscheme_id
       and cd.customer_id=fp_customer_id;
    if lv_cust_freq = 0
      then lv_cust_freq := 1;
      else lv_cust_freq := 1 / lv_cust_freq;
    end if;
    exception
      when no_data_found
       then lv_cust_freq:=1;
    end;
    if lv_freq > lv_cust_freq and lv_freq <= 1
      then return(lv_cust_freq);
      else return(lv_freq);
    end if;
  end determine_frequency;

  function determine_garm_frequency(fp_customer_id number) return number is
   lv_freq number;
  begin
    begin
     select min(d.frequency)
       into lv_freq
       from customerdeliveryscheme cd, deliveryscheme d
     where d.deliveryscheme_id=cd.deliveryscheme_id
       and cd.customer_id=fp_customer_id;
    if lv_freq = 0
      then return(1);
      else return(1 / lv_freq);
    end if;
    exception
      when no_data_found
       then return(1);
    end;
  end determine_garm_frequency;

  function determine_min_perc(fp_billingmethod number, fp_minimum_qty number, fp_minimum_turnaround number) return number is
  begin
    if fp_billingmethod=2 and fp_minimum_qty=0
      then return(fp_minimum_turnaround);
      else return(null);
    end if;
  end determine_min_perc;

  function determine_quantity(fp_quantity number, fp_billingmethod number, fp_minimum_qty number) return number is
  begin
    if fp_billingmethod=2 and fp_minimum_qty<>0
      then return(fp_minimum_qty);
      else return(fp_quantity);
    end if;
  end determine_quantity;

  function determine_garm_quantity(fp_changesperweek number, fp_circinventory number, fp_maxinventory number,
                                   fp_billingmethod number, fp_billingtype number) return number is
  begin
    case fp_billingmethod
      when 1 then if gv_set_price_per_change='Y'
                     then return(fp_changesperweek);
                     else return (1);
                  end if;
      when 3 then if fp_billingtype = 2 -- max
                     then return(fp_maxinventory);
                     else return(fp_circinventory);
                  end if;
      else return(0);
    end case;
  end determine_garm_quantity;

  function determine_transaction(fp_transaction number, fp_transactiondate date,
                                 fp_customer_date_active date, fp_customer_date_inactive date) return number is
    lv_transactionno number;
  begin
    lv_transactionno := fp_transaction;
    if --fp_transaction mod 2 <> 0 and -- odd transactions are new
       fp_transactiondate <= fp_customer_date_active + gv_new_customer_days
     then lv_transactionno := 1; -- new customer
    end if;
    if --fp_transaction mod 2 = 0 and -- even transactions are quits
       fp_transactiondate > fp_customer_date_inactive - gv_quit_customer_lead_days  -- starting 1 wk before cust end considered lost customer
     then lv_transactionno := 2; -- lost customer
    end if;
    return(lv_transactionno);
  end determine_transaction;

  function determine_price_date(fp_transaction number, fp_fromdate date, fp_todate date) return date is
  begin
    if fp_transaction mod 2 <> 0 -- odd transactions are new so take price a todate, even trans take price at fromdate
          then return(fp_todate);
          else return(fp_fromdate);
        end if;
  end determine_price_date;

  function determine_garment_price(fp_customer_id number, fp_product_id number, fp_sizedefinition_id number,
                                   fp_finishingmethod_id number, fp_price_date date, fp_number_of_changes number, fp_wearerinventory_id number) return number is
   lv_price number;
  begin
    if gv_wearer_invent_price='Y'
     then
        begin
          select wip.price
            into lv_price
            from wearerinvprice wip
           where wip.wearerinventory_id = fp_wearerinventory_id
             and wip.startdate =
                 (select max(wip.startdate)
                    from wearerinvprice wip
                   where wip.wearerinventory_id = fp_wearerinventory_id
                     and wip.startdate <= fp_price_date);
        exception
          when no_data_found then
            lv_price := pack_price.Rent_Price(fp_customer_id,fp_product_id,fp_sizedefinition_id,fp_finishingmethod_id,fp_price_date,fp_number_of_changes);
        end;
      else  -- gv_wearer_invent_price='N'
       lv_price := pack_price.Rent_Price(fp_customer_id,fp_product_id,fp_sizedefinition_id,fp_finishingmethod_id,fp_price_date,fp_number_of_changes);
   end if;
   return(lv_price);
  end determine_garment_price;

  function wearerinvprice_defined(fp_wearerinventory_id number, fp_price_date date) return boolean is
   lv_price number;
  begin
    begin
      select wip.price
        into lv_price
        from wearerinvprice wip
       where wip.wearerinventory_id = fp_wearerinventory_id
         and wip.startdate =
             (select max(wip.startdate)
                from wearerinvprice wip
               where wip.wearerinventory_id = fp_wearerinventory_id
                 and wip.startdate <= fp_price_date);
      return true;
    exception
      when no_data_found then
        return false;
    end;
  end wearerinvprice_defined;

  procedure determine_billingmethod(fp_customer_id in number,
                                    fp_product_id in number,
                                    fp_sizedefinition_id in number,
                                    fp_finishingmethod_id in number,
                                    fp_active_date in date,
                                    fp_billingmethod out number,
                                    fp_billingtype out number) is
  begin
   fp_billingmethod := null;
   fp_billingtype := 0;
   begin
     select pl.billingmethod, pl.inventorybillingtype
       into fp_billingmethod, fp_billingtype
       from productlistpercustomer pl
      where pl.customer_id= fp_customer_id and
            pl.product_id= fp_product_id and
            pl.sizedefinition_id= fp_sizedefinition_id and
            pl.finishingmethod_id= fp_finishingmethod_id and
            fp_active_date between pl.dateactive and pl.dateinactive;
   exception
     when no_data_found then
       begin
         select pl.billingmethod, pl.inventorybillingtype
           into fp_billingmethod, fp_billingtype
           from productlistpercustomer pl
          where pl.customer_id= fp_customer_id and
                pl.product_id= fp_product_id and
                pl.sizedefinition_id= gv_size_star_id and
                pl.finishingmethod_id= fp_finishingmethod_id and
                fp_active_date between pl.dateactive and pl.dateinactive;
       exception
         when no_data_found then
           fp_billingmethod := 1;
       end;
   end;
  end determine_billingmethod;

  function determine_amount(fp_quantity number,
                            fp_price number,
                            fp_min_perc number,
                            fp_frequency number,
                            fp_invoice_freq number) return number is
    lv_amount number(15,2);
  begin
    if fp_price is not null
     then
      if fp_min_perc is null
       then lv_amount := fp_quantity * fp_price;
       else lv_amount := round(fp_quantity*fp_min_perc/100) * fp_price;
      end if;
      if fp_invoice_freq=0 -- direct invoices only bill rent in week of delivery, not weekly so multiply by del.frequency.
        then return(lv_amount * fp_frequency);
        else return(lv_amount);
      end if;
     else
      return(0);
    end if;
  end determine_amount;

  procedure write_growth_history(fp_transactiondate date,
                                 fp_transactionno number,
                                 fp_businessunit_id  number,
                                 fp_route_id  number,
                                 fp_customer_id  number,
                                 fp_product_id  number,
                                 fp_weareremp_id  number,
                                 fp_currency_id  number,
                                 fp_quantity  number,
                                 fp_price  number,
                                 fp_amount  number,
                                 fp_billingmethod  number,
                                 fp_old_price  number,
                                 fp_new_price  number,
                                 fp_frequency  number,
                                 fp_min_perc number,
                                 fp_size_id number) is

  begin
    insert into growthhistory
          (growthhistory_id,
           transactiondate,
           transaction_id,
           businessunit_id,
           route_id,
           customer_link_id,
           product_link_id,
           weareremp_link_id,
           currency_id,
           quantity,
           price,
           amount,
           systemuser_id,
           timestamp,
           billingmethod,
           oldprice,
           newprice,
           frequency,
           minimumpercentage,
           sizedefinition_link_id)
        values
          (seq_growthhistory.nextval,
           fp_transactiondate,
           fp_transactionno,
           fp_businessunit_id,
           fp_route_id,
           fp_customer_id,
           fp_product_id,
           fp_weareremp_id,
           fp_currency_id,
           nvl(fp_quantity, 0),
           fp_price,
           nvl(fp_amount, 0),
           gv_system_user_id,
           sysdate,
           fp_billingmethod,
           fp_old_price,
           fp_new_price,
           fp_frequency,
           fp_min_perc,
           fp_size_id);
  end write_growth_history;

  procedure newlost_customerproduct_BM_1(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
-- NON GARMENTS ONLY Billingmethod 1
    --select the CPL lines from PLPC lines that qualify for export
    for x in (select 3 transactionno, -- new customer product
                     l.dateactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and l.dateactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     case when sdl.deliveryscheme_id is null
                      then 1
                      else (select ds.frequency from deliveryscheme ds where ds.deliveryscheme_id=sdl.deliveryscheme_id)
                     end frequency,
                     case when sdl.qtyfreeofcharge <> 0 and sdl.freeqtyfrequency = 0
                      then sdl.fixedrentquantity - sdl.qtyfreeofcharge
                      else sdl.fixedrentquantity
                     end net_quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.billingmethod,
                     sdl.dateactive,
                     sdl.productlistperdistribpoint_id
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu,
                     distributionpoint      dp,
                     department             d,
                     productlistperdistribpoint plpd,
                     standarddeliveryline   sdl
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod=1   -- only fixed qty
--                 and c.dateactive not between fromdate and todate
                 and c.dateinactive not between fromdate and todate -- don't select new for quit customers
                 and l.dateactive between fromdate and todate
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
                 and plpd.distributionpoint_id=dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id=l.customer_id
                 and plpd.product_id=l.product_id
                 and plpd.sizedefinition_id=l.sizedefinition_id
                 and plpd.finishingmethod_id=l.finishingmethod_id
                 and sdl.productlistperdistribpoint_id=plpd.productlistperdistribpoint_id
                 and sdl.dateactive <= todate
                 and sdl.dateinactive >= todate
              union
              select 4 transactionno, -- quit customer product
                     l.dateinactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and l.dateinactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     case when sdl.deliveryscheme_id is null
                      then 1
                      else (select ds.frequency from deliveryscheme ds where ds.deliveryscheme_id=sdl.deliveryscheme_id)
                     end frequency,
                     case when sdl.qtyfreeofcharge <> 0 and sdl.freeqtyfrequency = 0
                      then sdl.fixedrentquantity - sdl.qtyfreeofcharge
                      else sdl.fixedrentquantity
                     end net_quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.billingmethod,
                     sdl.dateactive,
                     sdl.productlistperdistribpoint_id
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu,
                     distributionpoint      dp,
                     department             d,
                     productlistperdistribpoint plpd,
                     standarddeliveryline   sdl
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod=1   -- only fixed qty
                 and c.dateactive not between fromdate and todate  -- don't select quits for new customers
--                 and c.dateinactive not between fromdate and todate
                 and l.dateinactive between fromdate and todate
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
                 and plpd.distributionpoint_id=dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id=l.customer_id
                 and plpd.product_id=l.product_id
                 and plpd.sizedefinition_id=l.sizedefinition_id
                 and plpd.finishingmethod_id=l.finishingmethod_id
                 and sdl.productlistperdistribpoint_id=plpd.productlistperdistribpoint_id
                 and sdl.dateactive <= fromdate
                 and sdl.dateinactive >= fromdate
                 )
               loop
      begin
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        if x.transactionno = 3 then
          lv_quantity := x.net_quantity;
        end if;
        if x.transactionno = 4 then -- lost customer product
          lv_quantity := -x.net_quantity;
        end if;
        lv_frequency := 1 / x.frequency;
        lv_min_perc  := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_quantity  := determine_quantity(lv_quantity, x.billingmethod, 0);
        lv_pricedate := determine_price_date(x.transactionno, fromdate, todate);
        lv_price     := pack_price.Rent_Price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,x.frequency);
        lv_amount    := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        --insert new/lost customer product record NON GARMENTS ONLY BM 1
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop;
  end newlost_customerproduct_BM_1;

  procedure newlost_customerproduct_BM_23(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
-- NON GARMENTS ONLY Billingmethod 2 and 3
    --select the PLPC lines that qualify for export
    for x in (select 3 transactionno, -- new customer product
                     l.dateactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and l.dateactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     nvl((select sum(q.quantity)
                           from rentalqtyadjustment        q,
                                productlistperdistribpoint pd,
                                distributionpoint          t,
                                department                 d
                          where q.productlistperdistribpoint_id =
                                pd.productlistperdistribpoint_id
                            and pd.product_id = l.product_id
                            and q.adjustmentdate <= todate -- hvh: added so that running afterwards will stil give the correct qty
                            and pd.distributionpoint_id =
                                t.distributionpoint_id
                            and t.department_id = d.department_id
                            and d.customer_id = l.customer_id),
                         0) quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.minimumturnaround,
                     l.minimumquantity,
                     l.minimumfrequency,
                     l.deedeliveryscheme_id,
                     l.productlistpercustomer_id,
                     l.billingmethod
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod in (2,3)   -- only rent based on minimum and based on circ
--                 and c.dateactive not between fromdate and todate
                 and c.dateinactive not between fromdate and todate -- don't select new for quit customers
                 and l.dateactive between fromdate and todate
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
              union
              select 4 transactionno,  -- lost customer product
                     l.dateinactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and l.dateinactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     nvl((select sum(q.quantity)
                           from rentalqtyadjustment        q,
                                productlistperdistribpoint pd,
                                distributionpoint          t,
                                department                 d
                          where q.productlistperdistribpoint_id =
                                pd.productlistperdistribpoint_id
                            and pd.product_id = l.product_id
                            and q.adjustmentdate < fromdate -- <todate -- hvh: added so that quit products have the qty before quitting
                            and pd.distributionpoint_id =
                                t.distributionpoint_id
                            and t.department_id = d.department_id
                            and d.customer_id = l.customer_id),
                         0) quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.minimumturnaround,
                     l.minimumquantity,
                     l.minimumfrequency,
                     l.deedeliveryscheme_id,
                     l.productlistpercustomer_id,
                     l.billingmethod
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod in (2,3)   -- only rent based on minimum and based on circ
                 and c.dateactive not between fromdate and todate  -- don't select quits for new customers
--                 and c.dateinactive not between fromdate and todate
                 and l.dateinactive between fromdate and todate
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid)
               loop
      begin
        if x.transactionno = 3
          then lv_quantity := x.quantity;
          else lv_quantity := -x.quantity;
        end if;
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_frequency := determine_frequency(x.customer_id, null, x.billingmethod, x.minimumfrequency, x.productlistpercustomer_id, x.deedeliveryscheme_id);
        lv_min_perc  := determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_quantity  := determine_quantity(lv_quantity, x.billingmethod, x.minimumquantity);
        lv_pricedate := determine_price_date(x.transactionno, fromdate, todate);
        lv_price     := pack_price.Rent_Price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,0);
        lv_amount    := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        --insert new/lost customer product record NON GARMENTS ONLY
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop;
  end newlost_customerproduct_BM_23;
--
  procedure changed_customerproduct_BM_1(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
   -- NON GARMENTS ONLY Billingmethod 1
    --select the CPL lines from PLPC lines that qualify for export
    for x in (
              -- new but not found a preceding quit one
              select /*+INDEX(sdl XIE1STANDARDDELIVERYLINE)*/  -- use index on dateactive
                     5 transactionno, -- changed customer product increase
                     sdl.dateactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and sdl.dateactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     case when sdl.deliveryscheme_id is null
                      then 1
                      else (select ds.frequency from deliveryscheme ds where ds.deliveryscheme_id=sdl.deliveryscheme_id)
                     end frequency,
                     case when sdl.qtyfreeofcharge <> 0 and sdl.freeqtyfrequency = 0
                      then sdl.fixedrentquantity - sdl.qtyfreeofcharge
                      else sdl.fixedrentquantity
                     end net_quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.billingmethod,
                     sdl.productlistperdistribpoint_id
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu,
                     distributionpoint      dp,
                     department             d,
                     productlistperdistribpoint plpd,
                     standarddeliveryline   sdl
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod=1   -- only fixed qty
                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                 and l.dateinactive > todate
                 and c.defaultbusinessunit_id = bu.businessunit_id
                 and bu.plant_id = plantid
                 and plpd.distributionpoint_id=dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id=l.customer_id
                 and plpd.product_id=l.product_id
                 and plpd.sizedefinition_id=l.sizedefinition_id
                 and plpd.finishingmethod_id=l.finishingmethod_id
                 and sdl.productlistperdistribpoint_id=plpd.productlistperdistribpoint_id
                 and sdl.dateactive between fromdate and todate
                 and not exists (select 1
                                  from standarddeliveryline sdl2
                                 where sdl2.standarddelivery_id = sdl.standarddelivery_id
                                   and sdl2.productlistperdistribpoint_id = sdl.productlistperdistribpoint_id
                                   and sdl2.standarddeliveryline_id <> sdl.standarddeliveryline_id
                                   and nvl(sdl2.deliveryscheme_id,-1) = nvl(sdl.deliveryscheme_id,-1)
                                   and nvl(sdl2.season_id,-1) = nvl(sdl.season_id,-1)
                                   and sdl2.dateinactive = sdl.dateactive - 1)
              union all
              -- quit but not found a new one
              select /*+INDEX(sdl_new XIE2STANDARDDELIVERYLINE)*/   -- use index on dateinactive
                     6 transactionno, -- changed customer product decrease
                     sdl.dateinactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and sdl.dateinactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     case when sdl.deliveryscheme_id is null
                      then 1
                      else (select ds.frequency from deliveryscheme ds where ds.deliveryscheme_id=sdl.deliveryscheme_id)
                     end frequency,
                     case when sdl.qtyfreeofcharge <> 0 and sdl.freeqtyfrequency = 0
                      then (sdl.fixedrentquantity - sdl.qtyfreeofcharge) * -1
                      else sdl.fixedrentquantity * -1
                     end net_quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.billingmethod,
                     sdl.productlistperdistribpoint_id
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu,
                     distributionpoint      dp,
                     department             d,
                     productlistperdistribpoint plpd,
                     standarddeliveryline   sdl
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod=1   -- only fixed qty
                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                 and l.dateinactive > todate
                 and c.defaultbusinessunit_id = bu.businessunit_id
                 and bu.plant_id = plantid
                 and plpd.distributionpoint_id=dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id=l.customer_id
                 and plpd.product_id=l.product_id
                 and plpd.sizedefinition_id=l.sizedefinition_id
                 and plpd.finishingmethod_id=l.finishingmethod_id
                 and sdl.productlistperdistribpoint_id=plpd.productlistperdistribpoint_id
                 and sdl.dateinactive between fromdate and todate
                 and not exists (select 1
                                  from standarddeliveryline sdl2
                                 where sdl2.standarddelivery_id = sdl.standarddelivery_id
                                   and sdl2.productlistperdistribpoint_id = sdl.productlistperdistribpoint_id
                                   and sdl2.standarddeliveryline_id <> sdl.standarddeliveryline_id
                                   and nvl(sdl2.deliveryscheme_id,-1) = nvl(sdl.deliveryscheme_id,-1)
                                   and nvl(sdl2.season_id,-1) = nvl(sdl.season_id,-1)
                                   and sdl2.dateactive = sdl.dateinactive + 1)
              union all
              -- changed ones, where the new records is right after the old record
              -- (e.g. by systemsetting DELIVERYSTDHISTORY=2 automatic history)
              select /*+INDEX(sdl_new XIE1STANDARDDELIVERYLINE)*/ -- use index on dateactive
                     5 transactionno, -- will be updated later to 6 when quantity < 0
                     sdl_new.dateactive transactiondate,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and sdl_new.dateactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     case when sdl_new.deliveryscheme_id is null
                      then 1
                      else (select ds.frequency from deliveryscheme ds where ds.deliveryscheme_id=sdl_new.deliveryscheme_id)
                     end frequency,
                     case when sdl_new.qtyfreeofcharge <> 0 and sdl_new.freeqtyfrequency = 0
                      then sdl_new.fixedrentquantity - sdl_new.qtyfreeofcharge
                      else sdl_new.fixedrentquantity
                     end -
                     case when sdl_old.qtyfreeofcharge <> 0 and sdl_old.freeqtyfrequency = 0
                      then sdl_old.fixedrentquantity - sdl_old.qtyfreeofcharge
                      else sdl_old.fixedrentquantity
                     end net_quantity,
                     c.defaultbusinessunit_id businessunit_id,
                     l.billingmethod,
                     sdl_old.productlistperdistribpoint_id
                from productlistpercustomer l,
                     customer               c,
                     product                p,
                     businessunit           bu,
                     distributionpoint      dp,
                     department             d,
                     productlistperdistribpoint plpd,
                     standarddeliveryline   sdl_old,  -- the old one
                     standarddeliveryline   sdl_new   -- the new one
               where l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.billingmethod=1   -- only fixed qty
                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                 and l.dateinactive > todate
                 and c.defaultbusinessunit_id = bu.businessunit_id
                 and bu.plant_id = plantid
                 and plpd.distributionpoint_id=dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id=l.customer_id
                 and plpd.product_id=l.product_id
                 and plpd.sizedefinition_id=l.sizedefinition_id
                 and plpd.finishingmethod_id=l.finishingmethod_id
                 and sdl_old.productlistperdistribpoint_id=plpd.productlistperdistribpoint_id
                 and sdl_old.standarddelivery_id = sdl_new.standarddelivery_id
                 and sdl_old.productlistperdistribpoint_id = sdl_new.productlistperdistribpoint_id
                 and sdl_old.standarddeliveryline_id <> sdl_new.standarddeliveryline_id
                 and nvl(sdl_old.deliveryscheme_id,-1) = nvl(sdl_new.deliveryscheme_id,-1)
                 and nvl(sdl_old.season_id,-1) = nvl(sdl_new.season_id,-1)
                 and sdl_new.dateactive between fromdate and todate
                 and sdl_new.dateactive = sdl_old.dateinactive + 1
                 )
               loop
      begin
        lv_quantity := x.net_quantity;
        if x.net_quantity < 0 then -- decrease
           x.transactionno := 6;  -- decrease  (5=increase)
        end if;
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_frequency := 1 / x.frequency;
        lv_min_perc  := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_quantity  := determine_quantity(lv_quantity, x.billingmethod, 0);
        lv_pricedate := todate; -- take new price, if price is changed this is covered by price change which takes old qty
        lv_price     := pack_price.Rent_Price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,x.frequency);
        lv_amount    := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency,x.invoicefrequency_id);
        --insert new/lost customer product record NON GARMENTS ONLY BM 1
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop;
  end changed_customerproduct_BM_1;
--
  procedure changed_customerproduct_BM_23(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
    --select the changed rentalqtyadjustment lines for export. NON GARMENTS ONLY
    for x in (select q.adjustmentdate transactiondate,
                     5 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and q.adjustmentdate between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     q.quantity,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     l.sizedefinition_id,
                     l.finishingmethod_id,
                     c.defaultbusinessunit_id businessunit_id,
                     l.minimumturnaround,
                     l.minimumquantity,
                     l.minimumfrequency,
                     l.deedeliveryscheme_id,
                     l.productlistpercustomer_id,
                     l.billingmethod
                from rentalqtyadjustment        q,
                     productlistperdistribpoint pd,
                     customer                   c,
                     department                 d,
                     product                    p,
                     distributionpoint          t,
                     businessunit               bu,
                     productlistpercustomer     l
               where q.productlistperdistribpoint_id =
                     pd.productlistperdistribpoint_id
                 and pd.distributionpoint_id = t.distributionpoint_id
                 and t.department_id = d.department_id
                 and d.customer_id = c.customer_id
                 and pd.product_id = p.product_id
                 and p.typeofmerchandise <> 2
                 and l.customer_id = c.customer_id
                 and l.product_id = p.product_id
                 and l.sizedefinition_id = pd.sizedefinition_id
                 and l.finishingmethod_id = pd.finishingmethod_id
                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                 and l.dateinactive > todate
                 and l.billingmethod in (2,3)   -- only rent based on minimum and based on circ
                 and q.adjustmentdate between fromdate and todate
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid) loop
      begin
        if x.quantity < 0 then -- decrease
           x.transactionno := 6;  -- decrease  (5=increase)
        end if;
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_frequency := determine_frequency(x.customer_id, null, x.billingmethod, x.minimumfrequency, x.productlistpercustomer_id, x.deedeliveryscheme_id);
        lv_min_perc  := determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_quantity  := determine_quantity(x.quantity, x.billingmethod, x.minimumquantity);
        lv_pricedate := todate; -- take new price, if price is changed this is covered by price change which takes old qty
        lv_price     := pack_price.Rent_Price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,0);
        lv_amount    := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        --insert changed rentalqtyadjustment
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop; --x end
  end changed_customerproduct_BM_23;
--
  procedure newquit_wearers(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction growthhistory.transaction_id%type;
    lv_billingmeth growthhistory.billingmethod%type;
    lv_billingtype productlistpercustomer.inventorybillingtype%type;
  begin
    --select the wearers that are new or stopped
    for x in (select /*+ index(W XIE1WEARER) */ w.dateactive transactiondate,
                     7 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and w.dateactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
                     i.changesperweek changesperweek,
                     i.circinventory circinventory,
                     i.maxinventory maxinventory,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     i.wearerinventory_id
                from wearer           w,
                     customer         c,
                     weareremployment e,
                     wearerinventory  i,
                     product          p,
                     businessunit     bu
               where w.customer_id = c.customer_id
--                 and c.dateactive not between fromdate and todate
                 and c.dateinactive not between fromdate and todate
                 and w.dateactive between fromdate and todate
                 and w.wearer_id = e.wearer_id
                 and e.weareremployment_id = i.weareremployment_id
                 and i.product_id = p.product_id
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
               union
              select /*+ index(W XIE2WEARER) */ w.dateinactive transactiondate,
                     8 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and w.dateinactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
--                     i.changesperweek changesperweek,
                     nvl((select /*+ index(sq XIF8SQSETINCIRCULATION) */ max(sq.changesperweek)
                            from sqsetincirculation sq, statusquoheader sh, businessunit b
                           where sq.statusquoheader_id = sh.statusquoheader_id
                             and sh.statusquotype = 2
                             and sh.processbusinessunit_id = b.businessunit_id
                             and b.plant_id = plantid
                             and sh.statusquodate =
                                 (select max(v.statusquodate)
                                    from statusquoheader v, businessunit b
                                   where v.statusquotype = 2
                                     and v.processbusinessunit_id = b.businessunit_id
                                     and b.plant_id = plantid
                                     and v.statusquodate <= fromdate)
                             and sq.weareremployment_link_id = i.weareremployment_id
                             and sq.product_link_id = i.product_id
                             and sq.sizedefinition_link_id = i.sizedefinition_id
                             and sq.finishingmethod_id = i.finishingmethod_id
                         ),i.changesperweek) changesperweek,
--
                     nvl((select /*+ index(sq XIF5SQITEMINCIRCULATION) */ sq.qtyrentedperpiece
                            from sqitemincirculation sq, statusquoheader sh, businessunit b
                           where sq.statusquoheader_id = sh.statusquoheader_id
                             and sh.statusquotype = 1
                             and sh.processbusinessunit_id = b.businessunit_id
                             and b.plant_id = plantid
                             and sh.statusquodate =
                                 (select max(v.statusquodate)
                                    from statusquoheader v, businessunit b
                                   where v.statusquotype = 1
                                     and v.processbusinessunit_id = b.businessunit_id
                                     and b.plant_id = plantid
                                     and v.statusquodate <= fromdate)
                             and sq.weareremployment_link_id = i.weareremployment_id
                             and sq.product_link_id = i.product_id
                             and sq.sizedefinition_link_id = i.sizedefinition_id
                             and sq.finishingmethod_id = i.finishingmethod_id
                         ),i.circinventory) circinventory,
                     nvl((select /*+ index(sq XIF5SQITEMINCIRCULATION) */ sq.maxinv
                            from sqitemincirculation sq, statusquoheader sh, businessunit b
                           where sq.statusquoheader_id = sh.statusquoheader_id
                             and sh.statusquotype = 1
                             and sh.processbusinessunit_id = b.businessunit_id
                             and b.plant_id = plantid
                             and sh.statusquodate =
                                 (select max(v.statusquodate)
                                    from statusquoheader v, businessunit b
                                   where v.statusquotype = 1
                                     and v.processbusinessunit_id = b.businessunit_id
                                     and b.plant_id = plantid
                                     and v.statusquodate <= fromdate)
                             and sq.weareremployment_link_id = i.weareremployment_id
                             and sq.product_link_id = i.product_id
                             and sq.sizedefinition_link_id = i.sizedefinition_id
                             and sq.finishingmethod_id = i.finishingmethod_id
                         ),i.maxinventory) maxinventory,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     i.wearerinventory_id
                from wearer           w,
                     customer         c,
                     weareremployment e,
                     wearerinventory  i,
                     product          p,
                     businessunit     bu
               where w.customer_id = c.customer_id
                 and c.dateactive not between fromdate and todate
--                 and c.dateinactive not between fromdate and todate
                 and w.dateinactive between fromdate and todate
                 and w.wearer_id = e.wearer_id
                 and e.weareremployment_id = i.weareremployment_id
                 and i.product_id = p.product_id
-- HVH 16-4-2012 Fixed issue to prevent old inventory lines are taken into account for quit wearer revenue
                 and i.dateinactive >= fromdate
-- end change
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid)
               loop
      begin
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        determine_billingmethod(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,x.transactiondate,lv_billingmeth, lv_billingtype);
        lv_quantity := determine_garm_quantity(x.changesperweek, x.circinventory, x.maxinventory, lv_billingmeth, lv_billingtype);
        if x.transactionno = 8 then -- quit wearer
          lv_quantity := -lv_quantity;
        end if;
        lv_frequency := determine_garm_frequency(x.customer_id);
        lv_min_perc  := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_pricedate := determine_price_date(x.transactionno, fromdate, todate);
        lv_price     := determine_garment_price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,x.changesperweek, x.wearerinventory_id);
        lv_amount    := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        --insert new/quit wearers
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             x.weareremployment_id,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             lv_billingmeth,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop; --x end
  end newquit_wearers;
--
  procedure newquit_wearerinv(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction growthhistory.transaction_id%type;
    lv_billingmeth growthhistory.billingmethod%type;
    lv_billingtype productlistpercustomer.inventorybillingtype%type;
  begin
    --select the wearer inventories that are new or stopped
    for x in (select /*+ index(i XIE2WEARERINVENTORY) */ i.dateactive transactiondate,
                     9 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and i.dateactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
                     i.changesperweek changesperweek,
                     i.circinventory circinventory,
                     i.maxinventory maxinventory,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     i.wearerinventory_id
                from wearer           w,
                     customer         c,
                     weareremployment e,
                     wearerinventory  i,
                     product          p,
                     businessunit     bu
               where w.customer_id = c.customer_id
--                 and c.dateactive not between fromdate and todate
                 and c.dateinactive not between fromdate and todate
                 and w.dateactive not between fromdate and todate
                 and w.dateinactive not between fromdate and todate
                 and i.dateactive between fromdate and todate
                 and w.wearer_id = e.wearer_id
                 and e.weareremployment_id = i.weareremployment_id
                 and i.product_id = p.product_id
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
               union
              select i.dateinactive transactiondate,
                     10 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and i.dateinactive between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
--                     i.changesperweek changesperweek,
                     nvl((select /*+ index(sq XIF8SQSETINCIRCULATION) */ max(sq.changesperweek)
                            from sqsetincirculation sq, statusquoheader sh, businessunit b
                           where sq.statusquoheader_id = sh.statusquoheader_id
                             and sh.statusquotype = 2
                             and sh.processbusinessunit_id = b.businessunit_id
                             and b.plant_id = plantid
                             and sh.statusquodate =
                                 (select max(v.statusquodate)
                                    from statusquoheader v, businessunit b
                                   where v.statusquotype = 2
                                     and v.processbusinessunit_id = b.businessunit_id
                                     and b.plant_id = plantid
                                     and v.statusquodate <= fromdate)
                             and sq.weareremployment_link_id = i.weareremployment_id
                             and sq.product_link_id = i.product_id
                             and sq.sizedefinition_link_id = i.sizedefinition_id
                             and sq.finishingmethod_id = i.finishingmethod_id
                         ),i.changesperweek) changesperweek,
--
                     nvl((select /*+ index(sq XIF5SQITEMINCIRCULATION) */ sq.qtyrentedperpiece
                            from sqitemincirculation sq, statusquoheader sh, businessunit b
                           where sq.statusquoheader_id = sh.statusquoheader_id
                             and sh.statusquotype = 1
                             and sh.processbusinessunit_id = b.businessunit_id
                             and b.plant_id = plantid
                             and sh.statusquodate =
                                 (select max(v.statusquodate)
                                    from statusquoheader v, businessunit b
                                   where v.statusquotype = 1
                                     and v.processbusinessunit_id = b.businessunit_id
                                     and b.plant_id = plantid
                                     and v.statusquodate <= fromdate)
                             and sq.weareremployment_link_id = i.weareremployment_id
                             and sq.product_link_id = i.product_id
                             and sq.sizedefinition_link_id = i.sizedefinition_id
                             and sq.finishingmethod_id = i.finishingmethod_id
                         ),i.circinventory) circinventory,
                     nvl((select /*+ index(sq XIF5SQITEMINCIRCULATION) */ sq.maxinv
                            from sqitemincirculation sq, statusquoheader sh, businessunit b
                           where sq.statusquoheader_id = sh.statusquoheader_id
                             and sh.statusquotype = 1
                             and sh.processbusinessunit_id = b.businessunit_id
                             and b.plant_id = plantid
                             and sh.statusquodate =
                                 (select max(v.statusquodate)
                                    from statusquoheader v, businessunit b
                                   where v.statusquotype = 1
                                     and v.processbusinessunit_id = b.businessunit_id
                                     and b.plant_id = plantid
                                     and v.statusquodate <= fromdate)
                             and sq.weareremployment_link_id = i.weareremployment_id
                             and sq.product_link_id = i.product_id
                             and sq.sizedefinition_link_id = i.sizedefinition_id
                             and sq.finishingmethod_id = i.finishingmethod_id
                         ),i.maxinventory) maxinventory,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     i.wearerinventory_id
                from wearer           w,
                     customer         c,
                     weareremployment e,
                     wearerinventory  i,
                     product          p,
                     businessunit     bu
               where w.customer_id = c.customer_id
                 and c.dateactive not between fromdate and todate
--                 and c.dateinactive not between fromdate and todate
                 and w.dateactive not between fromdate and todate
                 and w.dateinactive not between fromdate and todate
                 and i.dateinactive between fromdate and todate
                 and w.wearer_id = e.wearer_id
                 and e.weareremployment_id = i.weareremployment_id
                 and i.product_id = p.product_id
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid)
               loop
      begin
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        determine_billingmethod(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,x.transactiondate,lv_billingmeth, lv_billingtype);
        lv_quantity  := determine_garm_quantity(x.changesperweek, x.circinventory, x.maxinventory, lv_billingmeth, lv_billingtype);
        if x.transactionno = 10 then -- quit wearer inv
          lv_quantity := -lv_quantity;
        end if;
        lv_frequency := determine_garm_frequency(x.customer_id);
        lv_min_perc  := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_pricedate := determine_price_date(x.transactionno, fromdate, todate);
        lv_price     := determine_garment_price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,x.changesperweek, x.wearerinventory_id);
        lv_amount    := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        --insert new/quit wearers
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             x.weareremployment_id,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             lv_billingmeth,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop; --x end
  end newquit_wearerinv;
--
  procedure changed_sqsetsincirc(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction growthhistory.transaction_id%type;
    lv_billingmeth growthhistory.billingmethod%type;
  begin
    -- comparing current #changes in wearerinventory with last #changes from sqset in circulation
    for x in (select trunc(i.timestamp) transactiondate,
                     11 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and trunc(i.timestamp) between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
                     i.changesperweek,  -- for price determination
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     i.changesperweek - sb.changesperweek quantity,
                     i.wearerinventory_id
                from statusquoheader    hb,
                     sqsetincirculation sb,
                     customer           c,
                     wearer             w,
                     weareremployment   e,
                     wearerinventory    i,
                     product            p,
                     businessunit       bu
               where hb.statusquotype = 2
                 and hb.statusquodate =
                     (select max(v.statusquodate)
                        from statusquoheader v, businessunit b
                       where v.statusquotype = 2
                         and v.processbusinessunit_id = b.businessunit_id
                         and b.plant_id = plantid
                         and v.statusquodate <= fromdate)
                 and hb.statusquoheader_id = sb.statusquoheader_id
                 and i.changesperweek <> sb.changesperweek
                 and sb.customer_link_id = c.customer_id
                 and c.customer_id = w.customer_id
                 and w.wearer_id = e.wearer_id
                 and sb.weareremployment_link_id = e.weareremployment_id
                 and e.weareremployment_id = i.weareremployment_id
                 and sb.product_link_id = i.product_id
                 and sb.sizedefinition_link_id = i.sizedefinition_id
                 and sb.finishingmethod_id = i.finishingmethod_id
                 and p.product_id = i.product_id
--                 and c.dateactive not between fromdate and todate
--                 and c.dateinactive not between fromdate and todate
                 and w.dateactive   not between fromdate and todate
                 and w.dateinactive not between fromdate and todate
                 and i.dateactive   not between fromdate and todate
                 and i.dateinactive not between fromdate and todate
                 and todate between w.dateactive and w.dateinactive  -- still active
                 and todate between i.dateactive and i.dateinactive  -- still active
                 and trunc(i.timestamp) between fromdate and todate -- HVH Added 18/9/2007
                 and i.changesperweek <> 0
                 and sb.changesperweek <> 0
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
                 )
               loop
      begin
        if x.quantity < 0 then -- decrease
           x.transactionno := 12;  -- decrease  (11=increase)
        end if;
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_quantity    := x.quantity;
        lv_billingmeth := 1;  -- always BM = 1 for sq sets in circ
        lv_frequency   := determine_garm_frequency(x.customer_id);
        lv_min_perc    := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_pricedate   := determine_price_date(x.transactionno, fromdate, todate);
        lv_price       := determine_garment_price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,x.changesperweek, x.wearerinventory_id);
        lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             x.weareremployment_id,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             lv_billingmeth,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop; --x
  end changed_sqsetsincirc;
--
  procedure changed_circ_and_max(fromdate date, todate date, plantid number) is
-- will work only when SQ is run on
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_pricedate   date;
    lv_amount      growthhistory.amount%type;
    lv_transaction growthhistory.transaction_id%type;
    lv_billingmeth growthhistory.billingmethod%type;
  begin
    -- comparing current circ/max with last sqitem incirc
    for x in (select /*+ index(sb XIF5SQITEMINCIRCULATION) index(i XIE10WEARERINVENTORY_REVGROW) */
                     trunc(i.timestamp) transactiondate,
                     11 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and trunc(i.timestamp) between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     case sb.chargeafterdepreciation
                        when 'Y' then i.circinventory - sb.qtyrentedperpiece - sb.beyondlifetimecirc
                        else i.circinventory - sb.qtyrentedperpiece
                        end quantity,
                     i.wearerinventory_id
                from statusquoheader     hb,
                     sqitemincirculation sb,
                     customer            c,
                     wearer              w,
                     weareremployment    e,
                     wearerinventory     i,
                     product             p,
                     businessunit        bu
               where hb.statusquotype = 1
                 and hb.statusquodate =
                     (select max(v.statusquodate)
                        from statusquoheader v, businessunit b
                       where v.statusquotype = 1
                         and v.processbusinessunit_id = b.businessunit_id
                         and b.plant_id = plantid
                         and v.statusquodate <= fromdate)
                 and hb.statusquoheader_id = sb.statusquoheader_id
                 and sb.customer_link_id = c.customer_id
                 and c.customer_id = w.customer_id
                 and w.wearer_id = e.wearer_id
                 and sb.weareremployment_link_id = e.weareremployment_id
                 and e.weareremployment_id = i.weareremployment_id
                 and sb.product_link_id = i.product_id
                 and sb.sizedefinition_link_id = i.sizedefinition_id
                 and sb.finishingmethod_id = i.finishingmethod_id
                 and p.product_id = i.product_id
--                 and c.dateactive not between fromdate and todate
--                 and c.dateinactive not between fromdate and todate
                 and w.dateactive   not between fromdate and todate
                 and w.dateinactive not between fromdate and todate
                 and i.dateactive   not between fromdate and todate
                 and i.dateinactive not between fromdate and todate
                 and todate between w.dateactive and w.dateinactive  -- still active
                 and todate between i.dateactive and i.dateinactive  -- still active
                 and trunc(i.timestamp) between fromdate and todate -- HVH Added 18/9/2007
                 and i.circinventory <> 0
                 and sb.qtyrentedperpiece <> 0
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
                 and exists (select 1
                               from productlistpercustomer plpc
                              where plpc.customer_id = c.customer_id
                              and plpc.product_id = i.product_id
                              and plpc.sizedefinition_id = gv_size_star_id
                              and plpc.finishingmethod_id = i.finishingmethod_id
                              and plpc.billingmethod=3
                              and plpc.dateactive < fromdate
                              and plpc.dateinactive >todate
                              and plpc.inventorybillingtype < 2) -- 0 or 1 circ or real
                 union
                 select /*+ index(sb XIF5SQITEMINCIRCULATION) index(i XIE10WEARERINVENTORY_REVGROW) */
                     trunc(i.timestamp) transactiondate,
                     11 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and trunc(i.timestamp) between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     i.maxinventory - sb.maxinv quantity,
                     i.wearerinventory_id
                from statusquoheader     hb,
                     sqitemincirculation sb,
                     customer            c,
                     wearer              w,
                     weareremployment    e,
                     wearerinventory     i,
                     product             p,
                     businessunit        bu
               where hb.statusquotype = 1
                 and hb.statusquodate =
                     (select max(v.statusquodate)
                        from statusquoheader v, businessunit b
                       where v.statusquotype = 1
                         and v.processbusinessunit_id = b.businessunit_id
                         and b.plant_id = plantid
                         and v.statusquodate <= fromdate)
                 and hb.statusquoheader_id = sb.statusquoheader_id
                 and sb.customer_link_id = c.customer_id
                 and c.customer_id = w.customer_id
                 and w.wearer_id = e.wearer_id
                 and sb.weareremployment_link_id = e.weareremployment_id
                 and e.weareremployment_id = i.weareremployment_id
                 and sb.product_link_id = i.product_id
                 and sb.sizedefinition_link_id = i.sizedefinition_id
                 and sb.finishingmethod_id = i.finishingmethod_id
                 and p.product_id = i.product_id
--                 and c.dateactive not between fromdate and todate
--                 and c.dateinactive not between fromdate and todate
                 and w.dateactive   not between fromdate and todate
                 and w.dateinactive not between fromdate and todate
                 and i.dateactive   not between fromdate and todate
                 and i.dateinactive not between fromdate and todate
                 and todate between w.dateactive and w.dateinactive  -- still active
                 and todate between i.dateactive and i.dateinactive  -- still active
                 and trunc(i.timestamp) between fromdate and todate -- HVH Added 18/9/2007
                 and i.circinventory <> 0
                 and sb.qtyrentedperpiece <> 0
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                 and bu.plant_id = plantid
                 and exists (select 1
                               from productlistpercustomer plpc
                              where plpc.customer_id = c.customer_id
                              and plpc.product_id = i.product_id
                              and plpc.sizedefinition_id = gv_size_star_id
                              and plpc.finishingmethod_id = i.finishingmethod_id
                              and plpc.billingmethod=3
                              and plpc.dateactive < fromdate
                              and plpc.dateinactive >todate
                              and plpc.inventorybillingtype = 2) -- max
                 )
               loop
      begin
        if x.quantity < 0 then -- decrease
           x.transactionno := 12;  -- decrease  (11=increase)
        end if;
        lv_transaction := determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_quantity    := x.quantity;
        lv_billingmeth := 3;  -- always BM = 3
        lv_frequency   := determine_garm_frequency(x.customer_id);
        lv_min_perc    := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_pricedate   := determine_price_date(x.transactionno, fromdate, todate);
        lv_price       := determine_garment_price(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,lv_pricedate,0, x.wearerinventory_id);
        lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             x.weareremployment_id,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             lv_billingmeth,
                             null, -- old price
                             null, -- new price
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop; --x
  end changed_circ_and_max;
--
  procedure price_changes_non_garm_BM_1(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
    --get the price changes NON GARMENTS Billingmethod 1
    for x in (select y.*,
                     to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) new_price,
                     to_date(Substr(y.new_price_details,14,8),'yyyymmdd') transactiondate,
                      nvl((select min(s.route_id) from routestop s
                                    where s.customer_id = y.customer_id
                                    and to_date(Substr(y.new_price_details,14,8),'yyyymmdd') between s.dateactive and
                                    nvl((select min(s2.dateactive - 1)
                                                from routestop s2
                                                where s2.customer_id = s.customer_id
                                                and s2.dateactive > s.dateactive),
                                                s.dateinactive)),
                                    (select q.route_id
                                      from (select s.route_id
                                              from routestop s
                                             where s.customer_id = y.customer_id
                                             order by s.dateactive desc) q
                                    where rownum = 1)) route_id
                from (select z.*,
                             d.frequency,
                             d.quantity,
                             pack_price.Rent_Price(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   fromdate,
                                                   d.frequency) old_price,
                             pack_price.Rent_Price_Details(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   todate,
                                                   d.frequency) new_price_details

                        from (select 13 transactionno,
                                     c.customer_id,
                                     c.currency_id,
                                     c.invoicefrequency_id,
                                     c.dateactive cust_date_active,
                                     c.dateinactive cust_date_inactive,
                                     p.product_id,
                                     l.sizedefinition_id,
                                     l.finishingmethod_id,
                                     c.defaultbusinessunit_id businessunit_id,
                                     l.billingmethod,
                                     l.productlistpercustomer_id
                                from productlistpercustomer l,
                                     product                p,
                                     customer               c,
                                     businessunit           bu
                               where l.customer_id = c.customer_id
                                 and l.product_id = p.product_id
                                 and p.typeofmerchandise <> 2
                                 and l.billingmethod = 1
                                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                                 and l.dateinactive > todate
                                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                                 and bu.plant_id = plantid) z,
                             (select y.productlistpercustomer_id, y.frequency, sum(y.quantity) quantity from
                              (select x.*,
                                      case when x.deliveryscheme_id is null
                                           then 1
                                           else (select ds.frequency from deliveryscheme ds where ds.deliveryscheme_id=x.deliveryscheme_id)
                                           end frequency
                                 from(select sdl.productlistpercustomer_id,
                                             sdl.deliveryscheme_id,
                                             case when sdl.qtyfreeofcharge <> 0 and sdl.freeqtyfrequency = 0
                                               then sdl.fixedrentquantity - sdl.qtyfreeofcharge
                                               else sdl.fixedrentquantity
                                             end quantity
                                        from standarddeliveryline sdl
                                       where todate between sdl.dateactive and sdl.dateinactive -- take new qty
                                      ) x
                              ) y
                              group by y.productlistpercustomer_id, y.frequency) d
                     where d.productlistpercustomer_id=z.productlistpercustomer_id
                   ) y
         where to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> y.old_price  -- new <> old
           and to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> 0  -- new price <> 0
           and y.old_price <> 0)
               loop
      begin
        --insert price changes NON GARMENTS ONLY
        if x.new_price - x.old_price < 0 then
          x.transactionno := 14; -- decrease , 13 = increase
        end if;
        lv_transaction := x.transactionno; --determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_frequency   := 1 / x.frequency;
        lv_min_perc    := null;
        lv_quantity    := determine_quantity(x.quantity, x.billingmethod, 0);
        lv_price       := x.new_price - x.old_price;
        lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             x.old_price,
                             x.new_price,
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop;
  end price_changes_non_garm_BM_1;
--
  procedure price_changes_non_garm_BM_23(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
    --get the price changes NON GARMENTS Billingmethod 2 and 3
    for x in (select y.*,
                     to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) new_price,
                     to_date(Substr(y.new_price_details,14,8),'yyyymmdd') transactiondate,
                     nvl((select min(s.route_id) from routestop s
                                    where s.customer_id = y.customer_id
                                    and to_date(Substr(y.new_price_details,14,8),'yyyymmdd') between s.dateactive and
                                    nvl((select min(s2.dateactive - 1)
                                                from routestop s2
                                                where s2.customer_id = s.customer_id
                                                and s2.dateactive > s.dateactive),
                                                s.dateinactive)),
                                    (select q.route_id
                                      from (select s.route_id
                                              from routestop s
                                             where s.customer_id = y.customer_id
                                             order by s.dateactive desc) q
                                    where rownum = 1)) route_id
                from (select z.*,
                             pack_price.Rent_Price(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   fromdate,
                                                   0) old_price,
                             pack_price.Rent_Price_Details(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   todate,
                                                   0) new_price_details
                        from (select 13 transactionno,
                                     c.customer_id,
                                     c.currency_id,
                                     c.invoicefrequency_id,
                                     c.dateactive cust_date_active,
                                     c.dateinactive cust_date_inactive,
                                     p.product_id,
                                     l.sizedefinition_id,
                                     l.finishingmethod_id,
                                     c.defaultbusinessunit_id businessunit_id,
                                     l.minimumturnaround,
                                     l.minimumquantity,
                                     l.minimumfrequency,
                                     l.deedeliveryscheme_id,
                                     l.billingmethod,
                                     l.productlistpercustomer_id
                                from productlistpercustomer l,
                                     product                p,
                                     customer               c,
                                     businessunit           bu
                               where l.customer_id = c.customer_id
                                 and l.product_id = p.product_id
                                 and p.typeofmerchandise <> 2
                                 and l.billingmethod in (2,3)
                                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                                 and l.dateinactive > todate
                                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                                 and bu.plant_id = plantid) z) y
         where to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> y.old_price  -- new <> old
           and to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> 0  -- new price <> 0
           and y.old_price <> 0)
               loop
      begin
        begin
          --determine the non garment quantity from rentalqtyadjustment
          select nvl(sum(q.quantity), 0)
            into lv_quantity
            from rentalqtyadjustment        q,
                 productlistperdistribpoint pd,
                 distributionpoint          dp,
                 department                 d
           where q.productlistperdistribpoint_id =
                 pd.productlistperdistribpoint_id
             and q.adjustmentdate <= fromdate --x.transactiondate  -- price changes calc with old qty
             and pd.product_id = x.product_id
             and pd.sizedefinition_id = x.sizedefinition_id
             and pd.finishingmethod_id = x.finishingmethod_id
             and pd.distributionpoint_id = dp.distributionpoint_id
             and dp.department_id = d.department_id
             and d.customer_id = x.customer_id;
        exception
          when no_data_found then
            lv_quantity := 0;
        end;
        --insert price changes NON GARMENTS ONLY
        if x.new_price - x.old_price < 0 then
          x.transactionno := 14; -- decrease , 13 = increase
        end if;
        lv_transaction := x.transactionno; --determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_frequency   := determine_frequency(x.customer_id, null, x.billingmethod, x.minimumfrequency, x.productlistpercustomer_id, x.deedeliveryscheme_id);
        lv_min_perc    := determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_quantity    := determine_quantity(lv_quantity, x.billingmethod, x.minimumquantity);
        lv_price       := x.new_price - x.old_price;
        lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             x.old_price,
                             x.new_price,
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop;
  end price_changes_non_garm_BM_23;
--
  procedure price_changes_wearerinv(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_amount      growthhistory.amount%type;
    lv_transaction growthhistory.transaction_id%type;
    lv_billingmeth growthhistory.billingmethod%type;
    lv_billingtype productlistpercustomer.inventorybillingtype%type;
  begin
    --select the wearers that are new or stopped
    for x in (select wip.startdate transactiondate,
                     13 transactionno,
                     nvl((select min(s.route_id) from routestop s
                      where s.customer_id = c.customer_id
                      and wip.startdate between s.dateactive and
                      nvl((select min(s2.dateactive - 1)
                                  from routestop s2
                                  where s2.customer_id = s.customer_id
                                  and s2.dateactive > s.dateactive),
                                  s.dateinactive)),
                      (select q.route_id
                        from (select s.route_id
                                from routestop s
                               where s.customer_id = c.customer_id
                               order by s.dateactive desc) q
                      where rownum = 1)) route_id,
                     c.customer_id,
                     c.currency_id,
                     c.invoicefrequency_id,
                     c.dateactive cust_date_active,
                     c.dateinactive cust_date_inactive,
                     p.product_id,
                     i.sizedefinition_id,
                     i.finishingmethod_id,
                     i.changesperweek changesperweek,
                     i.circinventory circinventory,
                     i.maxinventory maxinventory,
                     e.weareremployment_id,
                     c.defaultbusinessunit_id businessunit_id,
                     wip.price new_price,
                     nvl((select wip2.price   -- HVH 22-6-2010 add nvl
                        from wearerinvprice wip2
                       where wip2.wearerinventory_id = wip.wearerinventory_id
                         and wip2.startdate =
                        (select max(wip3.startdate) startdate
                           from wearerinvprice wip3
                          where wip3.wearerinventory_id=wip.wearerinventory_id
                            and wip3.startdate < wip.startdate)),0) old_price,
                     i.wearerinventory_id
                from wearer           w,
                     customer         c,
                     weareremployment e,
                     wearerinventory  i,
                     product          p,
                     businessunit     bu,
                     wearerinvprice   wip
               where w.customer_id = c.customer_id
                 and wip.wearerinventory_id = i.wearerinventory_id
                 and w.dateactive not between fromdate and todate
                 and w.dateinactive not between fromdate and todate
                 and i.dateactive not between fromdate and todate
                 and i.dateinactive not between fromdate and todate
                 and wip.startdate between fromdate and todate  -- select price changes only
                 and w.wearer_id = e.wearer_id
                 and e.weareremployment_id = i.weareremployment_id
                 and i.product_id = p.product_id
                 and p.typeofmerchandise = 2
                 and c.defaultbusinessunit_id = bu.businessunit_id
                 and bu.plant_id = plantid)
               loop
      begin
       if x.old_price <> 0 then  -- HVH 22-6-2010 add condition price <> 0
        if x.new_price - x.old_price < 0 then
          x.transactionno := 14; -- decrease , 13 = increase
        end if;
        lv_transaction := x.transactionno; --determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        determine_billingmethod(x.customer_id,x.product_id,x.sizedefinition_id,x.finishingmethod_id,x.transactiondate,lv_billingmeth, lv_billingtype);
        lv_quantity    := determine_garm_quantity(x.changesperweek, x.circinventory, x.maxinventory, lv_billingmeth, lv_billingtype);
        lv_frequency   := determine_garm_frequency(x.customer_id);
        lv_min_perc    := null; --determine_min_perc(x.billingmethod, x.minimumquantity, x.minimumturnaround);
        lv_price       := x.new_price - x.old_price;
        lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        --insert new/quit wearers
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             x.weareremployment_id,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             lv_billingmeth,
                             x.old_price,
                             x.new_price,
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
       end if; -- x.old_price = 0
      end;
    end loop; --x end
  end price_changes_wearerinv;
--
  procedure price_changes_garments_BM_1(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_old_price   growthhistory.price%type;
    lv_new_price   growthhistory.price%type;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
    --get the price changes GARMENTS Billingmethod 1
    for x in (select y.*,
                     to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) new_price,
                     to_date(Substr(y.new_price_details,14,8),'yyyymmdd') transactiondate,
                     nvl((select min(s.route_id) from routestop s
                                    where s.customer_id = y.customer_id
                                    and to_date(Substr(y.new_price_details,14,8),'yyyymmdd') between s.dateactive and
                                    nvl((select min(s2.dateactive - 1)
                                                from routestop s2
                                                where s2.customer_id = s.customer_id
                                                and s2.dateactive > s.dateactive),
                                                s.dateinactive)),
                                    (select q.route_id
                                      from (select s.route_id
                                              from routestop s
                                             where s.customer_id = y.customer_id
                                             order by s.dateactive desc) q
                                    where rownum = 1)) route_id
                from (select z.*,
                             pack_price.Rent_Price(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   fromdate,
                                                   0) old_price,
                             pack_price.Rent_Price_Details(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   todate,
                                                   0) new_price_details
                        from (select 13 transactionno,
                                     c.customer_id,
                                     c.currency_id,
                                     c.invoicefrequency_id,
                                     c.dateactive cust_date_active,
                                     c.dateinactive cust_date_inactive,
                                     p.product_id,
                                     l.sizedefinition_id,
                                     l.finishingmethod_id,
                                     c.defaultbusinessunit_id businessunit_id,
                                     l.minimumturnaround,
                                     l.minimumquantity,
                                     l.billingmethod,
                                     l.inventorybillingtype,
                                     l.productlistpercustomer_id
                                from productlistpercustomer l,
                                     product                p,
                                     customer               c,
                                     businessunit           bu
                               where l.customer_id = c.customer_id
                                 and l.product_id = p.product_id
                                 and p.typeofmerchandise = 2  -- garments
                                 and l.billingmethod = 1
                                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                                 and l.dateinactive > todate
                                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                                 and bu.plant_id = plantid) z) y
         where to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> y.old_price  -- new <> old
           and to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> 0  -- new price <> 0
           and y.old_price <> 0)
               loop
      begin
         for x1 in (select wi.changesperweek, count(1) qty
                     from wearerinventory wi, weareremployment we, wearer w
                    where wi.product_id=x.product_id
                      and wi.finishingmethod_id=x.finishingmethod_id
                      and wi.weareremployment_id=we.weareremployment_id
                      and we.wearer_id=w.wearer_id
                      and w.customer_id=x.customer_id
                      and (gv_wearer_invent_price='N' or not exists   -- exclude those that have a wearerinv price
                                                        (select 1
                                                           from wearerinvprice wip
                                                          where wip.wearerinventory_id = wi.wearerinventory_id
                                                            and wip.startdate <= todate))
                      and wi.dateactive < fromdate
                      and wi.dateinactive > todate
                    group by wi.changesperweek
                   ) loop
           begin
             lv_old_price := pack_price.Rent_Price(x.customer_id,
                                                   x.product_id,
                                                   x.sizedefinition_id,
                                                   x.finishingmethod_id,
                                                   fromdate,
                                                   x1.changesperweek);
             lv_new_price := pack_price.Rent_Price(x.customer_id,
                                                   x.product_id,
                                                   x.sizedefinition_id,
                                                   x.finishingmethod_id,
                                                   todate,
                                                   x1.changesperweek);
             if lv_new_price <> lv_old_price then
               begin
                  --insert price changes NON GARMENTS ONLY
                  if lv_new_price - lv_old_price < 0 then
                    x.transactionno := 14; -- decrease , 13 = increase
                  end if;
                  if gv_set_price_per_change='Y'
                    then lv_quantity := x1.qty * x1.changesperweek;
                    else lv_quantity := x1.qty;
                  end if;
                  lv_transaction := x.transactionno; --determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
                  lv_frequency   := determine_garm_frequency(x.customer_id);
                  lv_min_perc    := null;
                  lv_quantity    := determine_quantity(lv_quantity, x.billingmethod, x.minimumquantity);
                  lv_price       := lv_new_price - lv_old_price;
                  lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
                  write_growth_history(x.transactiondate,
                                       lv_transaction,
                                       x.businessunit_id,
                                       x.route_id,
                                       x.customer_id,
                                       x.product_id,
                                       null,
                                       x.currency_id,
                                       lv_quantity,
                                       lv_price,
                                       lv_amount,
                                       x.billingmethod,
                                       lv_old_price,
                                       lv_new_price,
                                       lv_frequency,
                                       lv_min_perc,
                                       x.sizedefinition_id);
               end;
             end if;
           end;
         end loop; -- inner loop through x1
      end;
    end loop;  -- outer loop through x
  end price_changes_garments_BM_1;
--
  procedure price_changes_garments_BM_3(fromdate date, todate date, plantid number) is
    lv_frequency   growthhistory.frequency%type;
    lv_min_perc    growthhistory.minimumpercentage%type;
    lv_quantity    growthhistory.quantity%type;
    lv_price       growthhistory.price%type;
    lv_amount      growthhistory.amount%type;
    lv_transaction number;
  begin
    --get the price changes GARMENTS Billingmethod 3
    for x in (select y.*,
                     to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) new_price,
                     to_date(Substr(y.new_price_details,14,8),'yyyymmdd') transactiondate,
                     nvl((select min(s.route_id) from routestop s
                                    where s.customer_id = y.customer_id
                                    and to_date(Substr(y.new_price_details,14,8),'yyyymmdd') between s.dateactive and
                                    nvl((select min(s2.dateactive - 1)
                                                from routestop s2
                                                where s2.customer_id = s.customer_id
                                                and s2.dateactive > s.dateactive),
                                                s.dateinactive)),
                                    (select q.route_id
                                      from (select s.route_id
                                              from routestop s
                                             where s.customer_id = y.customer_id
                                             order by s.dateactive desc) q
                                    where rownum = 1)) route_id
                from (select z.*,
                             pack_price.Rent_Price(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   fromdate,
                                                   0) old_price,
                             pack_price.Rent_Price_Details(z.customer_id,
                                                   z.product_id,
                                                   z.sizedefinition_id,
                                                   z.finishingmethod_id,
                                                   todate,
                                                   0) new_price_details
                        from (select 13 transactionno,
                                     c.customer_id,
                                     c.currency_id,
                                     c.invoicefrequency_id,
                                     c.dateactive cust_date_active,
                                     c.dateinactive cust_date_inactive,
                                     p.product_id,
                                     l.sizedefinition_id,
                                     l.finishingmethod_id,
                                     c.defaultbusinessunit_id businessunit_id,
                                     l.minimumturnaround,
                                     l.minimumquantity,
                                     l.billingmethod,
                                     l.inventorybillingtype,
                                     l.productlistpercustomer_id
                                from productlistpercustomer l,
                                     product                p,
                                     customer               c,
                                     businessunit           bu
                               where l.customer_id = c.customer_id
                                 and l.product_id = p.product_id
                                 and p.typeofmerchandise = 2  -- garments
                                 and l.billingmethod = 3
                                 and l.dateactive < fromdate   -- active plpc line, not starting or ending in period
                                 and l.dateinactive > todate
                                 and c.defaultbusinessunit_id = bu.businessunit_id -- MBA 502383 - Programming 13
                                 and bu.plant_id = plantid) z) y
         where to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> y.old_price  -- new <> old
           and to_number(Replace(Substr(y.new_price_details,1,12),' ','0')) <> 0  -- new price <> 0
           and y.old_price <> 0)
               loop
      begin
        begin
          --determine the non garment quantity from SQ
          select case when x.inventorybillingtype=2
                  then nvl(sum(sq.maxinv), 0)
                  else nvl(sum(sq.qtyrentedperpiece), 0)
                 end
            into lv_quantity
            from statusquoheader            sh,
                 sqitemincirculation        sq
           where sh.statusquotype = 1 -- items in circ
                 and sh.statusquodate =
                     (select max(v.statusquodate)
                        from statusquoheader v, businessunit b
                       where v.statusquotype = 1  -- items in circ
                         and v.processbusinessunit_id = b.businessunit_id
                         and b.plant_id = plantid
                         and v.statusquodate <= fromdate)
                 and sh.statusquoheader_id = sq.statusquoheader_id
             and sq.customer_link_id = x.customer_id
             and sq.product_link_id = x.product_id
             -- and sq.sizedefinition_link_id = x.sizedefinition_id don't filter on size, because x.size could be *
             and sq.finishingmethod_id = x.finishingmethod_id;
        exception
          when no_data_found then
            lv_quantity := 0;
        end;
        --insert price changes NON GARMENTS ONLY
        if x.new_price - x.old_price < 0 then
          x.transactionno := 14; -- decrease , 13 = increase
        end if;
        lv_transaction := x.transactionno; --determine_transaction(x.transactionno, x.transactiondate, x.cust_date_active, x.cust_date_inactive);
        lv_frequency   := determine_garm_frequency(x.customer_id);
        lv_min_perc    := null;
        lv_quantity    := determine_quantity(lv_quantity, x.billingmethod, x.minimumquantity);
        lv_price       := x.new_price - x.old_price;
        lv_amount      := determine_amount(lv_quantity, lv_price, lv_min_perc, lv_frequency, x.invoicefrequency_id);
        write_growth_history(x.transactiondate,
                             lv_transaction,
                             x.businessunit_id,
                             x.route_id,
                             x.customer_id,
                             x.product_id,
                             null,
                             x.currency_id,
                             lv_quantity,
                             lv_price,
                             lv_amount,
                             x.billingmethod,
                             x.old_price,
                             x.new_price,
                             lv_frequency,
                             lv_min_perc,
                             x.sizedefinition_id);
      end;
    end loop;
  end price_changes_garments_BM_3;
--
  procedure exportgrowth(todate date, plantid number, FpSystemUser_ID in number, Fpabslogprocessjobid in abslogprocessjob.abslogprocessjob_id%type) is
  lv_from_date date;
  lv_start_date date;
  lv_to_date date;
  lv_end_date date;
  lv_date_iterator date;
--  lv_week_start_date date;
--  lv_week_end_date date;
--  lv_new_customer_days number;
  olddate exception;
  gvnabslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
  begin
    gv_system_user_id := FpSystemUser_ID;
    gvnabslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(Fpabslogprocessjobid,
                                                                        'RevenueGrowth',
                                                                        gv_system_user_id);
    lv_end_date := todate;
    -- Read system settings
    select nvl(max(s.value),7)   -- For how long transactions are considered related to new customer
      into gv_new_customer_days
      from systemsetting s
     where s.name = 'NEWCUSTOMERSTARTUPDAYS'
       and s.plant_id=plantid;
    --
    select nvl(max(s.value),'N')   -- To know if wearer inventory prices are used or on plpclevel
      into gv_wearer_invent_price
      from systemsetting s
     where s.name = 'WEARERINVENTPRICE'
       and s.plant_id=plantid;
    --
    select nvl(max(s.value),'N')   -- To know if set prices are per change or for the whole set
      into gv_set_price_per_change
      from systemsetting s
     where s.name = 'SETPRICEPERCHANGE'
       and s.plant_id=plantid;
    --
    select nvl(max(s.sizedefinition_id),-1)
      into gv_size_star_id
      from sizedefinition s
     where s.code = '*';
    -- Determine last date process was run
    select max(g.transactiondate)
      into lv_start_date
      from growthhistory g
           where g.businessunit_id in
           (select bu.businessunit_id
              from businessunit bu
             where bu.plant_id = plantid);
    if (lv_start_date is null)
      then lv_start_date := lv_end_date - 6;  -- One week when table is still empty
      else lv_start_date := lv_start_date + 1; -- start AFTER the day the last data is found
    end if;
    lv_date_iterator := lv_start_date-to_number(to_char(lv_start_date, 'D'))+7;  -- end of start week
    while lv_date_iterator <= lv_end_date-to_number(to_char(lv_end_date, 'D'))+7 loop
      if lv_date_iterator-6 < lv_start_date
       then lv_from_date := lv_start_date;
       else lv_from_date := lv_date_iterator -6;
      end if;
      if lv_date_iterator > lv_end_date
       then lv_to_date := lv_end_date;
       else lv_to_date := lv_date_iterator;
      end if;
--      lv_week_start_date := lv_date_iterator-to_number(to_char(lv_date_iterator, 'D'))+1;
--      lv_week_end_date := lv_date_iterator-to_number(to_char(lv_date_iterator, 'D'))+7;
      newlost_customerproduct_BM_1(lv_from_date, lv_to_date, plantid);
      commit;
      newlost_customerproduct_BM_23(lv_from_date, lv_to_date, plantid);
      commit;
      changed_customerproduct_BM_1(lv_from_date, lv_to_date, plantid);
      commit;
      changed_customerproduct_BM_23(lv_from_date, lv_to_date, plantid);
      commit;
      newquit_wearers(lv_from_date, lv_to_date, plantid);
      commit;
      newquit_wearerinv(lv_from_date, lv_to_date, plantid);
      commit;
      changed_sqsetsincirc(lv_from_date, lv_to_date, plantid);
      commit;
      changed_circ_and_max(lv_from_date, lv_to_date, plantid);
      commit;
      price_changes_non_garm_BM_1(lv_from_date, lv_to_date, plantid);
      commit;
      price_changes_non_garm_BM_23(lv_from_date, lv_to_date, plantid);
      commit;
      if gv_wearer_invent_price='Y' then
        price_changes_wearerinv(lv_from_date, lv_to_date, plantid);
        commit;
      end if;
      price_changes_garments_BM_1(lv_from_date, lv_to_date, plantid);
      commit;
      price_changes_garments_BM_3(lv_from_date, lv_to_date, plantid);
      commit;
      lv_date_iterator := lv_date_iterator + 7;
    end loop;
  exception
    when others then
      begin
        rollback;
        abslogwrite.abslogprocessjobline_write(gvnabslogprocessjobpartid, 3, substr(sqlerrm, 1, 200), FpSystemUser_ID);
      end;
  end;

end pack_exportgrowth;
/
create or replace package pack_fillweightdeliveryhist is
  pragma serially_reusable;
  -- Author  : LCO
  -- Version : 1.01
  -- Created : 23-11-2015
  -- Purpose : Fill the WeightBasedDeliveryHistory table
  -- Updated : 07-11-2016 description not found give error with no good log

  procedure fillweightbaseddeliveryhistory(fp_plantid            plant.plant_id%type,
                                           fp_plantprocessid     plantprocess.plantprocess_id%type,
                                           fp_abslogprocessjobid in out abslogprocessjob.abslogprocessjob_id%type,
                                           fp_systemuserid       systemuser.systemuser_id%type default 0);

end pack_fillweightdeliveryhist;

/
create or replace package body pack_fillweightdeliveryhist is
  pragma serially_reusable;
  -- Private variable declarations
  gv_userexception exception;
  gv_systemuserid           systemuser.systemuser_id%type := 0;
  gv_abslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
  gv_message                abslog.message%type;
  gv_linesokprocessed       number;
  gv_linesnokprocessed      number;
  gv_languageid             systemuser.language_id%type;
  -- Private constant declarations
  return_ok             constant integer := 0;
  return_failed_unknown constant integer := -1;
  gv_returnvalue number := return_ok;
  -- Private constant declarations
  priority_message constant abslogprocessjobline.priority%type := 1;
  priority_error   constant abslogprocessjobline.priority%type := 3;

  procedure write_log_line(fp_message              in abslogprocessjobline.message%type,
                           fp_customernumber       in customer.customernumber%type default null,
                           fp_notenumber           in packingnote.notenumber%type default null,
                           fp_deldate              in packingnote.deliverydate%type default null,
                           fp_weighingcategorydesc in weighingcategory_desc.description%type default null,
                           fp_weight               in referenceweighing.weight%type default null) is
    lv_message varchar2(1000) := fp_message;
  begin
    if (fp_customernumber is not null) then
      lv_message := rpad(fp_customernumber, 10) || rpad(fp_notenumber, 10) ||
                    rpad(nvl(to_char(fp_deldate, 'dd-mm-yyyy'), ' '), 12) ||
                    rpad(nvl(to_char(fp_weighingcategorydesc), ' '), 12) ||
                    rpad(nvl(to_char(fp_weight), ' '), 15) || fp_message;
    else
      lv_message := fp_message;
    end if;
    abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_error, lv_message,
                                           gv_systemuserid);
  exception
    when others then
      begin
        dbms_output.put_line(fp_message);
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := return_failed_unknown;
        raise gv_userexception;
      end;
  end write_log_line;

  function get_weighingcatdesc(fp_weighingcategoryid in weighingcategory_desc.weighingcategory_id%type)
    return varchar2 is
    lv_weighingcategorydesc weighingcategory_desc.description%type;
  begin
    --get description weighingcategory id fp_weighingcategoryid
    gv_message := 'get description weighingcategory id ' || fp_weighingcategoryid;
    select wcd.description
    into   lv_weighingcategorydesc
    from   weighingcategory_desc wcd
    where  wcd.weighingcategory_id = fp_weighingcategoryid
    and    wcd.language_id = gv_languageid;
    return lv_weighingcategorydesc;
  exception
    when no_data_found then
      begin
        select nvl(max(wcd.description), '-')
        into   lv_weighingcategorydesc
        from   weighingcategory_desc wcd
        where  wcd.weighingcategory_id = fp_weighingcategoryid;
        return lv_weighingcategorydesc;
      end;
  end get_weighingcatdesc;

  procedure fillweightbaseddeliveryhistory(fp_plantid            plant.plant_id%type,
                                           fp_plantprocessid     plantprocess.plantprocess_id%type,
                                           fp_abslogprocessjobid in out abslogprocessjob.abslogprocessjob_id%type,
                                           fp_systemuserid       systemuser.systemuser_id%type default 0) is
    lv_referenceweighing_id     number;
    lv_referenceweight          number;
    lv_quantity                 number;
    lv_weightbaseddelhistoryrec weightbaseddelhistory%rowtype;
    v_weighingcategorydesc      varchar2(100);
    weightbaseddelhistoryid     weightbaseddelhistory.weightbaseddelhistory_id%type;
  
    procedure initialize is
    
      procedure write_log_header is
        lv_message varchar2(1000);
      begin
        --write_log_header
        gv_message := 'Fill Weight Based Delivery History process - log header';
        lv_message := rpad('Process:', 13) || 'Fill Weight Based Delivery History';
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('Start Time:', 13) || to_char(sysdate, 'dd-mm-yyyy hh:mi:ss');
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('Not processed notes, no reference weight defined: ', 51);
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('Customer', 13) || rpad('Note number', 16) || rpad('Del. date', 14) ||
                      rpad('Weighing category', 20) || rpad('Weight(Kg)', 15);
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('-', 150, '-');
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      end write_log_header;
    begin
      --initialize
      gv_message := 'initialize';
      --START
      gv_linesokprocessed  := 0;
      gv_linesnokprocessed := 0;
      --
      if fp_systemuserid is null then
        gv_systemuserid := 0;
      else
        gv_systemuserid := fp_systemuserid;
      end if;
      --check/get plant
      if fp_plantid is null then
        begin
          gv_message := 'parameter fp_plantid cannot be left blank!';
        end;
      else
        begin
          gv_message := 'fp_plantid ' || fp_plantid;
          select pt.language_id into gv_languageid from plant pt where pt.plant_id = fp_plantid;
        end;
      end if;
      --get abslog process job id
      if (fp_abslogprocessjobid is null) then
        begin
          fp_abslogprocessjobid := abslogwrite.abslogprocessjob_write(fp_plantid, sysdate, null,
                                                                      null, fp_plantprocessid,
                                                                      gv_systemuserid);
        end;
      end if;
      --write_log part
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(fp_abslogprocessjobid,
                                                                          'pack_fillWeightDeliveryHist.fillWeightBasedDeliveryHistory',
                                                                          gv_systemuserid);
      -- report header:
      write_log_header;
    end initialize;
  
    procedure finalize is
    
      procedure write_log_footer is
        lv_message varchar2(1000);
      begin
        --write_log_footer
        gv_message := 'Fill Weight Based Delivery History process - log footer';
        lv_message := rpad('-', 150, '-');
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('Number of lines succesfully processed:', 40) ||
                      rpad(gv_linesokprocessed, 6);
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('Number of lines not processed (missing reference weight):', 58) ||
                      rpad(gv_linesnokprocessed, 6);
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('Total number of lines:', 24) ||
                      rpad(gv_linesokprocessed + gv_linesnokprocessed, 6);
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      
        lv_message := rpad('End time:', 11) || to_char(sysdate, 'dd-mm-yyyy hh:mi:ss');
        abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, priority_message,
                                               lv_message, gv_systemuserid);
      end write_log_footer;
    begin
      --finalize
      commit;
      -- report footer:
      write_log_footer;
    end finalize;
  begin
    --initialize
    initialize;
    ---loop packingnotecontainer
    for pncdata in (select d.customer_id, pnc.weighingcategory_id, pn.deliverydate,
                           bu.businessunit_id, pnc.grossweight, pnc.tareweight, pn.notenumber,
                           c.customernumber, pnc.packingnotecontainer_id, pn.distributionpoint_id
                    from   packingnotecontainer pnc, packingnote pn, businessunit bu,
                           distributionpoint dp, department d, customer c
                    where  pn.packingnote_id = pnc.packingnote_id
                    and    bu.businessunit_id = pn.processbusinessunit_id
                    and    pn.distributionpoint_id = dp.distributionpoint_id
                    and    dp.department_id = d.department_id
                    and    d.customer_id = c.customer_id
                    and    pnc.weightbaseddelhistory_id is null
                    and    pnc.referenceweighing = 'Y'
                    and    pn.status_id = (select s.status_id
                                           from   status s
                                           where  s.statustype = 'PN'
                                           and    s.code = 30)
                    and    bu.plant_id = fp_plantid) loop
      begin
        lv_referenceweighing_id := 0;
        lv_referenceweight      := 0;
        begin
          select nvl(rw.referenceweighing_id, 0), nvl(rw.weight, 0)
          into   lv_referenceweighing_id, lv_referenceweight
          from   referenceweighing rw
          where  rw.customer_id = pncdata.customer_id
          and    rw.weighingcategory_id = pncdata.weighingcategory_id
          and    rw.weighingdate =
                 (select max(rw2.weighingdate)
                   from   referenceweighing rw2
                   where  rw2.customer_id = pncdata.customer_id
                   and    rw2.weighingcategory_id = pncdata.weighingcategory_id
                   and    rw2.weighingdate <= pncdata.deliverydate);
        exception
          when no_data_found then
            lv_referenceweighing_id := 0;
            lv_referenceweight      := 0;
        end;
      
        if lv_referenceweighing_id = 0 then
          begin
            v_weighingcategorydesc := get_weighingcatdesc(pncdata.weighingcategory_id);
            gv_linesnokprocessed   := gv_linesnokprocessed + 1;
            write_log_line('No record in ReferenceWeighing table', pncdata.customernumber,
                           pncdata.notenumber, pncdata.deliverydate, v_weighingcategorydesc,
                           (pncdata.grossweight - pncdata.tareweight));
          end;
        else
          begin
            lv_quantity := 0;
            for x in (select rwd.product_link_id, rwd.sizedefinition_link_id, rwd.finishingmethod_id,
                             rwd.quantity
                      from   referenceweighingdetails rwd
                      where  rwd.referenceweighing_id = lv_referenceweighing_id) loop
              lv_quantity := round((((pncdata.grossweight - pncdata.tareweight) /
                                   lv_referenceweight) * x.quantity), 1);
              --create/update weightbaseddelhistory
              begin
                gv_message := 'create/update weightbaseddelhistory for packingnotecontainer id ' ||
                              pncdata.packingnotecontainer_id;
                select seq_weightbaseddelhistory.nextval into weightbaseddelhistoryid from dual;
                lv_weightbaseddelhistoryrec.weightbaseddelhistory_id  := weightbaseddelhistoryid;
                lv_weightbaseddelhistoryrec.customer_link_id          := pncdata.customer_id;
                lv_weightbaseddelhistoryrec.distributionpoint_link_id := pncdata.distributionpoint_id;
                lv_weightbaseddelhistoryrec.businessunit_id           := pncdata.businessunit_id;
                lv_weightbaseddelhistoryrec.product_link_id           := x.product_link_id;
                lv_weightbaseddelhistoryrec.sizedefinition_link_id    := x.sizedefinition_link_id;
                lv_weightbaseddelhistoryrec.finishingmethod_id        := x.finishingmethod_id;
                lv_weightbaseddelhistoryrec.deliverydate              := pncdata.deliverydate;
                lv_weightbaseddelhistoryrec.quantitydelivered         := lv_quantity;
                lv_weightbaseddelhistoryrec.referenceweighing_id      := lv_referenceweighing_id;
                lv_weightbaseddelhistoryrec.systemuser_id             := gv_systemuserid;
                lv_weightbaseddelhistoryrec.timestamp                 := sysdate;
              
                begin
                  insert into weightbaseddelhistory values lv_weightbaseddelhistoryrec;
                exception
                  when dup_val_on_index then
                    update weightbaseddelhistory wbdh
                    set    wbdh.quantitydelivered = wbdh.quantitydelivered + lv_quantity,
                           wbdh.systemuser_id = gv_systemuserid, wbdh.timestamp = sysdate
                    where  wbdh.customer_link_id = pncdata.customer_id
                    and    wbdh.distributionpoint_link_id = pncdata.distributionpoint_id
                    and    wbdh.businessunit_id = pncdata.businessunit_id
                    and    wbdh.product_link_id = x.product_link_id
                    and    wbdh.sizedefinition_link_id = x.sizedefinition_link_id
                    and    wbdh.finishingmethod_id = x.finishingmethod_id
                    and    wbdh.deliverydate = pncdata.deliverydate
                    returning wbdh.weightbaseddelhistory_id into weightbaseddelhistoryid;
                end;
              
                begin
                  gv_message := 'update packingnotecontainer id ' ||
                                pncdata.packingnotecontainer_id || ' with weightbaseddelhistory';
                  update packingnotecontainer pnc
                  set    pnc.weightbaseddelhistory_id = weightbaseddelhistoryid,
                         pnc.systemuser_id = gv_systemuserid, pnc.timestamp = sysdate
                  where  pnc.packingnotecontainer_id = pncdata.packingnotecontainer_id;
                end;
                gv_linesokprocessed := gv_linesokprocessed + 1;
              end;
            end loop;
          end;
        end if;
      end;
    end loop;
    ---loop weighingticket
    for wtldata in (select c.customer_id, wtl.weighingcategory_id, wt.weighingdate,
                           bu.businessunit_id, wtl.grossweight, wtl.tareweight, wt.ticketnumber,
                           c.customernumber, wtl.weighingticketline_id,
                           (select min(dp.distributionpoint_id)
                             from   distributionpoint dp
                             where  dp.department_id = wtl.department_id) distributionpoint
                    from   weighingticketline wtl, weighingticket wt, businessunit bu, customer c
                    where  wtl.weighingticket_id = wt.weighingticket_id
                    and    bu.businessunit_id = wt.processbusinessunit_id
                    and    wt.customer_id = c.customer_id
                    and    wtl.weightbaseddelhistory_id is null
                    and    wtl.referenceweighing = 'Y'
                    and    wt.status_id = (select s.status_id
                                           from   status s
                                           where  s.statustype = 'WN'
                                           and    s.code = 30)
                    and    bu.plant_id = fp_plantid) loop
      begin
        lv_referenceweighing_id := 0;
        lv_referenceweight      := 0;
        begin
          select nvl(rw.referenceweighing_id, 0), nvl(rw.weight, 0)
          into   lv_referenceweighing_id, lv_referenceweight
          from   referenceweighing rw
          where  rw.customer_id = wtldata.customer_id
          and    rw.weighingcategory_id = wtldata.weighingcategory_id
          and    rw.weighingdate =
                 (select max(rw2.weighingdate)
                   from   referenceweighing rw2
                   where  rw2.customer_id = wtldata.customer_id
                   and    rw2.weighingcategory_id = wtldata.weighingcategory_id
                   and    rw2.weighingdate <= wtldata.weighingdate);
        exception
          when no_data_found then
            lv_referenceweighing_id := 0;
            lv_referenceweight      := 0;
        end;
      
        if lv_referenceweighing_id = 0 then
          begin
            v_weighingcategorydesc := get_weighingcatdesc(wtldata.weighingcategory_id);
            gv_linesnokprocessed   := gv_linesnokprocessed + 1;
            write_log_line('No record in ReferenceWeighing table', wtldata.customernumber,
                           wtldata.ticketnumber, wtldata.weighingdate, v_weighingcategorydesc,
                           (wtldata.grossweight - wtldata.tareweight));
          end;
        else
          begin
            lv_quantity := 0;
            for x in (select rwd.product_link_id, rwd.sizedefinition_link_id, rwd.finishingmethod_id,
                             rwd.quantity
                      from   referenceweighingdetails rwd
                      where  rwd.referenceweighing_id = lv_referenceweighing_id) loop
              lv_quantity := round((((wtldata.grossweight - wtldata.tareweight) /
                                   lv_referenceweight) * x.quantity), 1);
              --create/update weightbaseddelhistory
              begin
                gv_message := 'create/update weightbaseddelhistory for weighingticketline_id ' ||
                              wtldata.weighingticketline_id;
                select seq_weightbaseddelhistory.nextval into weightbaseddelhistoryid from dual;
                lv_weightbaseddelhistoryrec.weightbaseddelhistory_id  := weightbaseddelhistoryid;
                lv_weightbaseddelhistoryrec.customer_link_id          := wtldata.customer_id;
                lv_weightbaseddelhistoryrec.distributionpoint_link_id := wtldata.distributionpoint;
                lv_weightbaseddelhistoryrec.businessunit_id           := wtldata.businessunit_id;
                lv_weightbaseddelhistoryrec.product_link_id           := x.product_link_id;
                lv_weightbaseddelhistoryrec.sizedefinition_link_id    := x.sizedefinition_link_id;
                lv_weightbaseddelhistoryrec.finishingmethod_id        := x.finishingmethod_id;
                lv_weightbaseddelhistoryrec.deliverydate              := wtldata.weighingdate;
                lv_weightbaseddelhistoryrec.quantitydelivered         := lv_quantity;
                lv_weightbaseddelhistoryrec.referenceweighing_id      := lv_referenceweighing_id;
                lv_weightbaseddelhistoryrec.systemuser_id             := gv_systemuserid;
                lv_weightbaseddelhistoryrec.timestamp                 := sysdate;
                begin
                  insert into weightbaseddelhistory values lv_weightbaseddelhistoryrec;
                exception
                  when dup_val_on_index then
                    begin
                      update weightbaseddelhistory wbdh
                      set    wbdh.quantitydelivered = wbdh.quantitydelivered + lv_quantity,
                             wbdh.systemuser_id = gv_systemuserid, wbdh.timestamp = sysdate
                      where  wbdh.customer_link_id = wtldata.customer_id
                      and    wbdh.distributionpoint_link_id = wtldata.distributionpoint
                      and    wbdh.businessunit_id = wtldata.businessunit_id
                      and    wbdh.product_link_id = x.product_link_id
                      and    wbdh.sizedefinition_link_id = x.sizedefinition_link_id
                      and    wbdh.finishingmethod_id = x.finishingmethod_id
                      and    wbdh.deliverydate = wtldata.weighingdate
                      returning wbdh.weightbaseddelhistory_id into weightbaseddelhistoryid;
                    end;
                end;
                gv_message := 'update weighingticketline id ' || wtldata.weighingticketline_id ||
                              ' with weightbaseddelhistory';
                update weighingticketline wtl
                set    wtl.weightbaseddelhistory_id = weightbaseddelhistoryid,
                       wtl.systemuser_id = gv_systemuserid, wtl.timestamp = sysdate
                where  wtl.weighingticketline_id = wtldata.weighingticketline_id;
                gv_linesokprocessed := gv_linesokprocessed + 1;
              end;
            end loop;
          end;
        end if;
      end;
    end loop;
    --finalize
    finalize;
  exception
    when no_data_found then
      begin
        rollback;
        gv_message := 'No data found ' || gv_message;
        raise;
      end;
    when others then
      begin
        rollback;
        write_log_line(gv_message || sqlerrm);
        raise;
      end;
  end;
end pack_fillweightdeliveryhist;

/
create or replace package "PACK_GLEXPORT" is

  -- Author  : CRISTINAM
  -- Created : 07/05/2008 12:02:18
  -- Updated : HVH 16/06/2009 for order 502666 National Account Cash Appl.
  --           For charge invoice and statement transactions populate plant
  --           in segment1 with plant of default BU of pay by or bill to
  --           They can be in different plants than the invoice was made e.g. corporate plant.
  -- Update  : HVH 25/10/2011 for Order 20011960 change AR Transaction Detail link to GLEXPORT
  -- Public functions and procedures declarations
  procedure exporttogl(fp_debugmode in varchar2 default 'N', statusout out number);
end pack_glexport;





/
create or replace PACKAGE BODY "PACK_GLEXPORT" is
  StatusOut        number;
  nri              integer;
  nru              integer;
  gv_systemuserid  systemuser.systemuser_id%type;
  gv_debugmode     varchar2(1);
  --502904
  gv_laundrycode databasesettings.code%type;
  gv_segment5 varchar2(25) default '000000';
  gv_segment6 varchar2(25) default '000000';
  --

  procedure write_log(fp_err_msg   in varchar2,
                      fp_priority  in number default 1) is
  begin
    /* writes logs into database.
    priority
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info  */
    if fp_priority<>5 or (fp_priority=5 and gv_debugmode = 'Y') then
      abslogwrite.abslog_write(5, 'GL Export', null, fp_priority, fp_err_msg,
                               gv_systemuserid);
    end if;
  end write_log;

  ----------------------------------------------------------------------
  procedure GetValuesToInsert(plantid             in plant.plant_id%type,
                              turnovergroupid     in turnovergroup.turnovergroup_id%type,
                              depotid             in depot.depot_id%type,
                              ardate              in artransaction.artransactiondate%type,
                              artransactiontypeid in artransactiontype.artransactiontype_id%type,
                              chargec             in varchar2,
                              cursortype          in varchar2,
                              setofbooks          out country.journalcode%type,
                              plantcode           out plant.code%type,
                              companycode         out systemsetting.value%type,
                              description         out varchar2,
                              segment2            out varchar2,
                              segment3            out varchar2,
                              StatusOut           out number) is
    countrycode country.code%type;
  begin
    description := null;
    segment2    := null;
    segment3    := null;
    setofbooks  := null;
    plantcode   := null;
    companycode := null;
    StatusOut   := 0;
    ----setofbooks_id
    select c.journalcode, c.code
      into setofbooks, countrycode
      from country c, plant p
     where c.country_id = p.country_id
       and p.plant_id = plantid;
    -----segment 1
    select p.code into plantcode from plant p where p.plant_id = plantid;
    -----segment 4 (companycode)
    select s.value
      into companycode
      from systemsetting s
     where s.name = 'COMPANYCODE'
       and s.plant_id = plantid;
    -----segment 3
    if cursortype = 'A' then
      begin
        select de.code
          into segment3
          from depot de
         where de.depot_id = depotid;
      exception
        when no_data_found then
          segment3 := '1000';
      end;
    else
      segment3 := '1000';
    end if;
    --502904
    if gv_laundrycode = 'NIW' then
      case when cursortype = 'A' then
                gv_segment6 := '1';
           when cursortype = 'B' then
                gv_segment6 := '2';
           else gv_segment6 := '3';
       end case;
    end if;
    -----segment 2 and description
    if chargec <> 'N' then
      description := 'CHARGE CUSTOMERS';
      segment2    := chargec;
    else
      -- find code for segment 2 and description
      if turnovergroupid != 0 then
        -- find turnovergroupcode&description
        select tg.code
          into segment2
          from turnovergroup tg
         where tg.turnovergroup_id = turnovergroupid;
        select td.description
          into description
          from turnovergroup_desc td
         where td.turnovergroup_id = turnovergroupid
           and td.language_id =
               (select l.language_id from languages l where l.code = 'EN_US');
      else
        -- find artranslegacycode&description
        select art.legacycode
          into segment2
          from artransactiontype art
         where art.artransactiontype_id = artransactiontypeid;
        select artd.description
          into description
          from artransactiontype      art,
               artransactiontype_desc artd,
               languages              l
         where art.artransactiontype_id = artd.artransactiontype_id
           and art.artransactiontype_id = artransactiontypeid
           and artd.language_id = l.language_id
           and l.code = 'EN_US';
        -- Overrule 'Invoice' and 'Statement' with CHARGE CUSTOMER
        if cursortype = 'A' then
          description := 'CHARGE CUSTOMERS';
        end if;
      end if; --turnovergroupid != 0
    end if; --chargec <> 'N'
    description := 'ABS ' || description || ' ' ||
                   to_char(ardate, 'MM/DD/YY');
  exception
    when no_data_found then
      StatusOut := -1;
      write_log('Country journal code must be numeric for country ' ||
                        countrycode || ' and plant_id ' || plantid,3);
    when others then
      StatusOut := -5;
      write_log('Others in GetValuesToInsert ' || sqlerrm,3);
  end;
  ----------------------------------------------------------------------
  procedure UpdateArTransaction(artransactionid in artransaction.artransaction_id%type,
                                plantid         in plant.plant_id%type,
                                glexportid      in glexport.glexport_id%type)

   is
  begin
    update artransaction ar1
       set ar1.glexport_id = glexportid , ar1.exportstatus = 1
     where ar1.artransaction_id = artransactionID;
  exception
    when others then
      write_log('Update failed for artransaction ' ||
                        artransactionid || ' with plant_id ' || plantid ||
                        sqlerrm,3);
     StatusOut := -6;
  end;
  ----------------------------------------------------------------------
  procedure CheckDefinitions(StatusOut out number) is
    aux varchar2(4000);
    cursor vv is
      select art.debitcredit,
             art.typenumber,
             artd.description,
             art.legacycode
        from artransactiontype      art,
             artransactiontype_desc artd,
             languages              l
       where art.artransactiontype_id = artd.artransactiontype_id
         and l.language_id = artd.language_id
         and art.legacycode is null
         and l.code = 'EN_US'
         and ((art.debitcredit = 'D' and art.typenumber <> 2) or
             (art.debitcredit = 'C' and art.typenumber not in (1, 2, 3)));
  begin
    aux := '';
    for v in vv loop
      aux := 'GL Account not defined in legacycode for AR Transaction type ' ||
             v.debitcredit || v.typenumber || ' ' || v.description || ' ' ||
             v.legacycode;
      write_log(aux,3);
    end loop;
    if aux is not null then
      StatusOut := -2;
    else
      StatusOut := 0;
    end if;
  EXCEPTION
    when others then
      StatusOut := -4;
      write_log('Others ' || sqlerrm,3);
  end checkdefinitions;
  ----------------------------------------------------------------------
  procedure InsertGLExport(xplant_id             in plant.plant_id%type,
                           xturnovergroup_id     in turnovergroup.turnovergroup_id%type,
                           xdepot_id             in depot.depot_id%type,
                           xardate               in artransaction.artransactiondate%type,
                           xartransactiontype_id in artransactiontype.artransactiontype_id%type,
                           xamount_dr            in number,
                           xamount_cr            in number,
                           chargec               in varchar2,
                           cursortype            in varchar2,
                           glexportid            out glexport.glexport_id%type) is

    gid number;
    --variables for insert
    gldesc      varchar(200);
    setofbooks  country.journalcode%type;
    pcode       plant.code%type;
    companycode systemsetting.value%type;
    segment2v   varchar2(25);
    segment3v   varchar2(25);
  begin
    getvaluestoinsert(xplant_id,
                      xturnovergroup_id,
                      xdepot_id,
                      xardate,
                      xartransactiontype_id,
                      chargec,
                      cursortype,
                      setofbooks,
                      pcode,
                      companycode,
                      gldesc,
                      segment2v,
                      segment3v,
                      StatusOut);
    --
    begin
      insert into glexport
        (glexport_id,
         set_of_books_id,
         accounting_date,
         date_created,
         segment1,
         segment2,
         segment3,
         segment4,
         segment5,
         segment6,
         amount_dr,
         amount_cr,
         description,
         importdate,
         systemuser_id,
         timestamp)
      values
        (seq_glexport.nextval,
         setofbooks,
         xardate,
         trunc(sysdate),
         pcode,
         segment2v,
         segment3v,
         companycode,
         gv_segment5,
         gv_segment6,
         xamount_dr,
         xamount_cr,
         gldesc,
         null,
         0,
         sysdate);
      nri := nri + 1; --a new record is inserted and counted
      select seq_glexport.currval into glexportid from dual;
    exception
      when dup_val_on_index then
        begin
          select gl.glexport_id
            into glexportid
            from glexport gl
           where gl.set_of_books_id = setofbooks
             and gl.accounting_date = xardate
             and gl.segment1 = pcode
             and gl.segment2 = segment2v
             and gl.segment3 = segment3v
             and gl.segment4 = companycode
             and gl.segment5 = gv_segment5
             and gl.segment6 = gv_segment6
             and gl.importdate is null;
          update glexport gl
             set gl.amount_dr     = gl.amount_dr + xamount_dr,
                 gl.amount_cr     = gl.amount_cr + xamount_cr,
                 gl.systemuser_id = 0,
                 gl.timestamp     = sysdate
           where gl.glexport_id = glexportid;
          nru := nru + 1; --a record is updated and counted
        end;
    end;
  exception
    when others then
      select max(glexp.glexport_id) + 1 into gid from glexport glexp;
      write_log('Insert failed for cursor ' || cursortype ||
                        ' for plantcode ' || pcode || ',segment ' ||
                        segment2v || ' and depot ' || segment3v ||
                        ' and glexport_id ' || gid || ' ' || sqlerrm,3);
      StatusOut := -3;
  end InsertGLexport;
  ----------------------------------------------------------------------
  procedure InsertGLUpdateAR(ardebitcredit in artransactiontype.debitcredit%type,
                             artypenumber  in artransactiontype.typenumber%type,
                             arpredefined  in artransactiontype.predefined%type,
                             CHARGEC       in artransactiontype.legacycode%type,
                             cursortype    in varchar2) is

    prevardate              artransaction.artransactiondate%type;
    prevplantid             plant.plant_id%type;
    prevdepotid             depot.depot_id%type;
    prevartransactiontypeid artransactiontype.artransactiontype_id%type;
    glexportid              glexport.glexport_id%type;
    returned_glexportid     glexport.glexport_id%type;
    vAmount                 number;
    firstiteration          varchar(1);
    original_depot          depot.depot_id%type;
    lvprev_bucode           businessunit.code%type;
  begin
    prevardate              := null;
    prevplantid             := null;
    prevdepotid             := null;
    prevartransactiontypeid := null;
    firstiteration          := 'Y';
    lvprev_bucode           := null;
    vAmount                 := 0;
    For x in (select ar.artransaction_id,
                     ar.amount s,
                     trunc(ar.artransactiondate) ardate,
/* Start change 16/6/2009/HVH order 502666 */
/*                     bu.plant_id,  */
                     bu.plant_id,
/* 21/02/2012 swh - revert to original code. Invoices with bill-to or pay-by relationships in different business units
   cause GL imbalances.
                     case when art.debitcredit = 'D'
                           and art.typenumber in (1,3)  -- invoice or statement
                           and ar.invoiceheader_id is not null
                       then
                        case  when (nvl((select realcollectiontype
                               from invoiceheader h
                              where h.invoiceheader_id = ar.invoiceheader_id
                                and h.documenttype=1),2)) = 2 -- charge invoices or statements
                        then
                        nvl((select b.plant_id
                              from businessunit b, customer c
                             where b.businessunit_id = c.defaultbusinessunit_id
                               and c.customer_id = -- pay by, else bill to
                                   nvl((select he.paybycustomer_link_id
                                         from invoiceheaderextrainfo he
                                        where he.invoiceheader_id = ar.invoiceheader_id),
                                       (select h.billtocustomer_link_id
                                          from invoiceheader h
                                         where h.invoiceheader_id = ar.invoiceheader_id))),
                            bu.plant_id)
                       else
                        bu.plant_id
                     end -- case realcollectiontype
                     else bu.plant_id
                     end plant_id,
*/
                     bu.plant_id transaction_plant_id,  -- store also original plant in cursor
/* End change 16/6/2009/HVH */
                     r.depot_id,
                     ar.artransactiontype_id, bu.code businessunitcode
                from artransactiontype art, artransaction ar
                left outer join route r on ar.route_id = r.route_id,
               businessunit bu
               where ar.artransactiontype_id = art.artransactiontype_id
                 and ar.businessunit_id = bu.businessunit_id
/* Start change 19/2/2009/HVH todo 8532 */
--                 and (art.debitcredit = ardebitcredit and
--                     (art.typenumber = artypenumber or
--                     art.predefined = arpredefined))
                 and art.debitcredit = ardebitcredit
                 and (art.typenumber = artypenumber or arpredefined='N')
                 and art.predefined = arpredefined
/* End change 19/2/2009/HVH */
                 and ar.glexport_id = -1
               order by ar.artransactiondate,
                        bu.plant_id,
                        r.depot_id,
                        ar.artransactiontype_id,
                        bu.code) Loop
      --502904
      if gv_laundrycode = 'NIW'
        then gv_segment5 := x.businessunitcode;
        else lvprev_bucode := x.businessunitcode; --never switch on BU when not NIW
      end if;
      --
/* Start change 16/6/2009/HVH order 502666 */
-- make depot null when the plant is not the original plant, but temporary store it for creating GL on artransdetails
      original_depot := x.depot_id;
      if x.plant_id <> x.transaction_plant_id
       then x.depot_id:=null;
      end if;
/* End change 16/6/2009/HVH */
      -- Initialize part:
      if firstiteration = 'Y' then
        insertglexport(x.plant_id,
                       0,
                       x.depot_id,
                       x.ardate,
                       x.artransactiontype_id,
                       0,
                       0,
                       'N',
                       cursortype,
                       glexportid);
      end if;
      -- Finalize part:
      if (x.ardate <> prevardate or x.plant_id <> prevplantid or
         x.depot_id <> prevdepotid or
         x.artransactiontype_id <> prevartransactiontypeid or
         x.businessunitcode <> lvprev_bucode) and
         (firstiteration = 'N') --not first iteration
       then
        if cursortype = 'A' then
          update glexport gl
             set gl.amount_dr = gl.amount_dr + vAmount
           where gl.glexport_id = glexportid;
        else
          --transaction C or D
          if ardebitcredit = 'D' then
            --if D then amount_cr = vamount, might look wrong, but is not
            update glexport gl
               set gl.amount_cr = gl.amount_cr + vAmount
             where gl.glexport_id = glexportid;
          else
            --if C then amount_dr = vamount, might look wrong, but is not
            update glexport gl
               set gl.amount_dr = gl.amount_dr + vAmount
             where gl.glexport_id = glexportid;
          end if;
          -- Create balancing transaction:
          if ardebitcredit = 'C' then
            insertglexport(prevplantid,
                           0,
                           prevdepotid,
                           prevardate,
                           prevartransactiontypeid,
                           0, --debit
                           vAmount, --credit
                           CHARGEC, --Charge Customer
                           cursortype,
                           glexportid);
          else
            insertglexport(prevplantid,
                           0,
                           prevdepotid,
                           prevardate,
                           prevartransactiontypeid,
                           vAmount, --debit
                           0, --credit
                           CHARGEC, --Charge Customer
                           cursortype,
                           glexportid);
          end if; -- if ardebitcredit=C
        end if; -- if cursor type
        -- insert new record
        insertglexport(x.plant_id,
                       0,
                       x.depot_id,
                       x.ardate,
                       x.artransactiontype_id,
                       0,
                       0,
                       'N', --Charge Customer
                       cursortype,
                       glexportid);
        vAmount := 0; -- initialize vAmount
      end if; -- something changed and not first iteration
      --- FOR EVERY RECORD IN CURSOR ---
      -- Add up amount and update AR transaction
      vAmount := vAmount + x.s;
      updateartransaction(x.artransaction_id,
                          x.plant_id,
                          glexportid);
      if cursortype = 'A' then
        --select all artransactions with artransactiondetail
        For y in (select ard.amount s, ard.turnovergroup_id, ard.artransaction_id, ard.businessunit_id
                    from artransactiondetail ard, artransaction ar
                   where ar.artransaction_id = ard.artransaction_id
                     and ar.artransaction_id = x.artransaction_id) loop
          insertglexport(x.transaction_plant_id, -- x.plant_id, HVH 16/6/09 always use original plant for revenue
                         y.turnovergroup_id,
                         original_depot, -- x.depot_id, HVH 16/6/09 always use original depot for revenue
                         x.ardate,
                         0, --x.artransactiontype_id,
                         0, --debit
                         y.s, --credit
                         'N', --Charge Customer
                         cursortype,
                         returned_glexportid);
           -- HVH change for Order 20011960 AR Transaction Detail link to GLEXPORT
           update artransactiondetail a
             set a.glexport_id = returned_glexportid
           where a.artransaction_id = y.artransaction_id
             and a.turnovergroup_id = y.turnovergroup_id
             and a.businessunit_id = y.businessunit_id;
           -- End Change order 20011960
        end loop;
      end if;
      prevardate              := x.ardate;
      prevplantid             := x.plant_id;
      prevdepotid             := x.depot_id;
      prevartransactiontypeid := x.artransactiontype_id;
      lvprev_bucode           := x.businessunitcode;
      firstiteration          := 'N';
    end loop;
    -- store totals for last record(s):
    if firstiteration = 'N' then
      -- only save if at least one record in the loop
      if cursortype = 'A' then
        update glexport gl
           set gl.amount_dr = gl.amount_dr + vAmount
         where gl.glexport_id = glexportid;
      else
        --transaction C or D
        if ardebitcredit = 'D' then
          --if D then amount_cr = vamount, might look wrong, but is not
          update glexport gl
             set gl.amount_cr = gl.amount_cr + vAmount
           where gl.glexport_id = glexportid;
        else
          --if C then amount_dr = vamount, might look wrong, but is not
          update glexport gl
             set gl.amount_dr = gl.amount_dr + vAmount
           where gl.glexport_id = glexportid;
        end if;
        -- Create balancing transaction:
        if ardebitcredit = 'C' then
          insertglexport(prevplantid,
                         0,
                         prevdepotid,
                         prevardate,
                         prevartransactiontypeid,
                         0, --debit
                         vAmount, --credit
                         CHARGEC, --Charge Customer
                         cursortype,
                         glexportid);
        else
          insertglexport(prevplantid,
                         0,
                         prevdepotid,
                         prevardate,
                         prevartransactiontypeid,
                         vAmount, --debit
                         0, --credit
                         CHARGEC, --Charge Customer
                         cursortype,
                         glexportid);
        end if;
      end if;
    end if; --firstiteration = 'N'
  end InsertGLUpdateAR;
  ----------------------------------------------------------------------
  procedure ExportToGL(fp_debugmode in varchar2 default 'N', StatusOut out number) is
    CHARGECUST      artransactiontype.legacycode%type;
    glexpID         integer;
    CURSOR G IS
      select gl.glexport_id, gl.amount_dr, gl.amount_cr from glexport gl;
  BEGIN
    --------------initialization of CASHINBANK and CHARGECUST and Check definitions in ARTransactiontype table
    StatusOut := 0;
    gv_debugmode := fp_debugmode;
    gv_systemuserid := 0;
    write_log('Process start : ' || to_char(sysdate, 'YYYY/MM/DD HH24:MI:SS'));
    --check if there is a null legacycode
    CheckDefinitions(StatusOut);
    --if there is no legacycode = null then the export can be started
    if StatusOut = 0 then
      begin
        select art.legacycode
          into CHARGECUST
          from artransactiontype      art,
               artransactiontype_desc artd,
               languages              l
         where art.debitcredit = 'D'
           and art.typenumber = 1
           and art.artransactiontype_id = artd.artransactiontype_id
           and l.language_id = artd.language_id
           and l.code = 'EN_US';
        ---STEP 1
        ---Create dummy value if not yet exists.
        begin
          select glexport_id
            into glexpID
            from glexport
           where glexport_id = -1;
        exception
          when no_data_found then
            begin
              insert into glexport
                (glexport_id,
                 set_of_books_id,
                 accounting_date,
                 date_created,
                 segment1,
                 segment2,
                 segment3,
                 segment4,
                 segment5,
                 segment6,
                 amount_dr,
                 amount_cr,
                 description,
                 importdate,
                 systemuser_id,
                 timestamp)
              values
                (-1,
                 -1,
                 to_date('01-01-2000', 'dd-mm-yyyy'),
                 to_date('01-01-2000', 'dd-mm-yyyy'),
                 '000000',
                 '000000',
                 '000000',
                 '000000',
                 gv_segment5,
                 gv_segment6,
                 0,
                 0,
                 'Dummy',
                 to_date('01-01-2000', 'dd-mm-yyyy'),
                 0,
                 sysdate);
            end;
        end;
        -- Link AR transactions to dummy to make them unchangeable and undeletable.
        update artransaction a
           set a.glexport_id = -1
         where a.artransaction_id in
               (select ar.artransaction_id
                  from artransaction ar, artransactiontype art
                 where ar.artransactiontype_id = art.artransactiontype_id
                   and ((art.debitcredit = 'D' and
                       (art.typenumber in (1, 3, 4) or
                       art.predefined = 'N')) or
                       (art.debitcredit = 'C' and
                       (art.typenumber in (4, 5) or art.predefined = 'N')))
                   and ar.glexport_id is null);
        commit;
        ---STEP 2
        nri := 0;
        nru := 0;
        insertglupdatear('D', 1, 'Y', CHARGECUST, 'A');
        insertglupdatear('D', 3, 'Y', CHARGECUST, 'A');
        write_log('Number of records for invoices & statements     : inserted ' || nri ||
                  ' and updated ' || nru);
        nri := 0;
        nru := 0;
        insertglupdatear('C', 5, 'Y', CHARGECUST, 'B');
        write_log('Number of records for payments                  : inserted ' || nri ||
                          ' and updated ' || nru);
        nri := 0;
        nru := 0;
        insertglupdatear('C', 4, 'Y', CHARGECUST, 'C');
        write_log('Number of records for discounts                 : inserted ' || nri ||
                          ' and updated ' || nru);
        nri := 0;
        nru := 0;
        insertglupdatear('D', 4, 'Y', CHARGECUST, 'D');
        write_log('Number of records for discount charges          : inserted ' || nri ||
                          ' and updated ' || nru);
        nri := 0;
        nru := 0;
        insertglupdatear('C', 0, 'N', CHARGECUST, 'E');
        write_log('Number of records for misc. credit transactions : inserted ' || nri ||
                          ' and updated ' || nru);
        nri := 0;
        nru := 0;
        insertglupdatear('D', 0, 'N', CHARGECUST, 'F');
        write_log('Number of records for misc. debit transactions  : inserted ' || nri ||
                          ' and updated ' || nru);
        --------step 7(make all transactions comply to accounting rules)
        For y in G LOOP
          if (y.amount_dr = 0 and y.amount_cr < 0) then
            update glexport gl
               set gl.amount_dr = (-1) * y.amount_cr
             where gl.glexport_id = y.glexport_id;
            update glexport gl
               set gl.amount_cr = 0
             where gl.glexport_id = y.glexport_id;
          else
            if (y.amount_cr = 0 and y.amount_dr < 0) then
              update glexport gl
                 set gl.amount_cr = (-1) * y.amount_dr
               where gl.glexport_id = y.glexport_id;
              update glexport gl
                 set gl.amount_dr = 0
               where gl.glexport_id = y.glexport_id;
            else
              if (y.amount_dr <> 0 and y.amount_cr <> 0) then

                if (y.amount_dr - y.amount_cr > 0) then
                  update glexport gl
                     set gl.amount_dr = (y.amount_dr - y.amount_cr)
                   where gl.glexport_id = y.glexport_id;
                  update glexport gl
                     set gl.amount_cr = 0
                   where gl.glexport_id = y.glexport_id;
                else
                  if (y.amount_dr - y.amount_cr < 0) then
                    update glexport gl
                       set gl.amount_cr = (y.amount_cr - y.amount_dr)
                     where gl.glexport_id = y.glexport_id;
                    update glexport gl
                       set gl.amount_dr = 0
                     where gl.glexport_id = y.glexport_id;
                  end if;
                end if;
              end if;
            end if;
          end if;
        end loop;
        --delete dummy record from glexport table
        delete from glexport gl where gl.glexport_id = -1;
        commit;
      end;
    else
      -- else the process is stopped
      rollback;
    end if;
    write_log('Process end: ' || to_char(sysdate, 'YYYY/MM/DD HH24:MI:SS'));
  EXCEPTION
    when others then
      rollback;
      StatusOut := -7;
      write_log('Others ' || sqlcode || ' ' || sqlerrm,3);
      write_log('Process end with errors: ' ||
                to_char(sysdate, 'YYYY/MM/DD HH24:MI:SS'),3);
  end ExportToGL;
  ---

begin
  --502904
  select max(ds.code) into gv_laundrycode from databasesettings ds;
  --
end PACK_GLEXPORT;
/
create or replace package pack_invoiceAudit_initialLoad is
  -- Author  : ANA-MARIA.ANTONESCU
  -- Created : 03/09/2023 21:07
  -- Purpose : initial load for InvoiceAudit
  -- Version: 2.0
  -- Modified : 14 feb 2024 ABS-161343 Price messaging load script - loss type 9 issue


  procedure loadInvoiceAuditInfoPerPlantForSalesLines(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForReplacementLines(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForRuinChargeResidualValue(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForSpecialSizeLines(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForEmblemLines(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForPrepChargeLines(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForStatementFeeLines(fp_plantCode in varchar2);
  procedure loadInvoiceAuditInfoPerPlantForLossLines(fp_plantCode in varchar2);

  procedure loadInvoiceAuditInfoPerPlantAllLines(fp_plantCode in varchar2);

end pack_invoiceAudit_initialLoad;
/
create or replace package body pack_invoiceAudit_initialLoad is
 gv_linetype_sales number := 5;
 gv_linetype_replacement number := 7;
 gv_linetype_loss number := 9;

 gv_systemuserid abslog.systemuser_id%type := 0;
 gv_sizestarid SIZEDEFINITION.SIZEDEFINITION_ID%type;

 procedure write_log(fpsource varchar2, fpserr_msg varchar2) is
  begin
    /* writes conversion logs into database.
    priority
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info  */
    abslogwrite.abslog_write(5, 'pack_invoiceAudit_initialLoad.' || fpsource, null, 5, fpserr_msg);
 end write_log;


  procedure auditInfoLastEmblemPriceForBU(fp_buId in number) is
    lv_contor number := 0;
    begin
     FOR emblemRec IN(
          select  customer_link_id, emblemtemplateline_id,max(lastInvoiceId) lastInvoiceId, max(lastPrice) lastEmblemPrice
           from
               (select eh.customer_link_id,eh.emblemtemplateline_id,
                  first_value(ih.invoiceheader_id) OVER (PARTITION BY eh.customer_link_id,eh.emblemtemplateline_id ORDER BY eh.customer_link_id,eh.emblemtemplateline_id,ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                  first_value(eh.amount) OVER (PARTITION BY eh.customer_link_id ,eh.emblemtemplateline_id ORDER BY eh.customer_link_id,eh.emblemtemplateline_id,ih.invoicedate desc, ih.invoiceheader_id desc) as lastPrice
                from emblemhistory eh, invoiceheader ih
                where eh.invoiceheader_id=ih.invoiceheader_id
                   and ih.documenttype = 1
                   and ih.status_id in (1,2)
                   and ih.invoicedate > sysdate -365*2
                   and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                   and ih.invoicetype= 1
                   and eh.status=0
                   and ih.invoicebusinessunit_id = fp_buId
                   and eh.emblemtemplateline_id is not null
                   )
           group by customer_link_id, emblemtemplateline_id )
                LOOP
                   merge into  lastemblempriceused
                   using (select  emblemRec.customer_link_id deltocustomer_link_id,
                        emblemRec.emblemtemplateline_id emblemtemplateline_id,
                        emblemRec.lastEmblemPrice lastEmblemPrice,
                        emblemRec.lastInvoiceId lastInvoiceId
                        from dual) mySrc
                   on ( lastemblempriceused.Customer_Link_Id = mySrc.deltocustomer_link_id and
                       lastemblempriceused.Emblemtemplateline_Id = mySrc.emblemtemplateline_id)
                   when not matched  then
                      insert
                       (LASTEMBLEMPRICEUSED_ID,
                        CUSTOMER_LINK_ID,
                        EMBLEMTEMPLATELINE_ID,
                        PRICE,
                        PRICELISTTYPE,
                        INVOICEHEADER_ID,
                        CREATIONINVOICEHEADER_ID,
                        Systemuser_Id,
                        Timestamp
                      ) values (
                        SEQ_lastemblempriceused.NEXTVAL,
                        emblemRec.customer_link_id,
                        emblemRec.emblemtemplateline_id,
                        emblemRec.lastEmblemPrice,
                        1,
                        null,
                        emblemRec.lastInvoiceId,
                        gv_systemuserid ,
                        sysdate
                      );

                      lv_contor := lv_contor + 1;
                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
              write_log('audit end Emblem ' ,'audit end Emblem For BU =' ||  fp_buId);
    exception
       when others then
          write_log('audit EmblemPrice','For BU =' ||  fp_buId ||  substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLastEmblemPriceForBU;

 procedure auditInfoLastProductPriceForBUAndLineTypeNoFinMeth(fp_buId in number, fp_lineType in number) is
    lv_contor number := 0;
    begin
     FOR loadRecord IN (
         with vv_lastInvoice as
              (select deltocustomer_link_id, invoicelinetype_id, invoicelinesubtype, product_link_id,sizedefinition_link_id,max(lastInvoiceId) lastInvoiceId, max(lastInvoiceDate) lastInvoiceDate
               from
                (select ih.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id,
                        first_value(ih.invoiceheader_id) OVER (PARTITION BY ih.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                        first_value(ih.invoicedate)      OVER (PARTITION BY ih.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceDate
                    from INVOICEHEADER IH, INVOICELINE IL, invoicelineproduct ilp
                   where IH.INVOICEHEADER_ID = IL.INVOICEHEADER_ID
                         and ih.invoicebusinessunit_id = fp_buId
                         and ih.invoicedate > sysdate -365*2
                         and ih.documenttype = 1
                         and ih.status_id in (1,2)
                         and ilp.invoiceline_id = il.invoiceline_id
                         and il.invoicelinetype_id = fp_lineType
                         and ih.invoicetype= 1
                         and il.extend = 'Y'
                         and il.billedqty > 0
                         and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                       order by ih.deltocustomer_link_id asc,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id,ih.invoicedate desc, ih.invoiceheader_id desc)
                  group by deltocustomer_link_id,invoicelinetype_id, invoicelinesubtype,product_link_id,sizedefinition_link_id)
                    select  vvlastInvoice.deltocustomer_link_id,
                          il.invoicelinetype_id,
                          il.invoicelinesubtype,
                          ilp.product_link_id,
                          case p.typeofmerchandise
                              when 2 then gv_sizestarid
                          else
                              ilp.sizedefinition_link_id
                          end sizedefinition,
                          null finishingmethod_id,
                          il.price,
                          null generalpricelist_id,
                          1 priceListType,
                          null Invoiceheader_Id,
                          vvlastInvoice.lastInvoiceId,
                          gv_systemuserid currentuser,
                          sysdate currentdate,
                         0 as changesPerWeek
                    from vv_lastInvoice vvlastInvoice,  invoiceline il, invoicelineproduct ilp  left outer join product p on ilp.product_link_id = p.product_id
                    where il.invoiceheader_id = vvlastInvoice.lastInvoiceId
                     and ilp.invoiceline_id = il.invoiceline_id
                     and nvl(ilp.product_link_id,0) = nvl(vvlastInvoice.product_link_id,0)
                     and nvl(ilp.sizedefinition_link_id,0) = nvl(vvlastInvoice.sizedefinition_link_id,0)
                     and il.invoicelinetype_id = vvlastInvoice.invoicelinetype_id
                     and il.invoicelinesubtype = vvlastInvoice.invoicelinesubtype
                     and il.extend = 'Y'
                     and il.billedqty > 0
                      order by  vvlastInvoice.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id, vvlastInvoice.lastInvoiceDate desc,vvlastInvoice.lastInvoiceId desc )
                LOOP
                        merge into  lastProductPriceused
                        using (select  loadRecord.deltocustomer_link_id deltocustomer_link_id,
                            loadRecord.invoicelinetype_id invoicelinetype_id,
                            case loadRecord.invoicelinesubtype
                              when 0 then null
                             else
                              loadRecord.invoicelinesubtype
                            end invoicelinesubtype,
                            loadRecord.product_link_id product_link_id,
                            loadRecord.sizedefinition sizedefinition,
                            loadRecord.finishingmethod_id finishingmethod_id,
                            loadRecord.price price,
                            loadRecord.generalpricelist_id generalpricelist_id,
                            loadRecord.priceListType priceListType,
                            loadRecord.lastInvoiceId lastInvoiceId,
                            loadRecord.currentuser currentuser,
                            loadRecord.currentdate currentdate,
                            loadRecord.changesPerWeek changesPerWeek
                             from dual ) mySrc
                          on (mySrc.deltocustomer_link_id =  lastProductPriceused.Customer_Link_Id and
                            mySrc.invoicelinetype_id =   lastProductPriceused.invoicelinetype_id and
                            nvl(mySrc.invoicelinesubtype,0) = nvl( lastProductPriceused.invoicelinesubtype,0) and
                            mySrc.product_link_id =  lastProductPriceused.Product_Id and
                            mySrc.sizedefinition =  lastProductPriceused.Sizedefinition_Id)
                          when not matched then
                             insert
                               (Lastproductpriceused_Id,
                                CUSTOMER_LINK_ID,
                                INVOICELINETYPE_ID,
                                INVOICELINESUBTYPE,
                                PRODUCT_ID,
                                SIZEDEFINITION_ID,
                                FINISHINGMETHOD_ID,
                                price,
                                Generalpricelist_Id,
                                Pricelisttype,
                                Invoiceheader_Id,
                                creationInvoiceHeader_id,
                                Systemuser_Id,
                                Timestamp,
                                changesPerWeek
                              ) values (
                                SEQ_LASTPRODUCTPRICEUSED.NEXTVAL,
                                mySrc.deltocustomer_link_id,
                                mySrc.invoicelinetype_id,
                                mySrc.invoicelinesubtype,
                                mySrc.product_link_id,
                                mySrc.sizedefinition,
                                mySrc.finishingmethod_id,
                                mySrc.price,
                                mySrc.generalpricelist_id,
                                mySrc.priceListType,
                                null,
                                mySrc.lastInvoiceId,
                                mySrc.currentuser,
                                mySrc.currentdate,
                                mySrc.changesPerWeek
                              );

                      lv_contor := lv_contor + 1;
                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end Product' ,'audit end Product for BU = ' || fp_buId );
    exception
       when others then
          write_log('auditLastProdBU=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLastProductPriceForBUAndLineTypeNoFinMeth;


procedure auditInfoLastProductPriceForBUAndLineTypeWithFinMeth(fp_buId in number, fp_lineType in number) is
    lv_contor number := 0;
    begin
     FOR loadRecord IN (
         with vv_lastInvoice as
              (select deltocustomer_link_id, invoicelinetype_id, invoicelinesubtype, product_link_id,sizedefinition_link_id,finishingmethod_id,max(lastInvoiceId) lastInvoiceId, max(lastInvoiceDate) lastInvoiceDate
               from
                (select ih.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id,ilp.finishingmethod_id,
                        first_value(ih.invoiceheader_id) OVER (PARTITION BY ih.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id, ilp.finishingmethod_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                        first_value(ih.invoicedate)      OVER (PARTITION BY ih.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id, ilp.finishingmethod_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceDate
                 from INVOICEHEADER IH, INVOICELINE IL, invoicelineproduct ilp
                   where IH.INVOICEHEADER_ID = IL.INVOICEHEADER_ID
                         and ih.invoicebusinessunit_id = fp_buId
                         and ih.invoicedate > sysdate -365*2
                         and ih.documenttype = 1
                         and ih.status_id in (1,2)
                         and ilp.invoiceline_id = il.invoiceline_id
                         and il.invoicelinetype_id = fp_lineType
                         and ih.invoicetype= 1
                         and il.extend = 'Y'
                         and il.billedqty > 0
                         and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                       order by ih.deltocustomer_link_id asc,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id,ilp.sizedefinition_link_id,ilp.finishingmethod_id,ih.invoicedate desc, ih.invoiceheader_id desc)
                  group by deltocustomer_link_id,invoicelinetype_id, invoicelinesubtype,product_link_id,sizedefinition_link_id,finishingmethod_id)
                    select  vvlastInvoice.deltocustomer_link_id,
                          il.invoicelinetype_id,
                          il.invoicelinesubtype,
                          ilp.product_link_id,
                          case p.typeofmerchandise
                              when 2 then gv_sizestarid
                          else
                              ilp.sizedefinition_link_id
                          end sizedefinition,
                          ilp.finishingmethod_id finishingmethod_id,
                          il.price,
                          null generalpricelist_id,
                          1 priceListType,
                          null Invoiceheader_Id,
                          vvlastInvoice.lastInvoiceId,
                          gv_systemuserid currentuser,
                          sysdate currentdate,
                         0 as changesPerWeek
                    from vv_lastInvoice vvlastInvoice,  invoiceline il, invoicelineproduct ilp  left outer join product p on ilp.product_link_id = p.product_id
                    where il.invoiceheader_id = vvlastInvoice.lastInvoiceId
                     and ilp.invoiceline_id = il.invoiceline_id
                     and nvl(ilp.product_link_id,0) = nvl(vvlastInvoice.product_link_id,0)
                     and nvl(ilp.sizedefinition_link_id,0) = nvl(vvlastInvoice.sizedefinition_link_id,0)
                     and il.invoicelinetype_id = vvlastInvoice.invoicelinetype_id
                     and il.invoicelinesubtype = vvlastInvoice.invoicelinesubtype
                     and il.extend = 'Y'
                     and il.billedqty > 0
                     order by  vvlastInvoice.deltocustomer_link_id,il.invoicelinetype_id,il.invoicelinesubtype,ilp.product_link_id, vvlastInvoice.lastInvoiceDate desc,vvlastInvoice.lastInvoiceId desc )
                LOOP
                        merge into  lastProductPriceused
                        using (select  loadRecord.deltocustomer_link_id deltocustomer_link_id,
                            loadRecord.invoicelinetype_id invoicelinetype_id,
                            case loadRecord.invoicelinesubtype
                              when 0 then null
                             else
                              loadRecord.invoicelinesubtype
                            end invoicelinesubtype,
                            loadRecord.product_link_id product_link_id,
                            loadRecord.sizedefinition sizedefinition,
                            loadRecord.finishingmethod_id finishingmethod_id,
                            loadRecord.price price,
                            loadRecord.generalpricelist_id generalpricelist_id,
                            loadRecord.priceListType priceListType,
                            loadRecord.lastInvoiceId lastInvoiceId,
                            loadRecord.currentuser currentuser,
                            loadRecord.currentdate currentdate,
                            loadRecord.changesPerWeek changesPerWeek
                             from dual ) mySrc
                          on (mySrc.deltocustomer_link_id =  lastProductPriceused.Customer_Link_Id and
                            mySrc.invoicelinetype_id =   lastProductPriceused.invoicelinetype_id and
                            nvl(mySrc.invoicelinesubtype,0) = nvl( lastProductPriceused.invoicelinesubtype,0) and
                            mySrc.product_link_id =  lastProductPriceused.Product_Id and
                            mySrc.sizedefinition =  lastProductPriceused.Sizedefinition_Id)
                          when not matched then
                             insert
                               (Lastproductpriceused_Id,
                                CUSTOMER_LINK_ID,
                                INVOICELINETYPE_ID,
                                INVOICELINESUBTYPE,
                                PRODUCT_ID,
                                SIZEDEFINITION_ID,
                                FINISHINGMETHOD_ID,
                                price,
                                Generalpricelist_Id,
                                Pricelisttype,
                                Invoiceheader_Id,
                                creationInvoiceHeader_id,
                                Systemuser_Id,
                                Timestamp,
                                changesPerWeek
                              ) values (
                                SEQ_LASTPRODUCTPRICEUSED.NEXTVAL,
                                mySrc.deltocustomer_link_id,
                                mySrc.invoicelinetype_id,
                                mySrc.invoicelinesubtype,
                                mySrc.product_link_id,
                                mySrc.sizedefinition,
                                mySrc.finishingmethod_id,
                                mySrc.price,
                                mySrc.generalpricelist_id,
                                mySrc.priceListType,
                                null,
                                mySrc.lastInvoiceId,
                                mySrc.currentuser,
                                mySrc.currentdate,
                                mySrc.changesPerWeek
                              );

                      lv_contor := lv_contor + 1;
                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end Product' ,'audit end Product for BU = ' || fp_buId );
    exception
       when others then
          write_log('auditLastProdBU=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLastProductPriceForBUAndLineTypeWithFinMeth;


procedure auditInfoLPPBUAndLineTypeNoSubtype(fp_buId in number, fp_lineType in number) is
    lv_contor number := 0;
    begin
     FOR loadRecord IN (
         with vv_lastInvoice as
              (select deltocustomer_link_id, invoicelinetype_id,  product_link_id,sizedefinition_link_id,finishingmethod_id,max(lastInvoiceId) lastInvoiceId, max(lastInvoiceDate) lastInvoiceDate
               from
                (select ih.deltocustomer_link_id,il.invoicelinetype_id,ilp.product_link_id,ilp.sizedefinition_link_id,ilp.finishingmethod_id,
                        first_value(ih.invoiceheader_id) OVER (PARTITION BY ih.deltocustomer_link_id,il.invoicelinetype_id,ilp.product_link_id,ilp.sizedefinition_link_id, ilp.finishingmethod_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                        first_value(ih.invoicedate)      OVER (PARTITION BY ih.deltocustomer_link_id,il.invoicelinetype_id,ilp.product_link_id,ilp.sizedefinition_link_id, ilp.finishingmethod_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceDate
                 from INVOICEHEADER IH, INVOICELINE IL, invoicelineproduct ilp
                   where IH.INVOICEHEADER_ID = IL.INVOICEHEADER_ID
                         and ih.invoicebusinessunit_id = fp_buId
                         and ih.invoicedate > sysdate -365*2
                         and ih.documenttype = 1
                         and ih.status_id in (1,2)
                         and ilp.invoiceline_id = il.invoiceline_id
                         and il.invoicelinetype_id = fp_lineType
                         and ih.invoicetype= 1
                         and il.extend = 'Y'
                         and il.billedqty > 0
                         and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                       order by ih.deltocustomer_link_id asc,il.invoicelinetype_id,ilp.product_link_id,ilp.sizedefinition_link_id,ilp.finishingmethod_id,ih.invoicedate desc, ih.invoiceheader_id desc)
                  group by deltocustomer_link_id,invoicelinetype_id, product_link_id,sizedefinition_link_id,finishingmethod_id)
                    select  vvlastInvoice.deltocustomer_link_id,
                          il.invoicelinetype_id,
                          null as invoicelinesubtype,
                          ilp.product_link_id,
                          case p.typeofmerchandise
                              when 2 then gv_sizestarid
                          else
                              ilp.sizedefinition_link_id
                          end sizedefinition,
                          ilp.finishingmethod_id finishingmethod_id,
                          il.price,
                          null generalpricelist_id,
                          1 priceListType,
                          null Invoiceheader_Id,
                          vvlastInvoice.lastInvoiceId,
                          gv_systemuserid currentuser,
                          sysdate currentdate,
                         0 as changesPerWeek
                    from vv_lastInvoice vvlastInvoice,  invoiceline il, invoicelineproduct ilp  left outer join product p on ilp.product_link_id = p.product_id
                    where il.invoiceheader_id = vvlastInvoice.lastInvoiceId
                     and ilp.invoiceline_id = il.invoiceline_id
                     and nvl(ilp.product_link_id,0) = nvl(vvlastInvoice.product_link_id,0)
                     and nvl(ilp.sizedefinition_link_id,0) = nvl(vvlastInvoice.sizedefinition_link_id,0)
                     and il.invoicelinetype_id = vvlastInvoice.invoicelinetype_id
                     and il.extend = 'Y'
                     and il.billedqty > 0
                     order by  vvlastInvoice.deltocustomer_link_id,il.invoicelinetype_id,ilp.product_link_id, vvlastInvoice.lastInvoiceDate desc,vvlastInvoice.lastInvoiceId desc )
                LOOP
                        merge into  lastProductPriceused
                        using (select  loadRecord.deltocustomer_link_id deltocustomer_link_id,
                            loadRecord.invoicelinetype_id invoicelinetype_id,
                            null invoicelinesubtype,
                            loadRecord.product_link_id product_link_id,
                            loadRecord.sizedefinition sizedefinition,
                            loadRecord.finishingmethod_id finishingmethod_id,
                            loadRecord.price price,
                            loadRecord.generalpricelist_id generalpricelist_id,
                            loadRecord.priceListType priceListType,
                            loadRecord.lastInvoiceId lastInvoiceId,
                            loadRecord.currentuser currentuser,
                            loadRecord.currentdate currentdate,
                            loadRecord.changesPerWeek changesPerWeek
                             from dual ) mySrc
                          on (mySrc.deltocustomer_link_id =  lastProductPriceused.Customer_Link_Id and
                            mySrc.invoicelinetype_id =   lastProductPriceused.invoicelinetype_id and
                            mySrc.product_link_id =  lastProductPriceused.Product_Id and
                            mySrc.sizedefinition =  lastProductPriceused.Sizedefinition_Id)
                          when not matched then
                             insert
                               (Lastproductpriceused_Id,
                                CUSTOMER_LINK_ID,
                                INVOICELINETYPE_ID,
                                INVOICELINESUBTYPE,
                                PRODUCT_ID,
                                SIZEDEFINITION_ID,
                                FINISHINGMETHOD_ID,
                                price,
                                Generalpricelist_Id,
                                Pricelisttype,
                                Invoiceheader_Id,
                                creationInvoiceHeader_id,
                                Systemuser_Id,
                                Timestamp,
                                changesPerWeek
                              ) values (
                                SEQ_LASTPRODUCTPRICEUSED.NEXTVAL,
                                mySrc.deltocustomer_link_id,
                                mySrc.invoicelinetype_id,
                                null,
                                mySrc.product_link_id,
                                mySrc.sizedefinition,
                                mySrc.finishingmethod_id,
                                mySrc.price,
                                mySrc.generalpricelist_id,
                                mySrc.priceListType,
                                null,
                                mySrc.lastInvoiceId,
                                mySrc.currentuser,
                                mySrc.currentdate,
                                mySrc.changesPerWeek
                              );

                      lv_contor := lv_contor + 1;
                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end Product' ,'audit end Product for BU = ' || fp_buId );
    exception
       when others then
          write_log('auditLastProdBU=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLPPBUAndLineTypeNoSubtype;


 procedure auditInfoLastProductPriceForBUResidualValue(fp_buId in number) is
    lv_contor number := 0;
    begin
     FOR loadRecord IN (
        with vv_lastInvoice as
               (
                     select customer_link_id,product_link_id,sizedefinition_link_id, max(lastInvoiceId) lastInvoiceId, max(lastAmount) lastAmount
                      from (
                            select ooh.customer_link_id,ooh.product_link_id,ooh.sizedefinition_link_id,ooh.amount,ooh.invoiceheader_id,
                                   first_value(ooh.invoiceheader_id) OVER (PARTITION BY ooh.customer_link_id,ooh.product_link_id,ooh.sizedefinition_link_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                                   first_value(ooh.amount) OVER (PARTITION BY ooh.customer_link_id,ooh.product_link_id,ooh.sizedefinition_link_id ORDER BY ih.invoicedate desc, ih.invoiceheader_id desc) as lastAmount
                            from outofcirculationhistory ooh, invoiceheader ih
                            where ooh.invoiceheader_id=ih.invoiceheader_id
                               and ih.documenttype = 1
                               and ooh.status=0
                               and ih.invoicetype = 1
                               and ih.status_id in (1,2)
                               and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                               and ih.invoicedate > sysdate -365*2
                               and ih.invoicebusinessunit_id = fp_buId
                               )
                      group by  customer_link_id,product_link_id,sizedefinition_link_id)
                select  customer_link_id,product_link_id,
                        case p.typeofmerchandise
                             when 2 then gv_sizestarid
                            else
                               vvv.sizedefinition_link_id
                        end sizedefinition,
                        vvv.lastinvoiceid,vvv.lastAmount
                from vv_lastInvoice vvv, product p
                        where vvv.product_link_id=p.product_id
                order by customer_link_id,product_link_id, sizedefinition, lastinvoiceid desc

                )
                LOOP
                        merge into  lastProductPriceused
                        using (select  loadRecord.customer_link_id customer_link_id,
                            loadRecord.product_link_id product_link_id,
                            10 invoicelinetype_id,
                            null invoicelinesubtype,
                            loadRecord.sizedefinition sizedefinition,
                            loadRecord.lastAmount lastAmount,
                            loadRecord.lastInvoiceId lastInvoiceId
                         from dual ) mySrc
                          on (mySrc.customer_link_id =  lastProductPriceused.Customer_Link_Id and
                            mySrc.invoicelinetype_id = lastProductPriceused.Invoicelinetype_Id and
                            nvl(mySrc.invoicelinesubtype,0) = nvl( lastProductPriceused.invoicelinesubtype,0) and
                            mySrc.product_link_id =  lastProductPriceused.Product_Id and
                            mySrc.sizedefinition =  lastProductPriceused.Sizedefinition_Id
                            )
                          when not matched then
                             insert
                               (Lastproductpriceused_Id,
                                CUSTOMER_LINK_ID,
                                INVOICELINETYPE_ID,
                                INVOICELINESUBTYPE,
                                PRODUCT_ID,
                                SIZEDEFINITION_ID,
                                FINISHINGMETHOD_ID,
                                price,
                                Generalpricelist_Id,
                                Pricelisttype,
                                Invoiceheader_Id,
                                creationInvoiceHeader_id,
                                Systemuser_Id,
                                Timestamp,
                                changesPerWeek
                              ) values (
                                SEQ_LASTPRODUCTPRICEUSED.NEXTVAL,
                                mySrc.Customer_Link_Id,
                                mySrc.invoicelinetype_id,
                                mySrc.invoicelinesubtype,
                                mySrc.product_link_id,
                                mySrc.sizedefinition,
                                null,
                                mySrc.lastAmount,
                                null,
                                1,
                                null,
                                mySrc.lastInvoiceId,
                                gv_systemuserid,
                                sysdate,
                                0
                              );

                      lv_contor := lv_contor + 1;
                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end ResValue' ,'audit end ResValue For BU =' ||  fp_buId);
    exception
       when others then
          write_log('auditLastProdBURezValue=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLastProductPriceForBUResidualValue;



 procedure auditInfoLastPrepPriceForBU(fp_buId in number) is
    lv_contor number := 0;
    begin
            FOR prepRec IN (
               select customer_link_id, max(lastInvoiceId) lastInvoiceId, max(lastAmount) lastPrepAmount
               from (
                      select ihist.customer_link_id,ihist.amount,
                        first_value(ihist.invoiceheader_id) OVER (PARTITION BY ihist.customer_link_id ORDER BY ihist.customer_link_id,ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                        first_value(ihist.amount) OVER (PARTITION BY ihist.customer_link_id ORDER BY ihist.customer_link_id,ih.invoicedate desc, ih.invoiceheader_id desc) as lastAmount
                      from issuehistory ihist, invoiceheader ih
                      where ih.invoiceheader_id= ihist.invoiceheader_id
                         and ih.documenttype = 1
                         and ih.invoicetype= 1
                         and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                         and ihist.issuestatus=0
                         and ih.status_id in (1,2)
                         and ih.invoicedate > sysdate - 365*2
                         and ih.invoicebusinessunit_id = fp_buId
                         )
                group by customer_link_id )
                LOOP
                    merge into  lastprepchargepriceused
                      using (select prepRec.customer_link_id customer_link_id,
                        prepRec.lastPrepAmount lastPrepAmount,
                        prepRec.lastInvoiceId lastInvoiceId
                         from dual) mySrc
                      on ( lastprepchargepriceused.customer_link_id = mySrc.customer_link_id )
                      when not matched then
                      insert (LASTPREPCHARGEPRICEUSED_ID,
                        CUSTOMER_LINK_ID,
                        REASONCODE_ID,
                        PRICE,
                        PRICELISTTYPE,
                        INVOICEHEADER_ID,
                        CREATIONINVOICEHEADER_ID,
                        Systemuser_Id,
                        Timestamp
                      ) values (
                        SEQ_lastprepchargepriceused.NEXTVAL,
                        prepRec.customer_link_id,
                        null,
                        prepRec.lastPrepAmount,
                        1,
                        null,
                        prepRec.lastInvoiceId,
                        gv_systemuserid ,
                        sysdate
                      );

                      lv_contor := lv_contor + 1;

                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end Prep' ,'audit end Prep For BU =' ||  fp_buId);
    exception
       when others then
          write_log('auditInfoLastPrepPriceForBU=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLastPrepPriceForBU;

procedure auditInfoStatementFeeForBU(fp_buId in number) is
    lv_contor number := 0;
    begin
            FOR statementFeeRec IN(
                  select  deltocustomer_link_id, max(lastInvoiceId) lastInvoiceId, max(lastStatementFeePrice) lastStatementFeePrice
                  from
                    (select ih.invoiceheader_id,ih.invoicenumber, ih.invoicedate, ih.deltocustomer_link_id, il.invoicelinetype_id,il.price,
                      first_value(ih.invoiceheader_id) OVER (PARTITION BY ih.deltocustomer_link_id ORDER BY ih.deltocustomer_link_id,ih.invoicedate desc, ih.invoiceheader_id desc) as lastInvoiceId,
                        first_value(il.price) OVER (PARTITION BY ih.deltocustomer_link_id ORDER BY ih.deltocustomer_link_id,ih.invoicedate desc, ih.invoiceheader_id desc) as lastStatementFeePrice
                       from INVOICEHEADER IH, INVOICELINE IL
                           where IH.INVOICEHEADER_ID = IL.INVOICEHEADER_ID
                             and ih.documenttype = 1
                             and ih.invoicetype =1
                             and ih.status_id in (1,2)
                             and ih.invoicedate > sysdate -365*2
                             and ih.invoicebusinessunit_id = fp_buId  --1
                             and il.invoicelinetype_id = 33
                             and il.billedqty > 0
                             and il.extend ='Y'
                             and exists ( select 1 from customer c where c.customer_id=ih.deltocustomer_link_id and c.dateinactive > sysdate )
                       order by ih.deltocustomer_link_id,ih.invoicedate desc,ih.invoiceheader_id desc)
                       group by deltocustomer_link_id )
                LOOP
                      merge into   lastcustomerpriceused
                      using(select statementFeeRec.deltocustomer_link_id deltocustomer_link_id,
                        statementFeeRec.lastStatementFeePrice lastStatementFeePrice,
                        statementFeeRec.lastInvoiceId lastInvoiceId from dual) mySrc
                      on ( lastcustomerpriceused.customer_link_id=mySrc.deltocustomer_link_id)
                      when not matched then
                      insert
                       (LASTCUSTOMERPRICEUSED_ID,
                        CUSTOMER_LINK_ID,
                        type,
                        PRICE,
                        PRICELISTTYPE,
                        INVOICEHEADER_ID,
                        CREATIONINVOICEHEADER_ID,
                        Systemuser_Id,
                        Timestamp
                      ) values (
                        SEQ_LASTCUSTOMERPRICEUSED.NEXTVAL,
                        statementFeeRec.deltocustomer_link_id,
                        0,
                        statementFeeRec.lastStatementFeePrice,
                        1,
                        null,
                        statementFeeRec.lastInvoiceId,
                        gv_systemuserid ,
                        sysdate
                      );

                      lv_contor := lv_contor + 1;

                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end StFee' ,'audit end StFee For BU =' ||  fp_buId);
    exception
       when others then
          write_log('loadAuditStatFeeForBU=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoStatementFeeForBU;

 procedure auditInfoLastProductPriceForBUSpecialSize(fp_buId in number) is
    lv_contor number := 0;
    begin
          FOR loadRecord IN (
            select  deltocustomer_link_id,product_link_id,sizedefinition_link_id, max(lastInvoiceId) lastInvoiceId,  max(lastSpecialPrice) lastSpecialPrice
                   from
                      (select  ih.deltocustomer_link_id, ihist.product_link_id, ihist.sizedefinition_link_id,
                             first_value(ih.invoiceheader_id) over(partition by ih.deltocustomer_link_id, ihist.product_link_id, ihist.sizedefinition_link_id order by ih.invoicedate desc, ih.invoiceheader_id desc) as lastinvoiceid, --sa nu fie cancel?
                             first_value(ihist.specialsizeprice) over(partition by ih.deltocustomer_link_id, ihist.product_link_id, ihist.sizedefinition_link_id order by ih.invoicedate desc, ih.invoiceheader_id desc) as lastSpecialPrice
                     from invoiceheader ih, invoiceline il, issuehistory ihist,invoicelineproduct ilp
                       where ih.invoiceheader_id = il.invoiceheader_id
                         and ih.documenttype = 1
                         and ih.status_id in (1,2)
                         and ih.invoicetype=1
                         and ihist.issuestatus = 0
                         and il.extend='Y'
                         and il.billedqty > 0
                         and ih.invoicedate > sysdate -365*2
                         and ih.invoiceheader_id = ihist.invoiceheader_id
                         and ilp.invoiceline_id=il.invoiceline_id
                         and ilp.weareremployment_link_id = ihist.weareremployment_link_id
                         and il.invoicelinetype_id = 34
                         and il.invoicelinesubtype =1
                        and ihist.processbusinessunit_id = fp_buId
                         and exists (select 1 from customer c  where c.customer_id = ih.deltocustomer_link_id  and c.dateinactive > sysdate) -- doar pentru customerii activi??
                       order by ih.invoicedate   desc, ih.invoiceheader_id  desc, ih.deltocustomer_link_id,ihist.product_link_id, ihist.sizedefinition_link_id)
                        group by  deltocustomer_link_id,product_link_id, sizedefinition_link_id)
                 LOOP
                     merge into    lastProductPriceused
                     using ( select loadRecord.deltocustomer_link_id deltocustomer_link_id,
                        loadRecord.product_link_id product_link_id,
                        loadRecord.sizedefinition_link_id sizedefinition_link_id,
                        loadRecord.lastSpecialPrice lastSpecialPrice,
                        loadRecord.lastInvoiceId lastInvoiceId
                        from dual) mySrc
                      on ( lastProductPriceused.Customer_Link_Id=mySrc.deltocustomer_link_id
                        and  lastProductPriceused.Product_Id = mySrc.product_link_id
                        and  lastProductPriceused.Sizedefinition_Id= mySrc.sizedefinition_link_id
                        and nvl( lastProductPriceused.Finishingmethod_Id,0)=0
                        and  lastProductPriceused.invoicelinetype_id = 34
                        and  lastProductPriceused.invoicelinesubtype =1  )
                     when not matched then
                     insert (Lastproductpriceused_Id,
                        CUSTOMER_LINK_ID,
                        INVOICELINETYPE_ID,
                        INVOICELINESUBTYPE,
                        PRODUCT_ID,
                        SIZEDEFINITION_ID,
                        FINISHINGMETHOD_ID,
                        price,
                        Generalpricelist_Id,
                        Pricelisttype,
                        Invoiceheader_Id,
                        creationInvoiceHeader_id,
                        Systemuser_Id,
                        Timestamp,
                        changesPerWeek
                      ) values (
                        SEQ_LASTPRODUCTPRICEUSED.NEXTVAL,
                        loadRecord.deltocustomer_link_id,
                        34,
                        1,
                        loadRecord.product_link_id,
                        loadRecord.sizedefinition_link_id,
                        null,
                        loadRecord.lastSpecialPrice,
                        null,
                        1,
                        null,
                        loadRecord.lastInvoiceId,
                        1,
                        sysdate,
                        0
                      );

                      lv_contor := lv_contor + 1;
                      if (lv_contor >=  5000)  then
                         commit;
                         lv_contor := 0;
                      end if;
                END LOOP;
                commit;
                write_log('audit end SpecSize ' ,'audit end SpecSizeFor BU =' ||  fp_buId);
    exception
       when others then
          write_log('audInfoLastdPriceSpeSiBU=' ||  fp_buId ,substr(sqlerrm, 1, 1000));
          rollback;
        raise;
 end auditInfoLastProductPriceForBUSpecialSize;

 procedure loadInvoiceAuditInfoPerPlantForSalesLines(fp_plantCode in varchar2) is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           auditInfoLastProductPriceForBUAndLineTypeNoFinMeth(burecord.businessunit_id, gv_linetype_sales) ;
           write_log('run ok - Sales' ,'For BU =' || burecord.businessunit_id || ' ' ||  burecord.description || 'process loadAuditLastProductPriceForBUAndLineType' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForSalesLines;

 procedure loadInvoiceAuditInfoPerPlantForReplacementLines(fp_plantCode in varchar2) is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           auditInfoLastProductPriceForBUAndLineTypeNoFinMeth(burecord.businessunit_id, gv_linetype_replacement) ;
           write_log('run ok - Replacement' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadInvoiceAuditInfoPerPlantForReplacementLines' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForReplacementLines;

 procedure loadInvoiceAuditInfoPerPlantForLossLines(fp_plantCode in varchar2)  is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code= fp_plantCode)
         loop
           auditInfoLPPBUAndLineTypeNoSubtype(burecord.businessunit_id, gv_linetype_loss) ;
           write_log('run ok-ReplLoss' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadInvoiceAuditInfoPerPlantForReplLossLines' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForLossLines;


 procedure loadInvoiceAuditInfoPerPlantForRuinChargeResidualValue(fp_plantCode in varchar2)  is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code= fp_plantCode)
         loop
           auditInfoLastProductPriceForBUResidualValue(burecord.businessunit_id) ;
           write_log('run ok-RuinChg' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadInvoiceAuditInfoPerPlantForRuinChargeResidualValue' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForRuinChargeResidualValue;


 procedure loadInvoiceAuditInfoPerPlantForEmblemLines(fp_plantCode in varchar2) is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           auditInfoLastEmblemPriceForBU(burecord.businessunit_id);
           write_log('run ok - Emblem' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadAuditLastEmblemPriceForBU' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForEmblemLines;

 procedure loadInvoiceAuditInfoPerPlantForPrepChargeLines(fp_plantCode in varchar2) is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           auditInfoLastPrepPriceForBU(burecord.businessunit_id);
           write_log('run ok - PrepCharge' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadAuditLastPrepPriceForBU' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForPrepChargeLines;

  procedure loadInvoiceAuditInfoPerPlantForStatementFeeLines(fp_plantCode in varchar2) is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           auditInfoStatementFeeForBU(burecord.businessunit_id);
           write_log('run ok - StatFee' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadAuditStatFeeForBU' );
         end loop;
 end loadInvoiceAuditInfoPerPlantForStatementFeeLines;

 procedure loadInvoiceAuditInfoPerPlantForSpecialSizeLines(fp_plantCode in varchar2) is
    begin
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           auditInfoLastProductPriceForBUSpecialSize(burecord.businessunit_id);
           write_log('run ok - SpecialSize' ,'For BU =' || burecord.businessunit_id || ' '  || burecord.code || ' ' ||  burecord.description || 'process loadInvoiceAuditAllBuSpecialSize' );
         end loop;
  end loadInvoiceAuditInfoPerPlantForSpecialSizeLines;

  procedure loadInvoiceAuditInfoPerPlantAllLines(fp_plantCode in varchar2) is
    begin
      abslogwrite.abslog_write(5, 'pack_invoiceAudit_initialLoad - begin', null, 5, 'pack_invoiceAudit_initialLoad - begin for plant = ' || fp_plantCode);
      for burecord in (select bu.businessunit_id, bu.code, bu.description
         from BUSINESSUNIT bu, plant p
          where p.plant_id = bu.plant_id
          and p.code = fp_plantCode)
         loop
           abslogwrite.abslog_write(5, 'pack_invoiceAudit_initialLoad - begin', null, 5, 'pack_invoiceAudit_initialLoad - begin for BU = ' || burecord.businessunit_id);

           auditInfoLastProductPriceForBUAndLineTypeNoFinMeth(burecord.businessunit_id, gv_linetype_sales) ;
           auditInfoLastProductPriceForBUAndLineTypeNoFinMeth(burecord.businessunit_id, gv_linetype_replacement) ;
           auditInfoLPPBUAndLineTypeNoSubtype(burecord.businessunit_id, gv_linetype_loss) ;
           auditInfoLastEmblemPriceForBU(burecord.businessunit_id);
           auditInfoLastPrepPriceForBU(burecord.businessunit_id);
           auditInfoStatementFeeForBU(burecord.businessunit_id);
           auditInfoLastProductPriceForBUSpecialSize(burecord.businessunit_id);
           auditInfoLastProductPriceForBUResidualValue(burecord.businessunit_id);
           abslogwrite.abslog_write(5, 'pack_invoiceAudit_initialLoad - end', null, 5, 'pack_invoiceAudit_initialLoad - end for BU = ' || burecord.businessunit_id);
       end loop;
  end loadInvoiceAuditInfoPerPlantAllLines;


begin
      begin
           select su.systemuser_id into gv_systemuserid from systemuser su where su.username='SYSADM' and rownum=1;
      exception
           when no_data_found then
             gv_systemuserid := 0;
      end;

      begin
            select SIZEDEFINITION_ID into gv_sizestarid from SIZEDEFINITION where CODE = '*';
      exception
           when others then
             write_log('pack_invoiceAudit_iniLoad-noStar ', substr(sqlerrm, 1, 1000));
      end;

exception
     when others then
          write_log('pack_invoiceAudit_initialLoad', substr(sqlerrm, 1, 1000));
          rollback;
end pack_invoiceAudit_initialLoad;
/
create or replace package pack_invoiceheader is

  /****************************************************************************\
  * -- Author   : PVD                                                          *
  * -- Created  : 18-9-2009                                                    *
  * -- Purpose  : Create invoiceheader and invoiceline                         *
  * -- Messages : 0 ok                                                         *
  *               1 no data found                                              *
  *               2 wrong value used                                           *
  *               3 duplicate value on index                                   *
  *               4 other error message                                        *
  * -- Remark   : This package does not check the totals for the invoiceheader *
  *               nor for the artransaction details, they have to provided in  *
  *               the right way!                                               *
  \****************************************************************************/

  procedure create_invoiceheader(fp_messagenumber        out number,
                                 fp_invoicedate          in invoiceheader.invoicedate%type,
                                 fp_invoicenumber        in invoiceheader.invoicenumber%type,
                                 fp_invoicebusinessunit  in businessunit.code%type,
                                 fp_city                 in invoiceheader.city%type,
                                 fp_zipcode              in invoiceheader.zipcode%type,
                                 fp_street               in invoiceheader.street%type, --length 30
                                 fp_street2              in invoiceheader.street2%type, --NEW   30
                                 fp_billtocustomername   in invoiceheader.billtocustomername%type,
                                 fp_billtocustomernumber in invoiceheader.billtocustomernumber%type,
                                 fp_invoicetype          in invoiceheader.invoicetype%type,
                                 fp_invoicecomments      in invoiceheader.invoicecomments%type,
                                 fp_paythisammount       in invoiceheader.paythisamount%type,
                                 fp_prebillamount        in invoiceheader.prebillamount%type,
                                 fp_currencycode         in currency.code%type,
                                 fp_totalamountexlvat    in invoiceheader.totalamountexclvat%type,
                                 fp_extraname1           in invoiceheader.extraname1%type,
                                 fp_extraname2           in invoiceheader.extraname2%type,
                                 fp_startdate            in invoiceheader.startdate%type,
                                 fp_enddate              in invoiceheader.enddate%type,
                                 fp_deltocustomernumber  in invoiceheader.deltocustomernumber%type,
                                 fp_deltocustomername    in invoiceheader.deltocustomername%type,
                                 fp_paymentdiscountdays  in invoiceheader.paymentdiscountdays%type,
                                 fp_netpaymentdays       in invoiceheader.netpaymentdays%type);

  procedure create_invoiceline(fp_messagenumber     out number,
                               fp_invoicenumber     in invoiceheader.invoicenumber%type,
                               fp_invoicelinetype   in invoicelinetype.invoicelinetype_id%type,
                               fp_linenumber        in invoiceline.linenumber%type, --line order
                               fp_invoicelinecode   in invoiceline.code%type,
                               fp_description       in invoiceline.description%type, --NEW length 40
                               fp_amount            in invoiceline.amount%type,
                               fp_price             in invoiceline.price%type,
                               fp_billedqty         in invoiceline.billedqty%type,
                               fp_turnovergroupcode in turnovergroup.code%type,
                               fp_percentage        in invoicelinevarious.percentage%type, --only for type 18
                               fp_overamount        in invoicelinevarious.overamount%type, --only for type 18
                               fp_billingmethod     in invoicelineproduct.billingmethod%type default 0,
                               fp_taxgroupcode      in invoiceline.taxgroupcode%type default '2');

end pack_invoiceheader;
/
create or replace package body pack_invoiceheader is
  gv_defaultuserid   systemuser.systemuser_id%type;
  gv_defaultusername systemuser.username%type := 'ALLTEX';
  gv_message         abslog.message%type;
  ge_wrongvalue exception;

  procedure write_log(fp_message  in abslog.message%type,
                      fp_priority in abslog.priority%type default 1) is
  begin
    /*
    Write message in ABSLOG with these priorities
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info
    */
    abslogwrite.abslog_write(5, 'pack_invoiceheader', null, fp_priority, fp_message,
                             gv_defaultuserid);
  end write_log;

  procedure init_artransaction(fp_artransactionrec in out artransaction%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init artransaction';
    --fill the artransaction row fp_artransactionrec with default values from table artransaction
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'ARTRANSACTION'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_artransactionrec;
    close rcur_typ;
    fp_artransactionrec.systemuser_id := gv_defaultuserid;
    fp_artransactionrec.timestamp     := sysdate;
    --get artransaction sequence
    gv_message := 'get sequence for artransaction';
    select seq_artransaction.nextval into fp_artransactionrec.artransaction_id from dual;
    --fill default values
    gv_message                               := 'fill other default values into artransaction';
    fp_artransactionrec.closingamount        := 0;
    fp_artransactionrec.exportstatus         := 0; --0=not exported
    fp_artransactionrec.artransactiontype_id := 1; --1=invoice
    fp_artransactionrec.paymenttype          := 1; --1=charge
    fp_artransactionrec.debitcredit          := 'D'; --'D'= Debit=charge
  end init_artransaction;

  procedure init_artransactiondetail(fp_artransactiondetailrec in out artransactiondetail%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init artransaction detail';
    --fill the artransaction row fp_artransactionrec with default values from table artransaction
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'ARTRANSACTIONDETAIL'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_artransactiondetailrec;
    close rcur_typ;
    fp_artransactiondetailrec.systemuser_id := gv_defaultuserid;
    fp_artransactiondetailrec.timestamp     := sysdate;
    --fill default values
    gv_message := 'fill other default values into artransaction detail';
  end init_artransactiondetail;

  procedure init_invoiceheader(fp_invoiceheaderrec in out invoiceheader%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init invoiceheader';
    --fill the invoiceheader row fp_invoiceheaderrec with default values from table invoiceheader
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'INVOICEHEADER'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_invoiceheaderrec;
    close rcur_typ;
    fp_invoiceheaderrec.systemuser_id := gv_defaultuserid;
    fp_invoiceheaderrec.timestamp     := sysdate;
    --get invoiceheader sequence
    gv_message := 'get sequence for invoiceheader';
    select seq_invoiceheader.nextval into fp_invoiceheaderrec.invoiceheader_id from dual;
    --other amounts
    gv_message                               := 'fill other default amounts into invoiceheader';
    fp_invoiceheaderrec.totalminusadjustment := 0;
    fp_invoiceheaderrec.totalplusadjustment  := 0;
    fp_invoiceheaderrec.cashcollected        := 0;
    fp_invoiceheaderrec.creditsqueezeamount  := 0;
    fp_invoiceheaderrec.creditsqueezeperc    := 0;
    --fill other default values
    gv_message                                 := 'fill other default values into invoiceheader';
    fp_invoiceheaderrec.invoicefrequency_id    := 0; --default direct invoice freq.
    fp_invoiceheaderrec.documenttype           := 1; --1=invoice
    fp_invoiceheaderrec.credited               := 1;
    fp_invoiceheaderrec.emailstatus            := 0;
    fp_invoiceheaderrec.realcollectiontype     := 2;
    fp_invoiceheaderrec.originalcollectiontype := 2;
    fp_invoiceheaderrec.exported               := 'N';
    fp_invoiceheaderrec.nextperiodnoweeks      := 0;
    fp_invoiceheaderrec.netpaymentdays         := 0;
    fp_invoiceheaderrec.paymentdiscountdays    := 0;
    fp_invoiceheaderrec.convertedfromlegacy    := 'N';
    fp_invoiceheaderrec.realcollectiontype     := 2;
    fp_invoiceheaderrec.originalcollectiontype := 2;
  end init_invoiceheader;

  procedure init_invoicelineproduct(fp_invoicelineproductrec in out invoicelineproduct%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init invoicelineproduct';
    --fill the invoiceline product row fp_invoicelineproductrec
    --with default values from table invoiceline product
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'INVOICELINEPRODUCT'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_invoicelineproductrec;
    close rcur_typ;
    fp_invoicelineproductrec.systemuser_id := gv_defaultuserid;
    fp_invoicelineproductrec.timestamp     := sysdate;
    --fill other default values
    gv_message                                   := 'fill other default values into invoiceline product';
    fp_invoicelineproductrec.relatedproduct      := 0; -- 0 = not applicable
    fp_invoicelineproductrec.delayedevenexchange := 0; -- 0 = no delay
    fp_invoicelineproductrec.soilquantity        := 0;
    fp_invoicelineproductrec.abusedquantity      := 0;
    fp_invoicelineproductrec.soilcountmethod     := 0;
    fp_invoicelineproductrec.inventoryqty        := 0;
    fp_invoicelineproductrec.invoiceqtycolumn    := 0;
  end init_invoicelineproduct;

  procedure init_invoiceline(fp_invoicelinerec in out invoiceline%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init invoiceline';
    --fill the invoiceline row fp_invoicelinerec with default values from table invoiceline
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'INVOICELINE'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_invoicelinerec;
    close rcur_typ;
    fp_invoicelinerec.systemuser_id := gv_defaultuserid;
    fp_invoicelinerec.timestamp     := sysdate;
    --get invoiceline sequence
    gv_message := 'get sequence for invoiceline';
    select seq_invoiceline.nextval into fp_invoicelinerec.invoiceline_id from dual;
    --fill other default values
    gv_message                            := 'fill other default values into invoiceline';
    fp_invoicelinerec.adjustedprice       := 0;
    fp_invoicelinerec.adjustmentbilledqty := 0;
    fp_invoicelinerec.adjustedamount      := 0;
    fp_invoicelinerec.discountpercentage  := 0;
    fp_invoicelinerec.subjecttominimum    := 'N';
    fp_invoicelinerec.taxtype             := 1; --1=define tax
    fp_invoicelinerec.generated           := 'N';
    fp_invoicelinerec.extend              := 'N';
  end init_invoiceline;

  function get_businessunit_id(fp_businessunitcode in businessunit.code%type) return number is
    lv_businessunit_id businessunit.businessunit_id%type;
  begin
    --get businessunit id for fp_businessunitcode parameter
    gv_message := 'get businessunit id for businessunit code parameter' || fp_businessunitcode;
    select bu.businessunit_id
    into   lv_businessunit_id
    from   businessunit bu
    where  bu.code = fp_businessunitcode;
    return lv_businessunit_id;
  end get_businessunit_id;

  function get_currency_id(fp_currency_code   in currency.code%type,
                           fp_invoicedecimals out currency.invoiceamountdecimals%type) return number is
    lv_currency_id currency.currency_id%type;
  begin
    --get currency id for currency code parameter
    gv_message := 'get currency id for currency code parameter' || fp_currency_code;
    select cy.currency_id, cy.invoiceamountdecimals
    into   lv_currency_id, fp_invoicedecimals
    from   currency cy
    where  cy.code = fp_currency_code;
    return lv_currency_id;
  end get_currency_id;

  function get_customer_link_id(fp_customernumber in customer.customernumber%type) return number is
    lv_customer_link_id customer_link.customer_link_id%type;
  begin
    --get bill to customer link id
    gv_message := 'get customer link id for customer number ' || fp_customernumber;
    select l.customer_link_id
    into   lv_customer_link_id
    from   customer_link l
    where  l.customernumber = fp_customernumber;
    return lv_customer_link_id;
  end get_customer_link_id;

  function get_invoiceheader_id(fp_invoicenumber in invoiceheader.invoicenumber%type) return number is
    lv_invoiceheader_id invoiceheader.invoiceheader_id%type;
  begin
    --get invoiceheader id for invoicennumber
    gv_message := 'get invoiceheadere id for invoice number ' || fp_invoicenumber ||
                  ' made by systemuser ' || gv_defaultusername;
    --if invoicennumber <= 0 then the number is wrong
    if fp_invoicenumber <= 0 then
      raise ge_wrongvalue;
    end if;
    --remark ONLY get invoices made by gv_defaultuserid
    select h.invoiceheader_id
    into   lv_invoiceheader_id
    from   invoiceheader h
    where  h.invoicenumber = fp_invoicenumber
    and    h.systemuser_id = gv_defaultuserid;
    return lv_invoiceheader_id;
  end get_invoiceheader_id;

  function get_invoice_status_id(fp_statuscode in status.code%type) return number is
    lv_status_id status.status_id%type;
  begin
    --get invoice status
    gv_message := 'get invoice status ' || fp_statuscode;
    select st.status_id
    into   lv_status_id
    from   status st
    where  st.statustype = 'IN'
    and    st.code = fp_statuscode;
    return lv_status_id;
  end get_invoice_status_id;

  function get_turnovergroup_id(fp_turnovergroupcode in turnovergroup.code%type) return number is
    lv_turnovergroupid turnovergroup.turnovergroup_id%type;
  begin
    --get turnovergroup id
    gv_message := 'get turnovergroup id for turnovergroup code = ' || fp_turnovergroupcode;
    select tg.turnovergroup_id
    into   lv_turnovergroupid
    from   turnovergroup tg
    where  tg.code = fp_turnovergroupcode;
    return lv_turnovergroupid;
  end get_turnovergroup_id;

  function get_artransaction_id(fp_invoicenumber in invoiceheader.invoicenumber%type) return number is
    lv_artransactionid artransaction.artransaction_id%type;
  begin
    --lookup artransaction id based on invoicenumber
    gv_message := 'get artransaction id for invoicenumber ' || to_char(fp_invoicenumber);
    select ar.artransaction_id
    into   lv_artransactionid
    from   artransaction ar
    where  ar.invoicenumber = fp_invoicenumber;
    return lv_artransactionid;
  end get_artransaction_id;

  function get_product_id(fp_productcode in product.code%type) return number is
    lv_productid product.product_id%type;
  begin
    --try to find product_id if not found return null
    select p.product_id into lv_productid from product p where p.code = fp_productcode;
    return lv_productid;
  exception
    when no_data_found then
      return null;
  end get_product_id;

  procedure create_artransaction(fp_invoiceheaderrec in invoiceheader%rowtype) is
    lv_artransactionrec artransaction%rowtype;
  begin
    --init artransaction record
    init_artransaction(lv_artransactionrec);
    --create artransaction header
    gv_message := 'create artransaction header for invoice number ' ||
                  fp_invoiceheaderrec.invoicenumber;
    --fill lv_artransactionrec
    lv_artransactionrec.invoicenumber          := fp_invoiceheaderrec.invoicenumber;
    lv_artransactionrec.businessunit_id        := fp_invoiceheaderrec.invoicebusinessunit_id;
    lv_artransactionrec.processbusinessunit_id := fp_invoiceheaderrec.invoicebusinessunit_id;
    lv_artransactionrec.billtocustomer_link_id := fp_invoiceheaderrec.billtocustomer_link_id;
    lv_artransactionrec.deltocustomer_link_id  := fp_invoiceheaderrec.deltocustomer_link_id;
    lv_artransactionrec.artransactiondate      := fp_invoiceheaderrec.invoicedate;
    lv_artransactionrec.currency_id            := fp_invoiceheaderrec.currency_id;
    lv_artransactionrec.amount                 := fp_invoiceheaderrec.paythisamount;
    --insert into artransaction
    insert into artransaction values lv_artransactionrec;
  end create_artransaction;

  procedure create_artransactiondetail(fp_invoicelinerec    in invoiceline%rowtype,
                                       fp_turnovergroup_id  in turnovergroup.turnovergroup_id%type,
                                       fp_invoicenumber     in invoiceheader.invoicenumber%type,
                                       fp_turnovergroupcode in turnovergroup.code%type) is
    lv_artransactiondetailrec artransactiondetail%rowtype;
  begin
    --init artransaction record
    init_artransactiondetail(lv_artransactiondetailrec);
    lv_artransactiondetailrec.artransaction_id := get_artransaction_id(fp_invoicenumber);
    --create artransaction detail
    gv_message := 'create artransaction detail for invoice number / turnovergroup ' ||
                  fp_invoicenumber || ' / ' || fp_turnovergroupcode;
    --fill lv_artransactiondetailrec
    lv_artransactiondetailrec.turnovergroup_id      := fp_turnovergroup_id;
    lv_artransactiondetailrec.amount                := fp_invoicelinerec.amount;
    lv_artransactiondetailrec.amountinplantcurrency := fp_invoicelinerec.amount;
    begin
      --insert into artransaction
      insert into artransactiondetail values lv_artransactiondetailrec;
    exception
      when dup_val_on_index then
        begin
          ---> when insert fails update!!
          gv_message := 'update artransaction detail for invoicenumber / turnovergroup ' ||
                        fp_invoicenumber || ' / ' || fp_turnovergroupcode;
          update artransactiondetail ard
          set    ard.amount = ard.amount + fp_invoicelinerec.amount
          where  ard.artransaction_id = lv_artransactiondetailrec.artransaction_id
          and    ard.turnovergroup_id = lv_artransactiondetailrec.turnovergroup_id;
        end;
    end;
  end create_artransactiondetail;

  procedure create_invoiceheaderextrainfo(fp_invoiceheader_id in invoiceheader.invoiceheader_id%type,
                                          fp_invoicenumber    in invoiceheader.invoicenumber%type) is
  begin
    --create invoiceheaderextrainfo
    gv_message := 'create invoiceheaderextrainfo for invoice number ' || fp_invoicenumber;
    --insert into invoiceheaderextrainfo
    --default formlayoutcode=3 14-10-2009
    insert into invoiceheaderextrainfo
      (formlayoutcode, attachinvoicecopies, taxable, paymenttermstype, paymenttermsduedate,
       invoiceheader_id, billtocountrydescription)
    values
      (3, 'N', 'Y', 0, sysdate, fp_invoiceheader_id, ' ');
  end create_invoiceheaderextrainfo;

  procedure create_invoiceheader(fp_messagenumber        out number,
                                 fp_invoicedate          in invoiceheader.invoicedate%type,
                                 fp_invoicenumber        in invoiceheader.invoicenumber%type,
                                 fp_invoicebusinessunit  in businessunit.code%type,
                                 fp_city                 in invoiceheader.city%type,
                                 fp_zipcode              in invoiceheader.zipcode%type,
                                 fp_street               in invoiceheader.street%type,
                                 fp_street2              in invoiceheader.street2%type,
                                 fp_billtocustomername   in invoiceheader.billtocustomername%type,
                                 fp_billtocustomernumber in invoiceheader.billtocustomernumber%type,
                                 fp_invoicetype          in invoiceheader.invoicetype%type,
                                 fp_invoicecomments      in invoiceheader.invoicecomments%type,
                                 fp_paythisammount       in invoiceheader.paythisamount%type,
                                 fp_prebillamount        in invoiceheader.prebillamount%type,
                                 fp_currencycode         in currency.code%type,
                                 fp_totalamountexlvat    in invoiceheader.totalamountexclvat%type,
                                 fp_extraname1           in invoiceheader.extraname1%type,
                                 fp_extraname2           in invoiceheader.extraname2%type,
                                 fp_startdate            in invoiceheader.startdate%type,
                                 fp_enddate              in invoiceheader.enddate%type,
                                 fp_deltocustomernumber  in invoiceheader.deltocustomernumber%type,
                                 fp_deltocustomername    in invoiceheader.deltocustomername%type,
                                 fp_paymentdiscountdays  in invoiceheader.paymentdiscountdays%type,
                                 fp_netpaymentdays       in invoiceheader.netpaymentdays%type) is
    lv_invoiceheaderrec invoiceheader%rowtype;
    lv_invoicedecimals  currency.invoiceamountdecimals%type;
  begin
    --init invoiceheader, fill with default values
    init_invoiceheader(lv_invoiceheaderrec);
    --get businessunit id
    lv_invoiceheaderrec.invoicebusinessunit_id := get_businessunit_id(fp_invoicebusinessunit);
    --get bill to customer link
    lv_invoiceheaderrec.billtocustomer_link_id := get_customer_link_id(fp_billtocustomernumber);
    lv_invoiceheaderrec.deltocustomer_link_id  := get_customer_link_id(fp_deltocustomernumber);
    --get currency
    lv_invoiceheaderrec.currency_id := get_currency_id(fp_currencycode, lv_invoicedecimals);
    --get invoice status
    lv_invoiceheaderrec.status_id := get_invoice_status_id('2');
    --copy parameters into lv_invoiceheaderrec
    gv_message                               := 'copy parameters into invoiceheader';
    lv_invoiceheaderrec.invoicedate          := fp_invoicedate;
    lv_invoiceheaderrec.invoicedaynumber     := getabsdaynumber(fp_invoicedate);
    lv_invoiceheaderrec.invoiceweek          := getisoweek(fp_invoicedate);
    lv_invoiceheaderrec.invoiceyear          := to_number(to_char(fp_invoicedate, 'IYYY'));
    lv_invoiceheaderrec.invoicenumber        := fp_invoicenumber;
    lv_invoiceheaderrec.startdate            := fp_startdate;
    lv_invoiceheaderrec.enddate              := fp_enddate;
    lv_invoiceheaderrec.startweek            := getisoweek(fp_startdate);
    lv_invoiceheaderrec.endweek              := getisoweek(fp_enddate);
    lv_invoiceheaderrec.startyear            := to_number(to_char(fp_startdate, 'IYYY'));
    lv_invoiceheaderrec.endyear              := to_number(to_char(fp_enddate, 'IYYY'));
    lv_invoiceheaderrec.startmonth           := to_number(to_char(fp_startdate, 'MM'));
    lv_invoiceheaderrec.endmonth             := to_number(to_char(fp_enddate, 'MM'));
    lv_invoiceheaderrec.city                 := fp_city;
    lv_invoiceheaderrec.zipcode              := fp_zipcode;
    lv_invoiceheaderrec.street               := fp_street;
    lv_invoiceheaderrec.street2              := fp_street2;
    lv_invoiceheaderrec.billtocustomername   := fp_billtocustomername;
    lv_invoiceheaderrec.billtocustomernumber := fp_billtocustomernumber;
    lv_invoiceheaderrec.deltocustomername    := nvl(fp_deltocustomername, fp_billtocustomername);
    lv_invoiceheaderrec.deltocustomernumber  := nvl(fp_deltocustomernumber, fp_billtocustomernumber);
    lv_invoiceheaderrec.invoicetype          := fp_invoicetype;
    lv_invoiceheaderrec.invoicecomments      := fp_invoicecomments;
    lv_invoiceheaderrec.paythisamount        := fp_paythisammount;
    lv_invoiceheaderrec.prebillamount        := fp_prebillamount;
    lv_invoiceheaderrec.totalamountexclvat   := fp_totalamountexlvat;
    lv_invoiceheaderrec.roundingamount       := 0; --default 0
    lv_invoiceheaderrec.extraname1           := fp_extraname1;
    lv_invoiceheaderrec.extraname2           := fp_extraname2;
    lv_invoiceheaderrec.deltocity            := fp_city;
    lv_invoiceheaderrec.deltozipcode         := fp_zipcode;
    lv_invoiceheaderrec.deltostreet          := fp_street;
    lv_invoiceheaderrec.paymentdiscountdays  := nvl(fp_paymentdiscountdays, 0);
    lv_invoiceheaderrec.netpaymentdays       := nvl(fp_netpaymentdays, 0);
    --create invoiceheader
    gv_message := 'insert into invoiceheader';
    insert into invoiceheader values lv_invoiceheaderrec;
    --create invoiceheaderextrainfo
    create_invoiceheaderextrainfo(lv_invoiceheaderrec.invoiceheader_id,
                                  lv_invoiceheaderrec.invoicenumber);
    --create artransaction
    create_artransaction(lv_invoiceheaderrec);
    --commit
    commit;
    write_log('Succesfully ran Create invoiceheader number ' || fp_invoicenumber || ' created.');
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error create invoiceheader No_Data_Found ' || gv_message, 3);
        rollback;
        fp_messagenumber := 1;
      end;
    when ge_wrongvalue then
      begin
        write_log('Error create invoiceheader Wrong value ' || gv_message, 3);
        rollback;
        fp_messagenumber := 2;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create invoiceheader Dup_Val_On_Index ' || gv_message, 3);
        rollback;
        fp_messagenumber := 3;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create invoiceheader Others ' || gv_message, 3);
        rollback;
        fp_messagenumber := 4;
      end;
  end create_invoiceheader;

  procedure create_invoicelineproduct(fp_invoicelinerec in invoiceline%rowtype,
                                      fp_billingmethod  in invoicelineproduct.billingmethod%type) is
    lv_invoicelineproductrec invoicelineproduct%rowtype;
  begin
    --create invoicelineproduct
    gv_message := 'create invoicelineproduct';
    --init invoiceline product
    init_invoicelineproduct(lv_invoicelineproductrec);
    --try to get product id
    lv_invoicelineproductrec.product_link_id := get_product_id(fp_invoicelinerec.code);
    --fill other values
    lv_invoicelineproductrec.invoiceline_id := fp_invoicelinerec.invoiceline_id;
    lv_invoicelineproductrec.deliveredqty   := fp_invoicelinerec.billedqty;
    lv_invoicelineproductrec.billingmethod  := fp_billingmethod;
    --insert into invoicelineproduct
    insert into invoicelineproduct values lv_invoicelineproductrec;
  end create_invoicelineproduct;

  procedure create_invoicelinevarious(fp_invoicelinerec in invoiceline%rowtype,
                                      fp_percentage     in invoicelinevarious.percentage%type,
                                      fp_overamount     in invoicelinevarious.overamount%type) is
  begin
    --create invoicelinevarious
    gv_message := 'create invoicelinevarious';
    --check parameters
    if fp_percentage is null then
      gv_message := 'create invoicelinevarious for invoiceline type 18, VAT percentage must be filled, now its NULL';
      raise ge_wrongvalue;
    end if;
    if fp_overamount is null then
      gv_message := 'create invoicelinevarious for invoiceline type 18, VAT overamount must be filled, now its NULL';
      raise ge_wrongvalue;
    end if;
    --insert into invoicelinevarious
    insert into invoicelinevarious
      (invoiceline_id, transactiontype, transactiondate, percentage, timestamp, systemuser_id,
       overamount)
    values
      (fp_invoicelinerec.invoiceline_id, null, null, fp_percentage, sysdate, gv_defaultuserid,
       fp_overamount);
  end create_invoicelinevarious;

  procedure create_invoiceline(fp_messagenumber     out number,
                               fp_invoicenumber     in invoiceheader.invoicenumber%type,
                               fp_invoicelinetype   in invoicelinetype.invoicelinetype_id%type,
                               fp_linenumber        in invoiceline.linenumber%type, --line order
                               fp_invoicelinecode   in invoiceline.code%type,
                               fp_description       in invoiceline.description%type,
                               fp_amount            in invoiceline.amount%type,
                               fp_price             in invoiceline.price%type,
                               fp_billedqty         in invoiceline.billedqty%type,
                               fp_turnovergroupcode in turnovergroup.code%type,
                               fp_percentage        in invoicelinevarious.percentage%type, --only for type 18 VAT
                               fp_overamount        in invoicelinevarious.overamount%type, --only for type 18 VAT
                               fp_billingmethod     in invoicelineproduct.billingmethod%type default 0,
                               fp_taxgroupcode      in invoiceline.taxgroupcode%type default '2') is
    lv_invoicelinerec  invoiceline%rowtype;
    lv_turnovergroupid turnovergroup.turnovergroup_id%type;
  begin
    --check invoiceline param
    if fp_invoicelinetype not in (1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 18) then
      gv_message := 'fp_invoicelinetype not in (1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 18) it is ' ||
                    to_char(fp_invoicelinetype);
      raise ge_wrongvalue;
    end if;
    --init invoiceline, fill with default values
    init_invoiceline(lv_invoicelinerec);
    --get invoiceheader id
    lv_invoicelinerec.invoiceheader_id := get_invoiceheader_id(fp_invoicenumber);
    --copy parameters into lv_invoicelinerec
    gv_message                           := 'copy parameters into invoiceline';
    lv_invoicelinerec.invoicelinetype_id := fp_invoicelinetype;
    lv_invoicelinerec.linenumber         := nvl(fp_linenumber, fp_invoicelinetype);
    lv_invoicelinerec.code               := fp_invoicelinecode;
    lv_invoicelinerec.description        := nvl(substr(fp_description, 1, 40), fp_invoicelinecode);
    lv_invoicelinerec.amount             := fp_amount;
    lv_invoicelinerec.price              := fp_price;
    lv_invoicelinerec.billedqty          := fp_billedqty;
    lv_invoicelinerec.taxgroupcode       := fp_taxgroupcode;
    --get turnovergroup id
    lv_turnovergroupid                 := get_turnovergroup_id(fp_turnovergroupcode);
    lv_invoicelinerec.turnovergroup_id := lv_turnovergroupid;
    --create invoiceline
    gv_message := 'insert into invoiceline';
    insert into invoiceline values lv_invoicelinerec;
    if fp_invoicelinetype = 18 then
      --create invoiceline various, for VAT fp_invoicelinetype = 18
      create_invoicelinevarious(lv_invoicelinerec, fp_percentage, fp_overamount);
    else
      --create invoiceline product, fp_invoicelinetype <> 18
      create_invoicelineproduct(lv_invoicelinerec, fp_billingmethod);
    end if;
    --create artransaction detail
    create_artransactiondetail(lv_invoicelinerec, lv_turnovergroupid, fp_invoicenumber,
                               fp_turnovergroupcode);
    --commit
    commit;
    write_log('Succesfully ran Create invoiceline for invoicenumber ' || fp_invoicenumber ||
              ' created.');
    --all ok return 0
    fp_messagenumber := 0;
  exception
    when no_data_found then
      begin
        write_log('Error create invoiceline No_Data_Found ' || gv_message, 3);
        rollback;
        fp_messagenumber := 1;
      end;
    when ge_wrongvalue then
      begin
        write_log('Error create invoiceline Wrong value ' || gv_message, 3);
        rollback;
        fp_messagenumber := 2;
      end;
    when dup_val_on_index then
      begin
        write_log('Error create invoiceline Dup_Val_On_Index ' || gv_message, 3);
        rollback;
        fp_messagenumber := 3;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error create invoiceline Others ' || gv_message, 3);
        rollback;
        fp_messagenumber := 4;
      end;
  end create_invoiceline;

begin
  -- Initialization
  --get default user
  select s.systemuser_id
  into   gv_defaultuserid
  from   systemuser s
  where  s.username = gv_defaultusername;
exception
  when no_data_found then
    begin
      select min(s.systemuser_id) into gv_defaultuserid from systemuser s;
      write_log('Error pack_invoiceheader No_Data_Found system user ' || gv_defaultusername, 3);
    end;
end pack_invoiceheader;
/
create or replace package pack_isapexport is

  -- Author  : PVD
  -- Created : 09-07-2008
  -- Purpose : Process for the collection of financial stock transactions,
  --           that will be exported to an external bookkeeping system
  --           Function export will fill table ISAPEXPORT

  -- Main function for export into ISAPEXPORT
  -- 29-10-2008 update in insert into isapexport nvl(abs(round(fps_btbu, 2)),0),
  -- 21-11-2008 changes because of changes in abslog package
  -- 18-12-2008 RVI: Changes due to changed requirements concerning retrieval of ledger accounts
  -- 30-01-2009 RVI: Use quantity of derived transaction (WorkOrderStockTransaction, PackingNoteStockTransaction, PurchaseOrderStockTransaction)
  --            instead of main (total) StockTransaction.Quantity
  -- 02-02-2009 RVI: Added check for Exported flag in pricechange procedure
  -- 11-02-2009 RVI: Addew new procedure internalstockmovements
  -- 17-02-2009 RVI: Changed function getledgeraccountperkeycode due to changed requirements concerning retrieval of ledger accounts for key codes 'AG' and 'RM'
  -- 17-02-2009 RVI: Changed procedure returnofrenteditems. Take grade from transaction, not from order line
  -- 18-02-2009 RVI: Added new procedure moveitems2activestock
  -- 24-03-2009 RVI: Added procedures issuesalesitemsfromstockwo, issuerentalitemsfromstockwo to support also normal garment work orders
  -- 02-04-2009 RVI: Changed function gettext_t1bu and also procedures that call this function. Product code and size code should be separated with '/'
  -- 02-04-2009 OOP: changed lvndocno  for transaction that display only  x.stocktransaction_id and x.stockvalueavgpp_id. Put before them a character to help user.
  -- 29-04-2009 RVI: Changed function gettext_t1bu and also procedures that call this function. Product code and size code should be separated with '^'
  -- 29-04-2009 RVI: Changed procedure receiveinstockusingexternalpo. Rounding is done now before adding up the costs.
  -- 26-05-2009 RVI: (502682) Changed procedures moveitemsfromstock2truck, moveitems2activestock. Also retrieve pick list numbers from table PICKLISTSTOCKTRANSACTION
  -- 26-05-2009 RVI: (502682) Changed several procedures that process transactions with real document numbers.
  --                 Added a prefix to the document numbers to distinguish between them.
  --                 It concerned following procedures:
  --                   receiveinstockusingexternalpo, receiveinstockusinginternalpo,
  --                   issuesalesitemsfromstock, issuesalesitemsfromstockwo,
  --                   issuerentalitemsfromstock, issuerentalitemsfromstockwo, issueitems2otherstockroom,
  --                   receivereturneditems, returnofrenteditems.
  -- 06-07-2009 RVI: (502682) Changed procedure receiveinstockusinginternalpo, use prefix 'E' instead of 'C' to identify the internal po.
  -- 08-07-2009 RVI: (502682) Changed procedures issuesalesitemsfromstockw and issuerentalitemsfromstock. Also workorders for pool are supported now.
  --07.08.2009(todo 9302) OOP change pack_isapexport procedure-  in issuesalesitemsfromstockadded transaction 453 for lvntruckaccount
  --12.01.2012(todo 20070) VSE added the process start timestamp as parameter to the export and to select procedures
  --06.09.2013(todo 23082) BVA added transaction 102 and 411 to internal PO
  --------------------------------------------------------------------------------
function export(fpnplantprocessid plantprocess.plantprocess_id%type,fpprocessstarttimestamp stocktransaction.timestamp%type default sysdate) return number;



end pack_isapexport;




/
create or replace package body pack_isapexport is
  -- Global variables
  -- General
  gvnsystemuserid           systemuser.systemuser_id%type;
  gvnplantid                plant.plant_id%type;
  gvsmsg                    abslogprocessjobline.message%type;
  gvnabslogprocessjobid     abslogprocessjob.abslogprocessjob_id%type;
  gvnabslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
  gveerror_initialization exception;
  gvnrowsprocessed number;
  -- System setting
  gvsexpcompanyfibuhts         systemsetting.value%type;
  gvsexptransitstockfibuhts    systemsetting.value%type;
  gvsexpsuspaccsupplfibuhts    systemsetting.value%type;
  gvsexpsuspaccdelcostfibuhts  systemsetting.value%type;
  gvsexpstockdiffaccfibuhts    systemsetting.value%type;
  gvsexpstockscrapaccfibuhts   systemsetting.value%type;
  gvsexpacctransitstockfibuhts systemsetting.value%type;

  -- Internal procedures/functions
  -- Begin general procedures/functions

  procedure initialization(fpnplantprocessid plantprocess.plantprocess_id%type) is
  begin
    gvnabslogprocessjobid := null;
    gvnrowsprocessed      := 0;
    select pp.plant_id, pp.systemuser_id
    into   gvnplantid, gvnsystemuserid
    from   plantprocess pp
    where  pp.plantprocess_id = fpnplantprocessid;
  exception
    when others then
      raise gveerror_initialization;
  end initialization;

  procedure write_abslogprocessjob(fpnplantprocessid in plantprocess.plantprocess_id%type) is
  begin
    if gvnabslogprocessjobid is null then
      begin
        gvnabslogprocessjobid     := abslogwrite.abslogprocessjob_write(gvnplantid, sysdate, null,
                                                                        null, fpnplantprocessid,
                                                                        gvnsystemuserid);
        gvnabslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gvnabslogprocessjobid,
                                                                            'ISAP Export',
                                                                            gvnsystemuserid);
      end;
    else
      begin
        abslogwrite.abslogprocessjob_update(gvnabslogprocessjobid, sysdate, gvnsystemuserid);
        dbms_output.put_line('ISAP Export is ready please check logs.');
      end;
    end if;
  end write_abslogprocessjob;

  procedure write_abslogprocessjobline(fpnmessage  abslogprocessjobline.message%type,
                                       fpnpriority abslogprocessjobline.priority%type default 1) is
  begin
    /*  fpnpriority
    1 = Message  -> Default
    2 = Warning
    3 = Error
    4 = (not used)
    5 = Debug info */
    abslogwrite.abslogprocessjobline_write(gvnabslogprocessjobpartid, fpnpriority, fpnmessage,
                                           gvnsystemuserid);
  end write_abslogprocessjobline;

  procedure initial_validations is
    -- Check all settings before starting
    lvsmsg abslogprocessjobline.message%type;
  begin
    write_abslogprocessjobline('initial_validations start');
    -- Determine company 1
    lvsmsg := 'No company specified for system setting EXPCOMPANYFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexpcompanyfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPCOMPANYFIBUHTS';
    -- Determine transit stockroom code 2
    lvsmsg := 'No transit stockroom code specified for system setting EXPTRANSITSTOCKFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexptransitstockfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPTRANSITSTOCKFIBUHTS';
    -- Determine suspense account supplier 3
    lvsmsg := 'No supplier suspense account specified for system setting EXPSUSPACCSUPPLFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexpsuspaccsupplfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPSUSPACCSUPPLFIBUHTS';
    --  Determine suspense account for transport costs 4
    lvsmsg := 'No suspense account for transport costs specified for system setting EXPSUSPACCDELCOSTFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexpsuspaccdelcostfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPSUSPACCDELCOSTFIBUHTS';
    --  Determine account for stock corrections 5
    lvsmsg := 'No account for stock corrections specified for system setting EXPSTOCKDIFFACCFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexpstockdiffaccfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPSTOCKDIFFACCFIBUHTS';
    --  Determine account for costs of items scrapped 6
    lvsmsg := 'No account for costs of scrapped items specified for system setting EXPSTOCKSCRAPACCFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexpstockscrapaccfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPSTOCKSCRAPACCFIBUHTS';
    --  Determine suspense account for transit stock 7
    lvsmsg := 'No suspense account for transit stock specified for system setting EXPACCTRANSITSTOCKFIBUHTS since it does not exist. Data collection process stopped!';
    select s.value
    into   gvsexpacctransitstockfibuhts
    from   systemsetting s
    where  s.plant_id = gvnplantid
    and    s.name = 'EXPACCTRANSITSTOCKFIBUHTS';
    write_abslogprocessjobline('initial_validations end');
  exception
    when no_data_found then
      begin
        write_abslogprocessjobline(lvsmsg, 3);
        write_abslogprocessjobline('initial_validations end');
        raise;
      end;
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('initial_validations end');
        raise;
      end;
  end initial_validations;

  function getledgeraccountsperproduct(fpnproductid    in product.product_id%type,
                                       fpsaccount_type in stocktype.code%type,
                                       fpsledgertype   in ledgeraccnttype.code%type default 'BEST')
    return number is
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvsproductcode  product.code%type;
  begin
    select la.accountnumber
    into   lvnstockaccount
    from   ledgeraccounts la
    where  la.ledgeraccounts_id =
           (select lp.ledgeraccounts_id
            from   ledgeraccntsperproduct lp, stocktype st, ledgeraccnttype lat
            where  lp.product_id = fpnproductid
            and    st.stocktype_id = lp.stocktype_id
            and    lat.ledgeraccnttype_id = lp.ledgeraccnttype_id
            and    st.code = fpsaccount_type
            and    lat.code = nvl(fpsledgertype, 'BEST'));
    return lvnstockaccount;
  exception
    when no_data_found then
      begin
        begin
          select p.code into lvsproductcode from product p where p.product_id = fpnproductid;
        exception
          when no_data_found then
            begin
              gvsmsg := 'Product_link_id product_id not found ' || to_char(fpnproductid);
              raise;
            end;
        end;
        gvsmsg := 'No ledger account ' || fpsaccount_type || ' type ' || nvl(fpsledgertype, 'BEST') ||
                  ' found for product ' || lvsproductcode;
        raise;
      end;
    when others then
      begin
        begin
          select p.code into lvsproductcode from product p where p.product_id = fpnproductid;
        exception
          when no_data_found then
            begin
              gvsmsg := 'Product_link_id product_id not found ' || to_char(fpnproductid);
              raise;
            end;
        end;
        write_abslogprocessjobline(sqlerrm, 3);
        gvsmsg := 'Error getting ledger account : ' || fpsaccount_type || ' ' ||
                  nvl(fpsledgertype, 'BEST') || ' for product ' || lvsproductcode;
        raise;
      end;
  end getledgeraccountsperproduct;

  -- RVI 18-12-2008 BEGIN
  function getledgeraccountperkeycode(fpnreasoncodeid in reasoncode.reasoncode_id%type,
                                      fpnproductid    in product.product_id%type,
                                      fpsaccount_type in stocktype.code%type) return number is
    lvnaccount     ledgeraccounts.accountnumber%type;
    lvsproductcode product.code%type;
    lvskeycode     extstocktranstype.keycode%type;
    lvsreasoncode  reasoncode.code%type;
    lvsledgertype  ledgeraccnttype.code%type;
    invalidkeycode exception;
    inactivekeycode exception;

    cursor get_keycode is
      select ex.keycode
      from   reasoncode rs, extstocktranstype ex
      where  ex.extstocktranstype_id = rs.extstocktranstype_id
      and    rs.reasoncode_id = fpnreasoncodeid;

  begin
    -- Determine key code linked to reason code
    for kc_rec_ in get_keycode loop
      lvskeycode := kc_rec_.keycode;
    end loop;
    if (lvskeycode is null) then
      raise invalidkeycode;
    end if;
    -- determine account
    case lvskeycode
      when 'AB' then
        lvsledgertype := 'WESV';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'AG' then
        -- RVI 17-02-2009 BEGIN
        --lvsledgertype := 'GWG';
        lvsledgertype := 'WESS';
        -- RVI 17-02-2009 END
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'AR' then
        lvsledgertype := 'WESR';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'AS' then
        -- Account := value of system setting EXPSTOCKSCRAPACCFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpstockscrapaccfibuhts;
      when 'AV' then
        lvsledgertype := 'WESV';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'AW' then
        lvsledgertype := 'ABW';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'AX' then
        lvsledgertype := 'WESV';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'AY' then
        lvsledgertype := 'GWG';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'EG' then
        -- Account := value of system setting EXPACCTRANSITSTOCKFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpacctransitstockfibuhts;
      when 'I+' then
        -- Account := value of system setting EXPSTOCKDIFFACCFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpstockdiffaccfibuhts;
      when 'I-' then
        -- Account := value of system setting EXPSTOCKDIFFACCFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpstockdiffaccfibuhts;
      when 'RE' then
        lvsledgertype := 'WESV';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'RM' then
        -- RVI 17-02-2009 BEGIN
        --lvsledgertype := 'GWG';
        lvsledgertype := 'WESS';
        -- RVI 17-02-2009 END
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'RR' then
        lvsledgertype := 'WESR';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'RT' then
        -- Account := value of system setting EXPACCTRANSITSTOCKFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpacctransitstockfibuhts;
      when 'RV' then
        lvsledgertype := 'WESV';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'RX' then
        lvsledgertype := 'WESV';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'RY' then
        lvsledgertype := 'GWG';
        lvnaccount    := getledgeraccountsperproduct(fpnproductid, fpsaccount_type, lvsledgertype);
      when 'SV' then
        begin
          -- Not used
          lvsledgertype := 'N/A';
          lvnaccount    := null;
          raise inactivekeycode;
        end;
      when 'UB' then
        -- Account := value of system setting EXPACCTRANSITSTOCKFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpacctransitstockfibuhts;
      when 'UD' then
        -- Account := value of system setting EXPSTOCKSCRAPACCFIBUHTS
        lvsledgertype := 'FIXED';
        lvnaccount    := gvsexpstockscrapaccfibuhts;
      when 'UF' then
        -- Account := value of system setting EXPACCTRANSITSTOCKFIBUHTS
        lvnaccount := gvsexpacctransitstockfibuhts;
      when 'UX' then
        begin
          -- Not used
          lvsledgertype := 'N/A';
          lvnaccount    := null;
          raise inactivekeycode;
        end;
      when 'ZG' then
        -- Account := value of system setting EXPSUSPACCDELCOSTFIBUHTS
        lvsledgertype := '';
        lvnaccount    := gvsexpsuspaccsupplfibuhts;
      when 'ZU' then
        begin
          -- Not used
          lvsledgertype := 'N/A';
          lvnaccount    := null;
          raise inactivekeycode;
        end;
    end case;
    return lvnaccount;
  exception
    when invalidkeycode then
      begin
        begin
          select r.code
          into   lvsreasoncode
          from   reasoncode r
          where  r.reasoncode_id = fpnreasoncodeid;
        exception
          when no_data_found then
            begin
              gvsmsg := 'Reasoncode_id not found ' || to_char(fpnreasoncodeid);
              raise;
            end;
        end;
        gvsmsg := 'No keycode found for ' || lvsreasoncode;
        raise;
      end;
    when inactivekeycode then
      begin
        gvsmsg := 'No ledgeraccount defined for keycode' || lvskeycode;
        raise;
      end;
    when others then
      begin
        begin
          select r.code
          into   lvsreasoncode
          from   reasoncode r
          where  r.reasoncode_id = fpnreasoncodeid;
        exception
          when no_data_found then
            begin
              gvsmsg := 'Reasoncode_id not found ' || to_char(fpnreasoncodeid);
              raise;
            end;
        end;
        write_abslogprocessjobline(sqlerrm, 3);
        gvsmsg := 'Error getting ledgeraccount : reason code = ' || lvsreasoncode ||
                  ' ledgeraccounttype = ' || lvsledgertype || ' for product ' || lvsproductcode;
        raise;
      end;
  end getledgeraccountperkeycode;
  -- RVI 18-12-2008 END

  function gettext_t1bu(fpnstocktransid  in stocktransaction.stocktransaction_id%type,
                        fpsstockroomcode in stockroom.code%type default null,
                        fpsproductsize   in varchar2 default null,
                        fpnreasoncodeid  in reasoncode.reasoncode_id%type default null)
    return varchar2 is
    lvsstockroomcode   stockroom.code%type;
    lvsproductsizecode varchar2(25);
    lvstransactioncode extstocktranstype.code%type;
    lvs_t1bu           isapexport.t1bu%type;
  begin
    if fpsstockroomcode is null and fpsproductsize is null then
      begin
        -- Determine stockroom code
        gvsmsg := 'stockroom code';
        select mag.code
        into   lvsstockroomcode
        from   stocktransaction st, stockreservationpergrade sr, stockdefinitionperitem sd,
               stockroom mag
        where  sr.stockreservationpergrade_id = st.stockreservationpergrade_id
        and    sd.stockdefinitionperitem_id = sr.stockdefinitionperitem_id
        and    mag.stockroom_id = sd.stockroom_id
        and    st.stocktransaction_id = fpnstocktransid;
        --Determine product/size code
        gvsmsg := 'product/size code';
        -- RVI 02-04-2009 BEGIN
        --select p.code || s.code
        select p.code || '^' || s.code
        -- RVI 02-04-2009 END
        into   lvsproductsizecode
        from   stocktransaction st, stockreservationpergrade sr, stockdefinitionperitem sd,
               product p, sizedefinition s
        where  sr.stockreservationpergrade_id = st.stockreservationpergrade_id
        and    sd.stockdefinitionperitem_id = sr.stockdefinitionperitem_id
        and    p.product_id = sd.product_id
        and    s.sizedefinition_id = sd.sizedefinition_id
        and    st.stocktransaction_id = fpnstocktransid;
        -- Determine transaction code
        gvsmsg := 'transaction code';
        if fpnreasoncodeid is null then
          select ex.keycode
          into   lvstransactioncode
          from   stocktransaction st, reasoncode rs, extstocktranstype ex
          where  rs.reasoncode_id = st.reasoncode_id
          and    ex.extstocktranstype_id = rs.extstocktranstype_id
          and    st.stocktransaction_id = fpnstocktransid;
        else
          select ex.keycode
          into   lvstransactioncode
          from   reasoncode rs, extstocktranstype ex
          where  rs.reasoncode_id = fpnreasoncodeid
          and    ex.extstocktranstype_id = rs.extstocktranstype_id;
        end if; --fpnreasoncodeid is null
        lvs_t1bu := substr(lvsstockroomcode || '^' || lvsproductsizecode, 1, 27) || '^' ||
                   -- RVI 23-07-2008 BEGIN
                   --            substr(lvstransactioncode, 2);
                    substr(lvstransactioncode, 1, 2);
        -- RVI 23-07-2008 END
      end;
    else
      begin
        -- Determine transaction code
        gvsmsg := 'transaction code';
        if fpnreasoncodeid is null then
          select ex.keycode
          into   lvstransactioncode
          from   stocktransaction st, reasoncode rs, extstocktranstype ex
          where  rs.reasoncode_id = st.reasoncode_id
          and    ex.extstocktranstype_id = rs.extstocktranstype_id
          and    st.stocktransaction_id = fpnstocktransid;
        else
          select ex.keycode
          into   lvstransactioncode
          from   reasoncode rs, extstocktranstype ex
          where  rs.reasoncode_id = fpnreasoncodeid
          and    ex.extstocktranstype_id = rs.extstocktranstype_id;
        end if; --fpnreasoncodeid is null
        lvs_t1bu := substr(fpsstockroomcode || '^' || fpsproductsize, 1, 27) || '^' ||
                    substr(lvstransactioncode, 1, 2);
      end;
    end if;
    return lvs_t1bu;
  exception
    when no_data_found then
      begin
        gvsmsg := 'No data found getting ' || gvsmsg || ' for t1bu info for stocktransaction id: ' ||
                  to_char(fpnstocktransid);
        raise;
      end;
    when others then
      begin
        gvsmsg := 'Error getting t1bu info ' || sqlerrm || ' ';
        raise;
      end;
  end gettext_t1bu;

  function getcostcentercode(fpndistributionpointid distributionpoint.distributionpoint_id%type)
    return varchar2 is
    lvscostcenter costcenter.code%type;
  begin
    select cc.code
    into   lvscostcenter
    from   costcenter cc, distributionpoint dp
    where  cc.costcenter_id = dp.costcenter_id
    and    dp.distributionpoint_id = fpndistributionpointid;
    if(length(lvscostcenter)>5) then
           lvscostcenter :=null;
    end if;
    return lvscostcenter;
  exception
    when no_data_found then
      begin
        gvsmsg := 'No costcenter found for distributionpoint id: ' || fpndistributionpointid;
        raise;
      end;
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        gvsmsg := 'Error getting costcenter for distributionpoint id: ' || fpndistributionpointid;
        raise;
      end;
  end getcostcentercode;

  function gettansportpercentage(fpnsupplierid supplier.supplier_id%type,
                                 fpnproductid  product.product_id%type,
                                 fpnsizeid     sizedefinition.sizedefinition_id%type) return number is
    lvntransportchargepercent supplierproduct.transportchargepercentage%type;
  begin
    select nvl(max(sp.transportchargepercentage), 0)
    into   lvntransportchargepercent
    from   supplierproduct sp, productsizepersupproduct pssp
    where  pssp.supplierproduct_id = sp.supplierproduct_id
    and    sp.supplier_id = fpnsupplierid
    and    pssp.product_id = fpnproductid
    and    pssp.sizedefinition_id = fpnsizeid;
    return lvntransportchargepercent;
  exception
    when no_data_found then
      begin
        gvsmsg := 'No data getting transportchargepercent for supplier/product/size ID''s' ||
                  fpnsupplierid || '/' || fpnproductid || '/' || fpnsizeid;
        raise;
      end;
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        gvsmsg := 'Error getting transportchargepercent for supplier/product/size ID''s' ||
                  fpnsupplierid || '/' || fpnproductid || '/' || fpnsizeid;
        raise;
      end;
  end gettansportpercentage;

  procedure write_isapexport(fps_f#bu          in isapexport.f#bu%type,
                             fps_jjbu          in isapexport.jjbu%type,
                             fps_mmbu          in isapexport.mmbu%type,
                             fps_babu          in isapexport.babu%type,
                             fps_b#bu          in isapexport.b#bu%type,
                             fps_dtbu          in isapexport.dtbu%type,
                             fps_t1bu          in isapexport.t1bu%type,
                             --fps_kstbu         in isapexport.kstbu%type,
                             fps_kstbu         in costcenter.code%type,
                             fps_zf3bu         in isapexport.zf3bu%type,
                             fps_btbu          in isapexport.btbu%type,
                             fps_ktbu          in isapexport.ktbu%type,
                             fps_ktgbu         in isapexport.ktgbu%type,
                             fps_shbu          in isapexport.shbu%type,
                             fpnbusinessunitid in isapexport.businessunit_id%type) is
                             lv_kstbu isapexport.kstbu%type;
  begin
      -- RVI 15-02-2013 BEGIN
    if (length(fps_kstbu) <= 5) then
      lv_kstbu := fps_kstbu;
    else
      lv_kstbu := null;
    end if;
    -- RVI 15-02-2013 END
    insert into isapexport
    -- RVI 23-07-2008 BEGIN
    --(isapexport_id, businessunit_id, creationtimestamp, exporttimestamp, timestamp, f#bu, jjbu,
      (isapexport_id, businessunit_id, creationtimestamp, timestamp, f#bu, jjbu,
       -- RVI 23-07-2008 END
       mmbu, babu, b#bu, dtbu, t1bu, kstbu, zf3bu, btbu, ktbu, ktgbu, shbu)
    values
    -- RVI 23-07-2008 BEGIN
    --(seq_isapexport.nextval, fpnbusinessunitid, sysdate, sysdate, sysdate, substr(fps_f#bu, 1, 3),
      (seq_isapexport.nextval, fpnbusinessunitid, sysdate, sysdate, substr(fps_f#bu, 1, 3),
       -- RVI 23-07-2008 END
       substr(fps_jjbu, 1, 4), substr(fps_mmbu, 1, 2), substr(fps_babu, 1, 3),
       substr(fps_b#bu, 1, 10), substr(fps_dtbu, 1, 8), substr(fps_t1bu, 1, 30),
    -- RVI 15-02-2013 BEGIN
    -- substr(fps_kstbu, 1, 5), substr(fps_zf3bu, 1, 10), nvl(abs(round(fps_btbu, 2)), 0),
       substr(lv_kstbu, 1, 5), substr(fps_zf3bu, 1, 10), nvl(abs(round(fps_btbu, 2)), 0),
    -- RVI 15-02-2013 END
       substr(fps_ktbu, 1, 10), substr(fps_ktgbu, 1, 10), substr(fps_shbu, 1, 1));
  end write_isapexport;

  procedure updatetransaction2exported(fpnstocktransid in stocktransaction.stocktransaction_id%type) is
    lvexportedyn varchar2(1);
    lveerror_exported exception;
  begin
    select st.exported
    into   lvexportedyn
    from   stocktransaction st
    where  st.stocktransaction_id = fpnstocktransid;
    if lvexportedyn <> 'Y' then
      begin
        update stocktransaction st
        set    st.exported = 'Y'
        where  st.stocktransaction_id = fpnstocktransid;
        gvnrowsprocessed := sql%rowcount + gvnrowsprocessed;
      end;
    else
      begin
        raise lveerror_exported;
      end;
    end if;
  exception
    when lveerror_exported then
      begin
        gvsmsg := 'Error : Transaction id was already updated !?: ' || fpnstocktransid;
        raise;
      end;
    when no_data_found then
      begin
        gvsmsg := 'No data found updatetransaction2exported transaction id: ' || fpnstocktransid;
        raise;
      end;
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        gvsmsg := 'Error during updatetransaction2exported for transaction id: ' || fpnstocktransid;
        raise;
      end;
  end updatetransaction2exported;

  -- End general procedures/functions
  -- Start export procedures

  procedure receiveinstockusingexternalpo(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu                  isapexport.babu%type;
    lvs_t1bu                  isapexport.t1bu%type;
    lvs_kstbu                 isapexport.kstbu%type;
    lvs_zf3bu                 isapexport.zf3bu%type;
    lvs_btbu                  isapexport.btbu%type;
    lvs_ktbu                  isapexport.ktbu%type;
    lvs_ktgbu                 isapexport.ktgbu%type;
    lvs_shbu                  isapexport.shbu%type;
    lvnaccnt_type             stocktype.code%type;
    lvntransportchargepercent supplierproduct.transportchargepercentage%type;
    lvnstockaccount           ledgeraccounts.accountnumber%type;
    lvnnetvalue               number;
    lvngrossvalue             number;
    lvntransportcosts         number;
    lvndocno                  varchar2(10);
    lvnextdocno               varchar2(10);
  begin
    write_abslogprocessjobline('receiveinstockusingexternalpo start');
    for x in (select st.stocktransaction_id, po.supplier_id, pol.product_link_id,
                     pol.sizedefinition_link_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     st.businessunit_id, max(bu.code) businessunitcode,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month, po.purchaseordernumber,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date,
                     nvl((select q.newgarment
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = pol.requestedgrade_id), 'N') newgarment,
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from  qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     -- RVI 17-02-2009 END
                     pol.purchaseprice, sum(pst.quantity) quantity
              from   purchaseorderheader po, purchaseorderstocktransaction pst,
                     v_stocktransactions2export st, purchaseorderline pol, businessunit bu
              where  pst.stocktransaction_id = st.stocktransaction_id
              and    pol.purchaseorderline_id = pst.purchaseorderline_id
              and    po.purchaseorderheader_id = pol.purchaseorderheader_id
              and    st.businessunit_id = bu.businessunit_id
              and    po.purchaseordertype = 0
              and    st.transactiontype_id in (12, 400, 102)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, po.supplier_id, pol.product_link_id,
                        pol.sizedefinition_link_id,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        st.businessunit_id, st.transactiondate, po.purchaseordernumber,
                        -- RVI 17-02-2009 BEGIN
                        -- pol.requestedgrade_id, pol.purchaseprice
                        st.qualitygrade_id, st.qualitygrade_id, pol.purchaseprice
                        -- RVI 17-02-2009 END
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        if length('Z'||x.purchaseordernumber) > 10 then
          lvndocno := substr('Z'||x.purchaseordernumber, length('Z'||x.purchaseordernumber) - 9, 10);
        else
          lvndocno := 'Z'||x.purchaseordernumber;
        end if;
        lvnextdocno := lvndocno;
        lvs_babu    := 'LAG';
        lvs_t1bu    := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu   := null; --costcenter
        lvs_zf3bu   := lvnextdocno;
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type             := '01';
            -- RVI 29-04-2009 BEGIN
            --lvnnetvalue               := x.purchaseprice * x.quantity;
            lvnnetvalue               := round((x.purchaseprice * x.quantity),2);
            -- RVI 29-04-2009 END
            lvntransportchargepercent := gettansportpercentage(x.supplier_id, x.product_link_id,
                                                               x.sizedefinition_link_id);
            -- RVI 29-04-2009 BEGIN
            --lvntransportcosts         := lvnnetvalue * lvntransportchargepercent / 100;
            lvntransportcosts         := round((lvnnetvalue * lvntransportchargepercent / 100),2);
            -- RVI 29-04-2009 END
            lvngrossvalue             := lvnnetvalue + lvntransportcosts;
          end;
        else
          begin
            lvnaccnt_type     := '02';
            -- RVI 17-02-2009 BEGIN
            if (x.defectitem = 'Y') then
              lvnaccnt_type := '03';
            end if;
            -- RVI 17-02-2009 END
            lvnnetvalue       := 0;
            lvntransportcosts := 0;
            lvngrossvalue     := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_link_id, lvnaccnt_type);
        --create line transport costs(when needed)
        if lvntransportcosts > 0 then
          begin
            lvs_btbu := lvntransportcosts;
            lvs_ktbu := gvsexpsuspaccdelcostfibuhts; --suppense account transport costs
            -- RVI 18-12-2008 BEGIN
            --lvs_ktgbu := gvsexpsuspaccsupplfibuhts; --suspense supplier account
            lvs_ktgbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_link_id,
                                                    lvnaccnt_type);
            -- RVI 18-12-2008 END
            lvs_shbu := 'H';
            pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu,
                                             lvndocno, x.document_date, lvs_t1bu, lvs_kstbu,
                                             lvs_zf3bu, lvs_btbu, lvs_ktbu, lvs_ktgbu, lvs_shbu,
                                             x.businessunit_id);
          end;
        end if; --lvntransportcosts > 0
        --create line increase stock value
        lvs_btbu := lvngrossvalue;
        lvs_ktbu := lvnstockaccount;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktgbu := gvsexpsuspaccsupplfibuhts; --suspense supplier account
        lvs_ktgbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_link_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line suspense account supplier
        lvs_btbu := lvnnetvalue;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktbu  := gvsexpsuspaccsupplfibuhts; --suspense supplier account
        lvs_ktbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_link_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('receiveinstockusingexternalpo end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('receiveinstockusingexternalpo end');
        raise;
      end;
  end receiveinstockusingexternalpo;

  procedure receiveinstockusinginternalpo(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
    lvnextdocno     varchar2(10);
  begin
    write_abslogprocessjobline('receiveinstockusinginternalpo start');
    for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, po.supplier_id,
                     pol.product_link_id, pol.sizedefinition_link_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     st.businessunit_id, max(bu.code) businessunitcode,
                     to_char(st.transactiondate, 'YYYY') year, st.transactiondate,
                     to_char(st.transactiondate, 'MM') month, po.purchaseordernumber,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date,
                     nvl((select q.newgarment
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = pol.requestedgrade_id), 'N') newgarment,
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from  qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     -- RVI 17-02-2009 END
                     sum(pst.quantity) quantity
              from   purchaseorderheader po, purchaseorderstocktransaction pst,
                     v_stocktransactions2export st, purchaseorderline pol, businessunit bu
              where  pst.stocktransaction_id = st.stocktransaction_id
              and    pol.purchaseorderline_id = pst.purchaseorderline_id
              and    po.purchaseorderheader_id = pol.purchaseorderheader_id
              and    st.businessunit_id = bu.businessunit_id
              and    po.purchaseordertype = 1
              and    st.transactiontype_id in (12, 400, 411, 102)
              and    st.timestamp <pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.stockreservationpergrade_id, po.supplier_id,
                        pol.product_link_id, pol.sizedefinition_link_id,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        st.businessunit_id, st.transactiondate, po.purchaseordernumber,
                        -- RVI 17-02-2009 BEGIN
                        -- pol.requestedgrade_id, pol.purchaseprice
                        st.qualitygrade_id, pol.purchaseprice
                        -- RVI 17-02-2009 END
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        if (length('E'||x.purchaseordernumber) > 10) then
          lvndocno := substr('E'||x.purchaseordernumber, length('E'||x.purchaseordernumber) - 9, 10);
        else
          lvndocno := 'E'||x.purchaseordernumber;
        end if;
        select max(substr(to_char(wo.workordernumber),1,10))
        into   lvnextdocno
        from   workorder wo
        where  wo.origin = 8
              -- RVI 23-07-2008 BEGIN
              --and    wo.referencenumber = x.purchaseordernumber;
        and    wo.referencenumber = to_char(x.purchaseordernumber);
        -- RVI 23-07-2008 END
        if (length('C'||lvnextdocno) > 10) then
          lvnextdocno := substr('C'||lvnextdocno, length('C'||lvnextdocno) - 9, 10);
        end if;
        lvs_babu  := 'LAG';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := lvnextdocno;
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            lvnaccnt_type := '02';
            -- RVI 17-02-2009 BEGIN
            if (x.defectitem = 'Y') then
              lvnaccnt_type := '03';
            end if;
            -- RVI 17-02-2009 END
            lvnnetvalue   := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_link_id, lvnaccnt_type);
        --create line increase new/used stock
        lvs_btbu := lvnnetvalue;
        lvs_ktbu := lvnstockaccount;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktgbu := gvsexpacctransitstockfibuhts; --supp_accnt_transit
        lvs_ktgbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_link_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line reduce transit stock
        lvs_btbu := lvnnetvalue;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktbu  := gvsexpacctransitstockfibuhts; --supp_accnt_transit
        lvs_ktbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_link_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('receiveinstockusinginternalpo end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('receiveinstockusinginternalpo end');
        raise;
      end;
  end receiveinstockusinginternalpo;

  procedure receiveinstockwithoutusingpo(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('receiveinstockwithoutusingpo start');
    for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (10, 401, 402)
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.businessunit_id, st.stockreservationpergrade_id,
                        st.transactiondate, st.stockroom, p.code, p.product_id, s.code,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        st.qualitygrade_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        lvndocno  := 'B'|| x.stocktransaction_id;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        --create line increase new/used/defect stock
        lvs_btbu := lvnnetvalue;
        lvs_ktbu := lvnstockaccount;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktgbu := gvsexpacctransitstockfibuhts; --susp_accnt_transit
        lvs_ktgbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line reduce transit stock
        lvs_btbu := lvnnetvalue;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktbu  := gvsexpacctransitstockfibuhts; --susp_accnt_transit
        lvs_ktbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('receiveinstockwithoutusingpo end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('receiveinstockwithoutusingpo end');
        raise;
      end;
  end receiveinstockwithoutusingpo;

  procedure receiveinstockmovedfromtruck(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvntruckaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('receiveinstockmovedfromtruck start');
    for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (415, 416)
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.businessunit_id, st.stockreservationpergrade_id,
                        st.transactiondate, st.stockroom, p.code, p.product_id, s.code,
                        st.qualitygrade_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        lvndocno  := 'T'|| x.stocktransaction_id;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        --truck account
        lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        --create line increase new/used/defect stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvntruckaccount;
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line reduce value for truck stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvntruckaccount;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('receiveinstockmovedfromtruck end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('receiveinstockmovedfromtruck end');
        raise;
      end;
  end receiveinstockmovedfromtruck;

  procedure issuesalesitemsfromstock(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwesv_account ledgeraccounts.accountnumber%type;
    lvngwg_account  ledgeraccounts.accountnumber%type;
    lvntruckaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('issuesalesitemsfromstock start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     wol.sizedefinition_link_id sizedefinition_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     case
                       when wo.origin = 10 then
                        'MO'
                       when wo.origin = 6 and wo.driversales = 'Y' and wo.mountingordersales = 'N' then
                        'DSN'
                       when wo.origin = 6 and wo.driversales = 'N' and wo.mountingordersales = 'N' then
                        'SN'
                     end abs_document_type, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') newgarment,
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     -- RVI 17-02-2009 END
                     nvl((select q.defectitem
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') defectitem,
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     -- RVI 17-02-2009 END
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin in (6, 10) --(sales / mounting order)
              and    st.transactiontype_id in (50, 450, 453, 454)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber, wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        st.stockreservationpergrade_id, wo.origin, wo.driversales,
                        -- RVI 17-02-2009 BEGIN
                        -- wo.mountingordersales, wol.requestedgrade_id, wol.product_link_id,
                        wo.mountingordersales, st.qualitygrade_id, wol.product_link_id,
                        -- RVI 17-02-2009 END
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        wol.sizedefinition_link_id
              union
              select st.stocktransaction_id, pn.notenumber, pn.distributionpoint_id, pnl.product_id,
                     pnl.sizedefinition_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     'PN' abs_document_type, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(pst.quantity) quantity
              from   packingnotestocktransaction pst, v_stocktransactions2export st,
                     packingnoteline pnl, packingnote pn
              where  st.stocktransaction_id = pst.stocktransaction_id
              and    pnl.packingnoteline_id = pst.packingnoteline_id
              and    pn.packingnote_id = pnl.packingnote_id
              and    st.transactiontype_id in (50, 450, 453, 454)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, pn.notenumber, pn.distributionpoint_id,
                        st.transactiontype_id, st.qualitygrade_id, st.businessunit_id,
                        st.transactiondate, st.stockreservationpergrade_id, pnl.product_id,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        pnl.sizedefinition_id
              order  by 1) loop
      begin
        ----begin common columns
        -- Document Number, depending on type
        if (x.abs_document_type = 'PN') then
          if (length(x.ordernumber) > 10) then
            lvndocno := substr(x.ordernumber, length(x.ordernumber) - 9, 10);
          else
            lvndocno := x.ordernumber;
          end if;
        end if;
        if (x.abs_document_type in ('SN','DSN')) then
          if (length('V'||x.ordernumber) > 10) then
            lvndocno := substr('V'||x.ordernumber, length('V'||x.ordernumber) - 9, 10);
          else
            lvndocno := 'V'||x.ordernumber;
          end if;
        end if;
        if (x.abs_document_type = ('MO')) then
          if (length('M'||x.ordernumber) > 10) then
            lvndocno := substr('M'||x.ordernumber, length('M'||x.ordernumber) - 9, 10);
          else
            lvndocno := 'M'||x.ordernumber;
          end if;
        end if;
        lvs_babu  := 'LAG';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu := getcostcentercode(x.distributionpoint_link_id);
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 BEGIN
        --lvnwesv_account := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'WESV');
        --lvngwg_account  := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'GWG');
        lvnwesv_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        lvngwg_account  := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        --truck account
        if x.transactiontype_id in (450,453, 454) then
          lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        else
          lvntruckaccount := null;
        end if;
        --create line increase value of goods sold(that were delivered)
        lvs_btbu := lvnnetvalue;
        if x.abs_document_type = 'PN' then
          lvs_ktbu := lvngwg_account;
        else
          lvs_ktbu := lvnwesv_account;
        end if;
        if x.transactiontype_id in (450, 453, 454) then
          lvs_ktgbu := lvntruckaccount;
        else
          lvs_ktgbu := lvnstockaccount;
        end if;
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to decrease value from either new/used stock
        if x.abs_document_type = 'PN' then
          lvs_ktgbu := lvngwg_account;
        else
          lvs_ktgbu := lvnwesv_account;
        end if;
        if x.transactiontype_id in (450, 453, 454) then
          lvs_ktbu := lvntruckaccount;
        else
          lvs_ktbu := lvnstockaccount;
        end if;
        lvs_shbu := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('issuesalesitemsfromstock end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('issuesalesitemsfromstock end');
        raise;
      end;
  end issuesalesitemsfromstock;

  procedure issuerentalitemsfromstock(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwess_account ledgeraccounts.accountnumber%type;
    lvngwg_account  ledgeraccounts.accountnumber%type;
    lvntruckaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('issuerentalitemsfromstock start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     wol.sizedefinition_link_id sizedefinition_id, 'MO' abs_document_type,
                     st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') newgarment,
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     -- RVI 17-02-2009 END
                     nvl((select q.defectitem
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') defectitem,
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     -- RVI 17-02-2009 END
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin = 10 --mounting order
              and    st.transactiontype_id in (22, 32, 422, 423, 424)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber, wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        st.stockreservationpergrade_id, wo.origin, wo.driversales,
                        -- RVI 17-02-2009 BEGIN
                        -- wo.mountingordersales, wol.requestedgrade_id, wol.product_link_id,
                        wo.mountingordersales, st.qualitygrade_id, wol.product_link_id,
                        -- RVI 17-02-2009 END
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        wol.sizedefinition_link_id
              union
              select st.stocktransaction_id, pn.notenumber, pn.distributionpoint_id, pnl.product_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     pnl.sizedefinition_id, 'PN' abs_document_type, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(pst.quantity) quantity
              from   packingnotestocktransaction pst, v_stocktransactions2export st,
                     packingnoteline pnl, packingnote pn
              where  st.stocktransaction_id = pst.stocktransaction_id
              and    pnl.packingnoteline_id = pst.packingnoteline_id
              and    pn.packingnote_id = pnl.packingnote_id
              and    st.transactiontype_id in (22, 32, 422, 423, 424)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, pn.notenumber, pn.distributionpoint_id,
                        st.transactiontype_id, st.qualitygrade_id, st.businessunit_id,
                        st.transactiondate, st.stockreservationpergrade_id, pnl.product_id,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        pnl.sizedefinition_id
              order  by 1) loop
      begin
        ----begin common columns
        -- Document Number, depending on type
        if (x.abs_document_type = 'PN') then
          if (length(x.ordernumber) > 10) then
            lvndocno := substr(x.ordernumber, length(x.ordernumber) - 9, 10);
          else
            lvndocno := x.ordernumber;
          end if;
        end if;
        if (x.abs_document_type = ('MO')) then
          if (length('M'||x.ordernumber) > 10) then
            lvndocno := substr('M'||x.ordernumber, length('M'||x.ordernumber) - 9, 10);
          else
            lvndocno := 'M'||x.ordernumber;
          end if;
        end if;
        lvs_babu  := 'AR';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu := getcostcentercode(x.distributionpoint_link_id);
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 BEGIN
        --lvnwess_account := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'WESS');
        --lvngwg_account  := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'GWG');
        lvnwess_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        lvngwg_account  := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        --truck account
        if x.transactiontype_id in (422, 423, 424) then
          lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        else
          lvntruckaccount := null;
        end if;
        --create line increase value of rented goods that were issued
        lvs_btbu := lvnnetvalue;
        if x.abs_document_type = 'PN' then
          lvs_ktbu := lvngwg_account;
        else
          lvs_ktbu := lvnwess_account;
        end if;
        if x.transactiontype_id in (422, 423, 424) then
          lvs_ktgbu := lvntruckaccount;
        else
          lvs_ktgbu := lvnstockaccount;
        end if;
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to decrease value from either new/used/defect stock
        if x.abs_document_type = 'PN' then
          lvs_ktgbu := lvngwg_account;
        else
          lvs_ktgbu := lvnwess_account;
        end if;
        if x.transactiontype_id in (422, 423, 424) then
          lvs_ktbu := lvntruckaccount;
        else
          lvs_ktbu := lvnstockaccount;
        end if;
        lvs_shbu := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('issuerentalitemsfromstock end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('issuerentalitemsfromstock end');
        raise;
      end;
  end issuerentalitemsfromstock;

-- RVI 18-12-2008 BEGIN
  procedure issuesalesitemsfromstockwo(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwesv_account ledgeraccounts.accountnumber%type;
    --lvngwg_account  ledgeraccounts.accountnumber%type;
    lvntruckaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
    lvndistribpoint number;
  begin
    write_abslogprocessjobline('issuesalesitemsfromstockwo start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber, wo.weareremployment_link_id,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     wol.sizedefinition_link_id sizedefinition_id,
                     st.reasoncode_id,
                    'WO' abs_document_type, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin in (1,2) --(work order)
              and    st.transactiontype_id in (50, 450)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber,  wo.weareremployment_link_id,
                        wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        st.stockreservationpergrade_id, wo.origin, wo.driversales,
                        wo.mountingordersales, st.qualitygrade_id, wol.product_link_id,
                        st.reasoncode_id,
                        wol.sizedefinition_link_id
              order  by 1) loop
      begin
        ----begin common columns
        if (length('W'||x.ordernumber) > 10) then
          lvndocno := substr('W'||x.ordernumber, length('W'||x.ordernumber) - 9, 10);
        else
          lvndocno := 'W'||x.ordernumber;
        end if;
        lvs_babu  := 'LAG';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        if (x.distributionpoint_link_id is null) then
          -- Determine consumptionpoint for weareremployment
          select wemp.distributionpoint_id into lvndistribpoint
          from weareremployment wemp
          where wemp.weareremployment_id = x.weareremployment_link_id;
          -- Determine costcenter
          lvs_kstbu := getcostcentercode(lvndistribpoint);
        else
          lvs_kstbu := getcostcentercode(x.distributionpoint_link_id);
        end if;
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        lvnwesv_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        --truck account
        if x.transactiontype_id in (450) then
          lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        else
          lvntruckaccount := null;
        end if;
        --create line increase value of goods sold(that were delivered)
        lvs_btbu := lvnnetvalue;
        lvs_ktbu := lvnwesv_account;
        if x.transactiontype_id in (450) then
          lvs_ktgbu := lvntruckaccount;
        else
          lvs_ktgbu := lvnstockaccount;
        end if;
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to decrease value from either new/used stock
        lvs_ktgbu := lvnwesv_account;
        if x.transactiontype_id in (450) then
          lvs_ktbu := lvntruckaccount;
        else
          lvs_ktbu := lvnstockaccount;
        end if;
        lvs_shbu := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('issuesalesitemsfromstockwo end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('issuesalesitemsfromstockwo end');
        raise;
      end;
  end issuesalesitemsfromstockwo;

  procedure issuerentalitemsfromstockwo(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwess_account ledgeraccounts.accountnumber%type;
    --lvngwg_account  ledgeraccounts.accountnumber%type;
    lvntruckaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
    lvndistribpoint number;
  begin
    write_abslogprocessjobline('issuerentalitemsfromstockwo start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber, wo.weareremployment_link_id,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     st.reasoncode_id,
                     wol.sizedefinition_link_id sizedefinition_id, 'WO' abs_document_type,
                     st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin in (1,2) --work order
              and    st.transactiontype_id in (22, 32, 422)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber, wo.weareremployment_link_id,
                        wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        st.stockreservationpergrade_id, wo.origin, wo.driversales,
                        wo.mountingordersales, st.qualitygrade_id, wol.product_link_id,
                        st.reasoncode_id,
                        wol.sizedefinition_link_id
              order  by 1) loop
      begin
        ----begin common columns
        if (length('W'||x.ordernumber) > 10) then
          lvndocno := substr('W'||x.ordernumber, length('W'||x.ordernumber) - 9, 10);
        else
          lvndocno := 'W'||x.ordernumber;
        end if;
        lvs_babu  := 'AR';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        if (x.distributionpoint_link_id is null) then
          -- Determine consumptionpoint for weareremployment
          select wemp.distributionpoint_id into lvndistribpoint
          from weareremployment wemp
          where wemp.weareremployment_id = x.weareremployment_link_id;
          -- Determine costcenter
          lvs_kstbu := getcostcentercode(lvndistribpoint);
        else
          lvs_kstbu := getcostcentercode(x.distributionpoint_link_id);
        end if;
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        lvnwess_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        --truck account
        if x.transactiontype_id in (422) then
          lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        else
          lvntruckaccount := null;
        end if;
        --create line increase value of rented goods that were issued
        lvs_btbu := lvnnetvalue;
        lvs_ktbu := lvnwess_account;
        if x.transactiontype_id in (422) then
          lvs_ktgbu := lvntruckaccount;
        else
          lvs_ktgbu := lvnstockaccount;
        end if;
        lvs_shbu := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to decrease value from either new/used/defect stock
        lvs_ktgbu := lvnwess_account;
        if x.transactiontype_id in (422) then
          lvs_ktbu := lvntruckaccount;
        else
          lvs_ktbu := lvnstockaccount;
        end if;
        lvs_shbu := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('issuerentalitemsfromstockwo end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('issuerentalitemsfromstockwo end');
        raise;
      end;
  end issuerentalitemsfromstockwo;
-- RVI 18-12-2008 END

  procedure issueitems2otherstockroom(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('issueitems2otherstockroom start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     wol.sizedefinition_link_id sizedefinition_id, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') newgarment,
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     -- RVI 17-02-2009 END
                     nvl((select q.defectitem
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') defectitem,
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     -- RVI 17-02-2009 END
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin in (8, 9) --inter PO delivery, stock delivery
              and    st.transactiontype_id = 409
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber, wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        st.stockreservationpergrade_id, wo.origin, wo.driversales,
                        -- RVI 17-02-2009 BEGIN
                        -- wo.mountingordersales, wol.requestedgrade_id, wol.product_link_id,
                        wo.mountingordersales, st.qualitygrade_id, wol.product_link_id,
                        -- RVI 17-02-2009 END
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        wol.sizedefinition_link_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        if (length('C'||x.ordernumber) > 10) then
          lvndocno := substr('C'||x.ordernumber, length('C'||x.ordernumber) - 9, 10);
        else
          lvndocno := 'C'||x.ordernumber;
        end if;
        lvs_babu  := 'LAG';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        --create line increase value of shipped goods
        lvs_btbu := lvnnetvalue;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktbu  := gvsexpacctransitstockfibuhts; --susp_accnt_transit
        lvs_ktbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to decrease value from either new/used/defect stock
        lvs_shbu := 'H';
        lvs_ktbu := lvnstockaccount;
        -- RVI 18-12-2008 BEGIN
        --lvs_ktgbu := gvsexpacctransitstockfibuhts; --susp_accnt_transit
        lvs_ktgbu := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('issueitems2otherstockroom end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('issueitems2otherstockroom end');
        raise;
      end;
  end issueitems2otherstockroom;

  procedure moveitemsfromstock2truck(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvntruckaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('moveitemsfromstock2truck start');
    -- RVI 26-05-2009 BEGIN
    --for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, st.transactiondate,
    for x in (select 'LOOP_A' processingorder,
                     st.stocktransaction_id, pl.picklistnumber ordernumber, 'TRL' abs_document_type,
                     st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(pst.quantity) quantity
              from   pickliststocktransaction pst, v_stocktransactions2export st,
                     picklistline pll, picklist pl, product p, sizedefinition s
              where  st.stocktransaction_id = pst.stocktransaction_id
              and    pll.picklistline_id = pst.picklistline_id
              and    pl.picklist_id = pll.picklist_id
              and    pl.origin = 2 -- Truck Load List
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.transactiontype_id in (405, 406)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, pl.picklistnumber, st.businessunit_id,
                        st.stockreservationpergrade_id, st.transactiondate,
                        st.stockroom, p.code, p.product_id, s.code,
                        st.qualitygrade_id
              union
              select 'LOOP_B' processingorder,
                     st.stocktransaction_id, st.stocktransaction_id ordernumber, 'STT' abs_document_type,
                     st.stockreservationpergrade_id, st.transactiondate,
              -- RVI 26-05-2009 END
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (405, 406)
              and    st.delayed = 'N'
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              -- RVI 26-05-2009 BEGIN
              and    not exists (select 1 from pickliststocktransaction pss where pss.stocktransaction_id = st.stocktransaction_id)
              -- RVI 26-05-2009 END
              group  by st.stocktransaction_id, st.businessunit_id, st.stockreservationpergrade_id,
                        st.transactiondate, st.stockroom, p.code, p.product_id, s.code,
                        st.qualitygrade_id
              -- RVI 26-05-2009 BEGIN
              --order  by st.stocktransaction_id) loop
              order  by 1) loop
              -- RVI 26-05-2009 END
      begin
        ----begin common columns
        -- Document Number, depending on type
        if (x.abs_document_type = 'TRL') then
          if (length('U'||x.ordernumber) > 10) then
            lvndocno := substr('U'||x.ordernumber, length('U'||x.ordernumber) - 9, 10);
          else
            lvndocno := 'U'||x.ordernumber;
          end if;
        else
          lvndocno  := 'T'||x.stocktransaction_id;
        end if;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        --truck account
        lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        --create line increase values of goods on truck
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvntruckaccount;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line decrease value from new/used/defect stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvntruckaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('moveitemsfromstock2truck end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('moveitemsfromstock2truck end');
        raise;
      end;
  end moveitemsfromstock2truck;

  procedure ragitemsfromstock(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnscrapaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('ragitemsfromstock start');
    for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (40, 41)
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.businessunit_id, st.stockreservationpergrade_id,
                        st.transactiondate, st.stockroom, p.code, p.product_id, s.code,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        st.qualitygrade_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        lvndocno  := 'R'|| x.stocktransaction_id;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            -- RVI 25-07-2008 BEGIN
            --    lvnnetvalue   := lvnprice * x.quantity;
            lvnnetvalue := lvnprice * abs(x.quantity);
            -- RVI 25-07-2008 END
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        --scrap account
        -- RVI 18-12-2008 END
        --lvnscrapaccount := gvsexpstockscrapaccfibuhts;
        lvnscrapaccount := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        --create line to book cost of ragged items from stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnscrapaccount;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line decrease value frmo either new/used/defect stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvnscrapaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('ragitemsfromstock end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('ragitemsfromstock end');
        raise;
      end;
  end ragitemsfromstock;

  procedure receivereturneditems(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwesv_account ledgeraccounts.accountnumber%type;
    lvngwg_account  ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('receivereturneditems start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     wol.sizedefinition_link_id sizedefinition_id,
                     case
                       when sn.driversales = 'N' and sn.mountingordersales = 'N' then
                        'SN'
                       when sn.driversales = 'Y' and sn.mountingordersales = 'N' then
                        'DSN'
                       when sn.driversales = 'N' and sn.mountingordersales = 'Y' then
                        'MOSN'
                       else
                        'X'
                     end abs_document_type, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = wol.requestedgrade_id), 'N') newgarment,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo, workorder sn
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin in 7 --credit note
              and    st.transactiontype_id = 53
              and    sn.workorder_id = wo.creditworkorder_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber, wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        st.stockreservationpergrade_id, wo.origin, wo.driversales,
                        wo.mountingordersales, wol.requestedgrade_id, wol.product_link_id,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        wol.sizedefinition_link_id, sn.driversales, sn.mountingordersales
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        if (length('V'||x.ordernumber) > 10) then
          lvndocno := substr('V'||x.ordernumber, length('V'||x.ordernumber) - 9, 10);
        else
          lvndocno := 'V'||x.ordernumber;
        end if;
        lvs_babu  := 'GS';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu := getcostcentercode(x.distributionpoint_link_id);
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            lvnaccnt_type := '02';
            lvnnetvalue   := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 BGEIN
        --lvnwesv_account := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'WESV');
        --lvngwg_account  := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'GWG');
        lvnwesv_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        lvngwg_account  := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        --create line reduce value of sold goods
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnwesv_account;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to increase value from either new/used stock
        lvs_shbu  := 'S';
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvnwesv_account;
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('receivereturneditems end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('receivereturneditems end');
        raise;
      end;
  end receivereturneditems;

  procedure returnofrenteditems(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwess_account ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('returnofrenteditems start');
    for x in (select st.stocktransaction_id, wo.workordernumber ordernumber,
                     wo.distributionpoint_link_id, wol.product_link_id product_id,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     wol.sizedefinition_link_id sizedefinition_id, st.transactiontype_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                     -- RVI 17-02-2009 BEGIN
                     --     where  q.qualitygrade_id = wol.requestedgrade_id), 'N') newgarment,
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from  qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     -- RVI 17-02-2009 END
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, sum(wst.quantity) quantity
              from   workorderstocktransaction wst, v_stocktransactions2export st, workorderline wol,
                     workorder wo
              where  st.stocktransaction_id = wst.stocktransaction_id
              and    wol.workorderline_id = wst.workorderline_id
              and    wo.workorder_id = wol.workorder_id
              and    wo.origin = 11 --dismounting order
              and    st.transactiontype_id in (15, 16)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, wo.workordernumber, wo.distributionpoint_link_id,
                        st.transactiontype_id, st.businessunit_id, st.transactiondate,
                        -- RVI 17-02-2009 BEGIN
                        -- st.stockreservationpergrade_id, wo.origin, wol.requestedgrade_id,
                        st.stockreservationpergrade_id, wo.origin, st.qualitygrade_id,
                        -- RVI 17-02-2009 END
                        wol.product_link_id,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        wol.sizedefinition_link_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        if (length('M'||x.ordernumber) > 10) then
          lvndocno := substr('M'||x.ordernumber, length('M'||x.ordernumber) - 9, 10);
        else
          lvndocno := 'M'||x.ordernumber;
        end if;
        lvs_babu  := 'GS';
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id);
        lvs_kstbu := getcostcentercode(x.distributionpoint_link_id);
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            lvnaccnt_type := '02';
            -- RVI 17-02-2009 BEGIN
            if (x.defectitem = 'Y') then
              lvnaccnt_type := '03';
            end if;
            -- RVI 17-02-2009 END
            lvnnetvalue   := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        --lvnwess_account := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'WESS');
        lvnwess_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END
        --create line reduce value of rented goods that were returned
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnwess_account;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line to increase value from either new/used/defect stock
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvnwess_account;
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('returnofrenteditems end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('returnofrenteditems end');
        raise;
      end;
  end returnofrenteditems;

  procedure returnofgeneralpoolitems(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnprice        number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnwesr_account ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('returnofgeneralpoolitems start');
    for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (15, 16)
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.businessunit_id, st.stockreservationpergrade_id,
                        st.transactiondate, st.stockroom, p.code, p.product_id, s.code,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        st.qualitygrade_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        lvndocno  := 'G'|| x.stocktransaction_id;
        lvs_babu  := 'GS';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 BGEIN
        --lvnwesr_account := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'WESR');
        lvnwesr_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 END

        --create line reduce value of sold/rented goods that were returned
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnwesr_account;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line increase value for either new/used/defect stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvnwesr_account; --intially wrong in analyse
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('returnofgeneralpoolitems end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('returnofgeneralpoolitems end');
        raise;
      end;
  end returnofgeneralpoolitems;

  procedure stockcorrections(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu            isapexport.babu%type;
    lvs_t1bu            isapexport.t1bu%type;
    lvs_kstbu           isapexport.kstbu%type;
    lvs_zf3bu           isapexport.zf3bu%type;
    lvs_btbu            isapexport.btbu%type;
    lvs_ktbu            isapexport.ktbu%type;
    lvs_ktgbu           isapexport.ktgbu%type;
    lvs_shbu            isapexport.shbu%type;
    lvnaccnt_type       stocktype.code%type;
    lvnprice            number;
    lvnstockaccount     ledgeraccounts.accountnumber%type;
    lvnstockdiffaccount ledgeraccounts.accountnumber%type;
    lvntruckaccount     ledgeraccounts.accountnumber%type;
    lvnnetvalue         number;
    lvndocno            varchar2(10);
  begin
    write_abslogprocessjobline('stockcorrections start');
    for x in (select st.stocktransaction_id, st.transactiontype_id, st.stockreservationpergrade_id,
                     st.transactiondate, to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     -- RVI 18-12-2008 BEGIN
                     st.reasoncode_id,
                     -- RVI 18-12-2008 END
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (84, 414, 444)
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.transactiontype_id, st.businessunit_id,
                        st.stockreservationpergrade_id, st.transactiondate, st.stockroom, p.code,
                        p.product_id, s.code,
                        -- RVI 18-12-2008 BEGIN
                        st.reasoncode_id,
                        -- RVI 18-12-2008 END
                        st.qualitygrade_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        lvndocno  := 'S'|| x.stocktransaction_id;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 BEGIN
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * abs(x.quantity);
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        --stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- RVI 18-12-2008 BEGIN
        --lvnstockdiffaccount := gvsexpstockdiffaccfibuhts;
        lvnstockdiffaccount := getledgeraccountperkeycode(x.reasoncode_id, x.product_id,
                                                          lvnaccnt_type);
        -- RVI 18-12-2008 END
        if x.transactiontype_id in (414, 444) then
          lvntruckaccount := getledgeraccountsperproduct(x.product_id, '05');
        else
          lvntruckaccount := null;
        end if;
        --create line reduce/increase value of stock differences
        lvs_btbu := lvnnetvalue;
        if x.transactiontype_id in (414, 444) then
          lvs_ktbu  := lvnstockdiffaccount;
          lvs_ktgbu := lvntruckaccount;
        else
          lvs_ktbu  := lvnstockdiffaccount;
          lvs_ktgbu := lvnstockaccount;
        end if;
        if x.quantity > 0 then
          lvs_shbu := 'H';
        else
          lvs_shbu := 'S';
        end if;
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line increase/decrease value for either new/used/defect stock
        lvs_btbu := lvnnetvalue;
        if x.transactiontype_id in (414, 444) then
          lvs_ktbu  := lvntruckaccount;
          lvs_ktgbu := lvnstockdiffaccount;
        else
          lvs_ktbu  := lvnstockaccount;
          lvs_ktgbu := lvnstockdiffaccount;
        end if;
        if x.quantity > 0 then
          lvs_shbu := 'S';
        else
          lvs_shbu := 'H';
        end if;
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('stockcorrections end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('stockcorrections end');
        raise;
      end;
  end stockcorrections;

-- RVI 11-02-2009 BEGIN
  procedure internalstockmovements(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu            isapexport.babu%type;
    lvs_t1bu            isapexport.t1bu%type;
    lvs_kstbu           isapexport.kstbu%type;
    lvs_zf3bu           isapexport.zf3bu%type;
    lvs_btbu            isapexport.btbu%type;
    lvs_ktbu            isapexport.ktbu%type;
    lvs_ktgbu           isapexport.ktgbu%type;
    lvs_shbu            isapexport.shbu%type;
    lvnaccnt_type       stocktype.code%type;
    lvnprice            number;
    lvnstockaccount     ledgeraccounts.accountnumber%type;
    lvnstockdiffaccount ledgeraccounts.accountnumber%type;
    lvntruckaccount     ledgeraccounts.accountnumber%type;
    lvnnetvalue         number;
    lvndocno            varchar2(10);
  begin
    write_abslogprocessjobline('internalstockmovements start');
    for x in (select st.stocktransaction_id, st.transactiontype_id, st.stockreservationpergrade_id,
                     st.transactiondate, to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     p.code productcode, p.product_id, s.code sizecode,
                     st.reasoncode_id,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (93)
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, st.transactiontype_id, st.businessunit_id,
                        st.stockreservationpergrade_id, st.transactiondate, st.stockroom, p.code,
                        p.product_id, s.code,
                        st.reasoncode_id,
                        st.qualitygrade_id
              order  by st.stocktransaction_id) loop
      begin
        ----begin common columns
        lvndocno  :=  'L'|| x.stocktransaction_id;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * abs(x.quantity);
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        -- stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        lvntruckaccount := null;
        -- stock differences account
        lvnstockdiffaccount := getledgeraccountperkeycode(x.reasoncode_id, x.product_id,
                                                          lvnaccnt_type);
        --create line reduce/increase value of stock differences
        lvs_btbu := lvnnetvalue;
        lvs_ktbu  := lvnstockdiffaccount;
        lvs_ktgbu := lvnstockaccount;
        if x.quantity > 0 then
          lvs_shbu := 'H';
        else
          lvs_shbu := 'S';
        end if;
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --create line increase/decrease value for either new/used/defect stock
        lvs_btbu := lvnnetvalue;
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvnstockdiffaccount;

        if x.quantity > 0 then
          lvs_shbu := 'S';
        else
          lvs_shbu := 'H';
        end if;
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        --set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('internalstockmovements end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('internalstockmovements end');
        raise;
      end;
  end internalstockmovements;
-- RVI 11-02-2009 END

-- RVI 18-02-2009 BEGIN
  procedure moveitems2activestock(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu         isapexport.babu%type;
    lvs_t1bu         isapexport.t1bu%type;
    lvs_kstbu        isapexport.kstbu%type;
    lvs_zf3bu        isapexport.zf3bu%type;
    lvs_btbu         isapexport.btbu%type;
    lvs_ktbu         isapexport.ktbu%type;
    lvs_ktgbu        isapexport.ktgbu%type;
    lvs_shbu         isapexport.shbu%type;
    lvnaccnt_type    stocktype.code%type;
    lvnprice         number;
    lvnstockaccount  ledgeraccounts.accountnumber%type;
    lvnastockaccount ledgeraccounts.accountnumber%type;
    lvnnetvalue      number;
    lvndocno         varchar2(10);
  begin
    write_abslogprocessjobline('moveitems2activestock start');
    -- RVI 26-05-2009 BEGIN
    --for x in (select st.stocktransaction_id, st.stockreservationpergrade_id, st.transactiondate,
    for x in (select 'LOOP_A' processingorder,
                     st.stocktransaction_id, pl.picklistnumber ordernumber, 'TRL' abs_document_type,
                     st.stockreservationpergrade_id, st.transactiondate,
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     st.reasoncode_id,
                     p.code productcode, p.product_id, s.code sizecode,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(pst.quantity) quantity
              from   pickliststocktransaction pst, v_stocktransactions2export st,
                     picklistline pll, picklist pl, product p, sizedefinition s
              where  st.stocktransaction_id = pst.stocktransaction_id
              and    pll.picklistline_id = pst.picklistline_id
              and    pl.picklist_id = pll.picklist_id
              and    pl.origin = 2 -- Truck Load List
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.transactiontype_id in (22)
              and    st.timestamp < pnprocessstarttimestamp
              group  by st.stocktransaction_id, pl.picklistnumber, st.businessunit_id,
                        st.stockreservationpergrade_id, st.transactiondate,
                        st.stockroom, p.code, p.product_id, s.code,
                        st.reasoncode_id, st.qualitygrade_id
              union
              select 'LOOP_B' processingorder,
                     st.stocktransaction_id, st.stocktransaction_id ordernumber, 'STT' abs_document_type,
                     st.stockreservationpergrade_id, st.transactiondate,
              -- RVI 26-05-2009 END
                     to_char(st.transactiondate, 'YYYY') year,
                     to_char(st.transactiondate, 'MM') month,
                     to_char(st.transactiondate, 'YYYYMMDD') document_date, st.stockroom,
                     st.reasoncode_id,
                     p.code productcode, p.product_id, s.code sizecode,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = st.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = st.businessunit_id) businessunitcode,
                     st.businessunit_id, sum(st.quantity) quantity
              from   v_stocktransactions2export st, product p, sizedefinition s
              where  st.transactiontype_id in (22)
              and    st.delayed = 'N'
              and    p.product_id = st.product_id
              and    s.sizedefinition_id = st.sizedefinition_id
              and    st.timestamp < pnprocessstarttimestamp
              -- RVI 26-05-2009 BEGIN
              and    not exists (select 1 from pickliststocktransaction pss where pss.stocktransaction_id = st.stocktransaction_id)
              -- RVI 26-05-2009 END
              -- RVI 11-01-2012 BEGIN
              and    not exists (select 1 from workorderstocktransaction wss where wss.stocktransaction_id = st.stocktransaction_id)
              -- RVI 11-01-2012 END
              group  by st.stocktransaction_id, st.businessunit_id, st.stockreservationpergrade_id,
                        st.transactiondate, st.stockroom, p.code, p.product_id, s.code,
                        st.reasoncode_id, st.qualitygrade_id
              -- RVI 26-05-2009 BEGIN
              --order  by st.stocktransaction_id) loop
              order  by 1) loop
              -- RVI 26-05-2009 END
      begin
        ----begin common columns
        -- Document Number, depending on type
        if (x.abs_document_type = 'TRL') then
          if (length('A'||x.ordernumber) > 10) then
            lvndocno := substr('A'||x.ordernumber, length('A'||x.ordernumber) - 9, 10);
          else
            lvndocno := 'A'||x.ordernumber;
          end if;
        else
          lvndocno  := 'A'||x.stocktransaction_id;
        end if;
        lvs_babu  := 'AR';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
            lvnprice      := f_getavgpurchasepricesatdate(x.stockreservationpergrade_id,
                                                          x.transactiondate);
            lvnnetvalue   := lvnprice * x.quantity;
          end;
        else
          begin
            if x.defectitem = 'Y' then
              lvnaccnt_type := '03';
            else
              lvnaccnt_type := '02';
            end if;
            lvnnetvalue := 0;
          end;
        end if;
        -- passve stock account
        lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
        -- active stock account
        lvnastockaccount := getledgeraccountperkeycode(x.reasoncode_id, x.product_id, lvnaccnt_type);
        -- create line increase values of goods on passive stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnastockaccount;
        lvs_ktgbu := lvnstockaccount;
        lvs_shbu  := 'S';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        -- create line decrease value from new/used/defect stock
        lvs_btbu  := lvnnetvalue;
        lvs_ktbu  := lvnstockaccount;
        lvs_ktgbu := lvnastockaccount;
        lvs_shbu  := 'H';
        pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu, lvndocno,
                                         x.document_date, lvs_t1bu, lvs_kstbu, lvs_zf3bu, lvs_btbu,
                                         lvs_ktbu, lvs_ktgbu, lvs_shbu, x.businessunit_id);
        -- set exported to Y
        updatetransaction2exported(x.stocktransaction_id);
        commit;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('moveitems2activestock end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('moveitems2activestock end');
        raise;
      end;
  end moveitems2activestock;
-- RVI 18-02-2009 END

  procedure pricechange(pnprocessstarttimestamp stocktransaction.timestamp%type) is
    lvs_babu        isapexport.babu%type;
    lvs_t1bu        isapexport.t1bu%type;
    lvs_kstbu       isapexport.kstbu%type;
    lvs_zf3bu       isapexport.zf3bu%type;
    lvs_btbu        isapexport.btbu%type;
    lvs_ktbu        isapexport.ktbu%type;
    lvs_ktgbu       isapexport.ktgbu%type;
    lvs_shbu        isapexport.shbu%type;
    lvnaccnt_type   stocktype.code%type;
    lvnpricediff    number;
    lvnstockaccount ledgeraccounts.accountnumber%type;
    lvnabw_account  ledgeraccounts.accountnumber%type;
    lvnnetvalue     number;
    lvndocno        varchar2(10);
  begin
    write_abslogprocessjobline('pricechange start');
    for x in (select stav.stockvalueavgpp_id, stav.reasoncode_id, stav.avgpurchaseprice,
                     stav.prevavgpurchaseprice, stav.transactiondate, stav.actualstockquantity,
                     to_char(stav.transactiondate, 'YYYY') year,
                     to_char(stav.transactiondate, 'MM') month,
                     to_char(stav.transactiondate, 'YYYYMMDD') document_date,
                     nvl((select q.newgarment
                          from   qualitygrade q
                          where  q.qualitygrade_id = stav.qualitygrade_id), 'N') newgarment,
                     nvl((select q.defectitem
                          from   qualitygrade q
                          where  q.qualitygrade_id = stav.qualitygrade_id), 'N') defectitem,
                     (select bu.code
                       from   businessunit bu
                       where  bu.businessunit_id = lag.managedbybu_id) businessunitcode,
                     lag.managedbybu_id businessunit_id, lag.code stockroom, p.product_id,
                     p.code productcode, s.code sizecode, stav.stocktransaction_id
              from   stockvalueavgpp stav, stockroom lag, product p, sizedefinition s
              where  stav.transactiontype = 3 --administrative transaction
              and    stav.origin = 9 --manual price change
              and    lag.stockroom_id = stav.stockroom_id
              and    p.product_id = stav.product_link_id
              and    s.sizedefinition_id = stav.sizedefinition_link_id
              -- RVI 02-02-2009 BEGIN
              and    stav.exported = 'N'
              and    stav.timestamp < pnprocessstarttimestamp
              -- RVI 02-02-2009 END
              order  by stav.stockvalueavgpp_id) loop
      begin
        ----begin common columns
        lvndocno  := 'X'||x.stockvalueavgpp_id;
        lvs_babu  := 'LAG';
        -- RVI 02-04-2009 BEGIN
        lvs_t1bu  := gettext_t1bu(x.stocktransaction_id, x.stockroom, x.productcode || '^' || x.sizecode,
                                  x.reasoncode_id);
        -- RVI 02-04-2009 END
        lvs_kstbu := null; --costcenter
        lvs_zf3bu := null; --extdocno
        ----end common columns
        if x.newgarment = 'Y' then
          begin
            lvnaccnt_type := '01';
          end;
        else
          begin
            if x.defectitem = 'Y' then
               lvnaccnt_type := '03';
            else
               lvnaccnt_type := '02';
            end if;
          end;
        end if;
        -- determine if there is a price difference
        lvnpricediff := x.avgpurchaseprice - x.prevavgpurchaseprice;
        lvnnetvalue := abs(lvnpricediff * x.actualstockquantity);

        -- only export any transactions if there is a price difference
        if lvnpricediff <> 0 then
          begin
            --stock account
            lvnstockaccount := getledgeraccountsperproduct(x.product_id, lvnaccnt_type);
            -- RVI 18-12-2008 BEGIN
            --lvnabw_account  := getledgeraccountsperproduct(x.product_id, lvnaccnt_type, 'ABW');
            lvnabw_account := getledgeraccountperkeycode(x.reasoncode_id, x.product_id,
                                                         lvnaccnt_type);
            -- RVI 18-12-2008 END
            --create line reduce /increase value stock devaluation
            lvs_btbu  := lvnnetvalue;
            lvs_ktbu  := lvnabw_account;
            lvs_ktgbu := lvnstockaccount;
            if lvnpricediff > 0 then
              lvs_shbu := 'H';
            else
              lvs_shbu := 'S';
            end if;
            pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu,
                                             lvndocno, x.document_date, lvs_t1bu, lvs_kstbu,
                                             lvs_zf3bu, lvs_btbu, lvs_ktbu, lvs_ktgbu, lvs_shbu,
                                             x.businessunit_id);
            --create line increase/decrease value for either new/used/defect stock
            if lvnpricediff > 0 then
              lvs_shbu := 'S';
            else
              lvs_shbu := 'H';
            end if;
            lvs_ktbu  := lvnstockaccount;
            lvs_ktgbu := lvnabw_account;
            pack_isapexport.write_isapexport(x.businessunitcode, x.year, x.month, lvs_babu,
                                             lvndocno, x.document_date, lvs_t1bu, lvs_kstbu,
                                             lvs_zf3bu, lvs_btbu, lvs_ktbu, lvs_ktgbu, lvs_shbu,
                                             x.businessunit_id);
            --set exported to Y
            update stockvalueavgpp stav
            set    stav.exported = 'Y'
            where  stav.stockvalueavgpp_id = x.stockvalueavgpp_id;
            -- RVI 15-04-2011 BEGIN
            gvnrowsprocessed := sql%rowcount + gvnrowsprocessed;
            -- RVI 15-04-2011 END
            commit;
          end; --lvnpricediff <> 0
        end if;
      exception
        when no_data_found then
          begin
            rollback;
            write_abslogprocessjobline('No data found ' || gvsmsg, 3);
          end;
        when others then
          begin
            rollback;
            write_abslogprocessjobline(gvsmsg || ' ' || sqlerrm, 3);
          end;
      end;
    end loop;
    write_abslogprocessjobline('pricechange end');
  exception
    when others then
      begin
        write_abslogprocessjobline(sqlerrm, 3);
        write_abslogprocessjobline('pricechange end');
        raise;
      end;
  end pricechange;

  -- End Export procedures
  -- End Internal function begin external procedure

  function export(fpnplantprocessid plantprocess.plantprocess_id%type, fpprocessstarttimestamp stocktransaction.timestamp%type) return number is
    -- Main function for export into ISAPEXPORT
  begin
    initialization(fpnplantprocessid);
    -- Create abslogprocessjob start line
    write_abslogprocessjob(fpnplantprocessid);
    initial_validations;
    -- Start processing
    receiveinstockusingexternalpo(fpprocessstarttimestamp);
    receiveinstockusinginternalpo(fpprocessstarttimestamp);
    receiveinstockwithoutusingpo(fpprocessstarttimestamp);
    receiveinstockmovedfromtruck(fpprocessstarttimestamp);
    issuesalesitemsfromstock(fpprocessstarttimestamp);
    issuerentalitemsfromstock(fpprocessstarttimestamp);
    -- RVI 24-03-2009 BEGIN
    issuesalesitemsfromstockwo(fpprocessstarttimestamp);
    issuerentalitemsfromstockwo(fpprocessstarttimestamp);
    -- RVI 24-03-2009 END
    issueitems2otherstockroom(fpprocessstarttimestamp);
    moveitemsfromstock2truck(fpprocessstarttimestamp);
    ragitemsfromstock(fpprocessstarttimestamp);
    receivereturneditems(fpprocessstarttimestamp);
    returnofrenteditems(fpprocessstarttimestamp);
    returnofgeneralpoolitems(fpprocessstarttimestamp);
    stockcorrections(fpprocessstarttimestamp);
    -- RVI 11-02-2009 BEGIN
    internalstockmovements(fpprocessstarttimestamp);
    -- RVI 11-02-2009 END
    -- RVI 18-02-2009 BEGIN
    moveitems2activestock(fpprocessstarttimestamp);
    -- RVI 18-02-2009 BEGIN
    pricechange(fpprocessstarttimestamp);
    -- End processing
    write_abslogprocessjobline('No of lines processed correctly: ' || to_char(gvnrowsprocessed));
    -- Create abslogprocessjob end line
    write_abslogprocessjob(fpnplantprocessid);
    commit;
    return 0;
  exception
    when gveerror_initialization then
      begin
        --error initialization cannot start.. no plantprocess?
        dbms_output.put_line('Pack_ISAPExport Error initialization cannot start.. no plantprocess?');
        write_abslogprocessjob('Pack_ISAPExport Error initialization cannot start.. no plantprocess!?: ' ||
                               fpnplantprocessid);
        rollback;
        return 2;
      end;
    when others then
      begin
        write_abslogprocessjobline('export' || ' ' || sqlerrm, 3);
        -- Create abslogprocessjob end line
        write_abslogprocessjob(fpnplantprocessid);
        rollback;
        return 1;
      end;
  end export;

end pack_isapexport;
/
create or replace package pack_lossforpool is
  -- version : 3.3
  -- author  : alin.n
  -- created : 01-08-2011 13:19:16
  -- purpose : loss for pool scheduled process
  -- updated : 20-02-2014 HVH order 20014641 Redesign Loss for Pool Module
  -- updated : 16-06-2014 HVH order 20015191 Added option to bill based on last scandate in addition to outscandate
  -- updated : 22-11-2022 ABS-143320 ASD-52891 CLU: Scheduled process failed/ stuck in progress
  -- updated : 15-11-2023 ABS-157213 loss for pool process performance
  -- updated : 26-02-2024 ABS-161920 loss for pool department depending on systemsetting LOSSFORPOOLDEPARTMENT
  -- updated : 25-03-2024 ABS-162494 Loss for pool number of days taken from customer instead of plpc
  -- updated : 08-04-2024 ABS-163317 lastdelivery date in uniqueitempool not filled with the correct date
  -- updated : 12-04-2024 ABS-163317 lastdelivery date in uniqueitempool not filled with the correct date, check also for stay of unique item
  -- updated : 06-06-2024 ABS-164043 New procedure to recalculate loss amount before invoicing

  -- public function and procedure declarations
  function lossforpoolprocess(fp_plantprocessid in plantprocess.plantprocess_id%type)
    return number;

  procedure recalc_not_invoiced_lossforpool(fp_plant_id in plant.plant_id%type,
                                            fp_recalc_days number default 32);

end pack_lossforpool;
/
create or replace package body pack_lossforpool is

  -- private type declarations
  gv_userexception exception;

  -- private constant declarations
  return_ok                    constant integer := 0;
  return_failed_no_lossperiod  constant integer := 1;
  return_failed_unknown        constant integer := -1;
  gc_max_date                  constant date    := to_date('31-12-2099', 'dd-mm-yyyy');

  priority_message constant abslogprocessjobline.priority%type := 1;
--priority_warning constant abslogprocessjobline.priority%type := 2;
  priority_error constant abslogprocessjobline.priority%type   := 3;
  priority_debug constant abslogprocessjobline.priority%type   := 5;


  -- private variable declarations
  gv_processname            abslogprocessjobpart.processname%type;
  gv_systemuserid           systemuser.systemuser_id%type := 0;
  gv_abslogprocessjobid     abslogprocessjob.abslogprocessjob_id%type;
  gv_abslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
  gv_message                abslog.message%type;
  gv_returnvalue            number := return_ok;
  gv_plantid                plant.plant_id%type;

  gv_sizestarid             number;
  gv_lossforpoolprice      number;
  gv_lossforpooldepartment number;

  ---------------------------------------------------------------------------------------------------
  procedure write_log(fp_message  in abslogprocessjobline.message%type,
                      fp_priority in abslogprocessjobline.priority%type default priority_message) is
  begin
    --write_log part
    if gv_abslogprocessjobpartid is null and
       gv_abslogprocessjobid is not null then
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gv_abslogprocessjobid,
                                                                          gv_processname,
                                                                          gv_systemuserid);
    end if;
    if (gv_abslogprocessjobpartid is not null) then
      abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid,
                                             fp_priority,
                                             fp_message,
                                             gv_systemuserid);
    end if;
    if (gv_abslogprocessjobpartid is null and gv_abslogprocessjobpartid is null) then
       abslogwrite.abslog_write(5, 'pack_lossforpool', gv_plantid, fp_priority, fp_message, gv_systemuserid);
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(fp_message);
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := return_failed_unknown;
        raise gv_userexception;
      end;
  end write_log;


  ---------------------------------------------------------------------------------------------------
  procedure end_log is
  begin
    --end_log
    if gv_abslogprocessjobid is not null then
      abslogwrite.abslogprocessjob_update(gv_abslogprocessjobid,
                                          sysdate,
                                          gv_systemuserid);
      gv_abslogprocessjobid := null;
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(gv_message);
        dbms_output.put_line(sqlerrm);
      end;
  end end_log;

  ---------------------------------------------------------------------------------------------------
  procedure get_abslogprocessjobid(fp_plantprocessid in plantprocess.plantprocess_id%type,
                                   fp_plantid        in plant.plant_id%type) is
  begin
    --write_log
    gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(fp_plantid,
                                                                sysdate,
                                                                null,
                                                                null,
                                                                fp_plantprocessid,
                                                                gv_systemuserid);
  end get_abslogprocessjobid;

  procedure initialise is
  begin
    --get size star
    gv_message := 'size *';
    select s.sizedefinition_id
    into gv_sizestarid
    from sizedefinition s
    where s.code = '*';

    -- get system setting LOSSFORPOOLPRICE
    gv_message := 'Read systemsetting LOSSFORPOOLPRICE for plant_id ' ||
                  to_char(gv_plantid);
    select to_number(nvl(ss.value, ss.factorydefault))
      into gv_lossforpoolprice
      from systemsetting ss
     where ss.plant_id = gv_plantid
       and ss.name = 'LOSSFORPOOLPRICE';

    -- get system setting LOSSFORPOOLDEPARTMENT
    gv_message := 'Read systemsetting LOSSFORPOOLDEPARTMENT for plant_id ' ||
                  to_char(gv_plantid);
    begin
      select to_number(nvl(ss.value, ss.factorydefault))
        into gv_lossforpooldepartment
        from systemsetting ss
       where ss.plant_id = gv_plantid
         and ss.name = 'LOSSFORPOOLDEPARTMENT';
    exception
      when no_data_found then
        gv_lossforpooldepartment := 0;
    end;
  end;

  -------------------------- MAIN ---------------------------------------------------------------------
  function lossforpoolprocess(fp_plantprocessid in plantprocess.plantprocess_id%type)
    return number is
    lv_nr_of_lossperiods     number;
    lv_lossforpoolmethod     number;

  begin
    -- STEP 0 Initialization -----------------------------------------------------------------------
    gv_abslogprocessjobid := null;
    gv_abslogprocessjobpartid := null;
    gv_processname        := 'PACK_LOSSFORPOOL.LOSSFORPOOLPROCESS';
    gv_message            := 'STEP 0 Initialization';
    gv_returnvalue        := return_ok;

    --check parameter not null
    if fp_plantprocessid is null then
      begin
        gv_message     := 'Parameter fp_plantprocessid cannot be left empty!';
        write_log(gv_message, priority_error);
        gv_returnvalue := return_failed_unknown;
        raise gv_userexception;
      end;
    end if;

    --get plant id
    gv_message := 'Get plant_id for plantprocess_id ' || to_char(fp_plantprocessid);
    select pp.plant_id, pp.systemuser_id
      into gv_plantid, gv_systemuserid
      from plantprocess pp
     where pp.plantprocess_id = fp_plantprocessid;
    --get abslog process job id
    get_abslogprocessjobid(fp_plantprocessid, gv_plantid);

    write_log('START PACK_LOSSFORPOOL.LOSSFORPOOLPROCESS');

    initialise;

    -- get system setting LOSSFORPOOLMETHOD
    gv_message := 'Read systemsetting LOSSFORPOOLMETHOD for plant_id ' || to_char(gv_plantid);
    select to_number(nvl(ss.value, ss.factorydefault))
      into lv_lossforpoolmethod
      from systemsetting ss
     where ss.plant_id = gv_plantid
       and ss.name = 'LOSSFORPOOLMETHOD';

    if lv_lossforpoolmethod = 1 then
      gv_message := 'Check for existence loss for pool periods per invoice frequency';
      lv_nr_of_lossperiods := 0;
      for j in (select ifc.invoicefrequency_id, ifc.factorydescription
                  from invoicefrequency ifc,
                       plantinvoicefrequency pif
                 where pif.invoicefrequency_id = ifc.invoicefrequency_id
                   and pif.plant_id = gv_plantid
                   and ifc.invoicefrequencynumber <> 200  -- exclude manual
                   and exists
                       (select c.customer_id
                          from customer c, businessunit b
                         where c.invoicefrequency_id = ifc.invoicefrequency_id
                           and c.chargelossforpoolitems = 1
                           and b.businessunit_id = c.defaultbusinessunit_id
                           and b.plant_id = gv_plantid)
               )
        loop
          select count(1)
            into lv_nr_of_lossperiods
            from invoicefrequencylossperiod iflp
           where iflp.invoicefrequency_id = j.invoicefrequency_id
             and iflp.enddate >= trunc(sysdate);
            if (lv_nr_of_lossperiods = 0) then
              gv_message     := 'There are no current or future loss charge periods defined for invoice frequency ' || j.factorydescription || ' Please define periods.';
              write_log(gv_message, priority_error);
              gv_returnvalue := return_failed_no_lossperiod;
            end if;
        end loop;
      if gv_returnvalue = return_failed_no_lossperiod then
        raise gv_userexception;
      end if;
    end if; --  lv_lossforpoolmethod = 1

    -- STEP 1 Credit Returned Items -----------------------------------------------------------------------
    gv_message := 'STEP 1 Credit Returned Items';
    write_log(gv_message);
    merge into uniqueitemloss using
          (select uil.uniqueitemloss_id,
                  nvl((select lgsd.percentage
                         from lossgraceschemedetail lgsd
                        where lgsd.lossgracescheme_id = c.lossgracescheme_id
                          and lgsd.numberofdays =
                             (select min(lgsd2.numberofdays)
                                from lossgraceschemedetail lgsd2
                               where lgsd2.lossgracescheme_id = c.lossgracescheme_id
                                 and lgsd2.numberofdays >= uil.returneddate - h.invoicedate + 1)),0) percentage,
                  uil.lossamount,
                  cu.invoiceamountdecimals decimals
             from uniqueitemloss uil,
                  uniqueitem     ui,
                  businessunit   b,
                  invoiceheader  h,
                  currency       cu,
                  customer       c,
                  status         s
            where ui.uniqueitem_id = uil.uniqueitem_link_id
              and b.businessunit_id = c.defaultbusinessunit_id
              and b.plant_id = gv_plantid
              and uil.lossstatus = 1 -- charged for loss
              and uil.returneddate <> gc_max_date --to_date('31/12/2099', 'dd/mm/yyyy') -- this means returned
              and h.invoiceheader_id = uil.lossinvoiceheader_id
              and cu.currency_id = h.currency_id
              and c.customer_id = uil.customer_link_id
              and s.status_id = h.status_id
              and s.code = '2' --finalized
          ) merge_subquery
       on (uniqueitemloss.uniqueitemloss_id = merge_subquery.uniqueitemloss_id)
    when matched then update
       set lossstatus    = case
                             when merge_subquery.percentage = 0 then 4  -- 4 = returned not credited
                             when merge_subquery.percentage = 100 then 2 -- 2 = returned credited 100%
                             else 3 -- returned credited < 100%
                           end,
           creditamount  = case
                             when merge_subquery.percentage = 0 then 0
                             when merge_subquery.percentage = 100 then merge_subquery.lossamount * -1
                             else round(merge_subquery.lossamount * merge_subquery.percentage / 100 * -1,
                                        merge_subquery.decimals)
                           end,
           systemuser_id = gv_systemuserid,
           timestamp     = sysdate;
    commit;


    -- STEP 2 Update items that are returned before loss is charged -------------------------------------------
    gv_message := 'STEP 2 Update items that are returned before loss is charged';
    write_log(gv_message);
    merge into uniqueitemloss using
          (select uil.uniqueitemloss_id
             from uniqueitemloss uil,
                  customer c,
                  businessunit b
            where c.customer_id = uil.customer_link_id
              and b.businessunit_id = c.defaultbusinessunit_id
              and b.plant_id = gv_plantid
              and uil.lossstatus = 0
              and uil.returneddate <>  gc_max_date --to_date('31/12/2099', 'dd/mm/yyyy') -- this means returned
          ) merge_subquery
       on (uniqueitemloss.uniqueitemloss_id = merge_subquery.uniqueitemloss_id)
    when matched then update
       set lossstatus    = 5,
           lossamount    = 0,
           creditamount  = 0,
           systemuser_id = gv_systemuserid,
           timestamp     = sysdate;
    commit;


    -- STEP 3 Charge loss for not returned items  -------------------------------------------------------
    gv_message := 'STEP 3 Charge loss for not returned items';
    write_log(gv_message);

    insert into uniqueitemloss
      (uniqueitemloss_id, uniqueitem_link_id, customer_link_id, distributionpoint_link_id,
       lossstatus, outscandate, returneddate, lossinvoiceheader_id, creditinvoiceheader_id,
       lossamount, creditamount, systemuser_id, timestamp, invoicefrequencylossperiod_id,
       losschargetrigger, lastscandate, losschargedate, lastdeliverydate)
      select seq_uniqueitemloss.nextval, ui.uniqueitem_id, c.customer_id, dp.distributionpoint_id, 0,
             ui.lastoutscandate, gc_max_date, null, null,
             case
               when gv_lossforpoolprice = 2 -- then charge residual value, else full replacement price
                then
                round(nvl(ap.price, aps.price) * (case
                                                    when nvl(ap.calculationbasis, aps.calculationbasis) = 1 -- 1=weeks in use, 2=washes
                                                     then
                                                     get_depreciation_percent(nvl(ap.residualvaluescheme_id, aps.residualvaluescheme_id),
                                                                              ceil((uif.daysincircprevissue +
                                                                                    (trunc(sysdate) - uif.lastissuedate)) / 7))
                                                    else
                                                     get_depreciation_percent(nvl(ap.residualvaluescheme_id, aps.residualvaluescheme_id),
                                                                              ui.washestotal)
                                                  end) / 100, cu.decimals)
               else
                nvl(ap.price, aps.price)
             end,
             -- detetermine price
             0, gv_systemuserid, sysdate,
             case lv_lossforpoolmethod
               when 1 then
                (select iflp.invoicefrequencylossperiod_id
                 from   invoicefrequencylossperiod iflp
                 where  iflp.invoicefrequency_id = c.invoicefrequency_id
                 and    iflp.enddate = (select max(iflp2.enddate)
                                        from   invoicefrequencylossperiod iflp2
                                        where  iflp2.invoicefrequency_id = iflp.invoicefrequency_id
                                        and    iflp2.enddate <= trunc(sysdate)))
               else
                null
             end, c.losschargetrigger,
             case
               when c.losschargetrigger = 1 then
                ui.lastscandate
               else
                null
             end lastscandate, sysdate, trunc(nvl(ui.lastdeliverydate, ui.lastoutscandate))
      from   uniqueitem ui
      join   product p
      on     p.product_id = ui.product_id
      join   uniqueitemfixedinfo uif
      on     uif.uniqueitem_id = ui.uniqueitem_id
      join   packingnote pn
      on     pn.notenumber = ui.lastdeliverynotenumber
      join   distributionpoint dp
      on     ((dp.distributionpoint_id = ui.distributionpoint_id and gv_lossforpooldepartment = 0) or
                (dp.distributionpoint_id = pn.distributionpoint_id and gv_lossforpooldepartment = 1  and pn.deliverydate>= nvl(trunc(ui.lastinscandate), pn.deliverydate-1)
              and ui.stay_id not in (select st.stay_id from stay st where st.staytype=1 and st.staynr in (29,30))))
      join   department dep
      on     dep.department_id = dp.department_id
      join   customer c
      on     c.customer_id = dep.customer_id
      join   businessunit bu
      on     bu.businessunit_id = c.defaultbusinessunit_id
      join   currency cu
      on     cu.currency_id = c.currency_id
      left   join (select plpc.customer_id, plpc.product_id, plpc.sizedefinition_id,
                          plpc.finishingmethod_id, plpc.dateactive, plpc.dateinactive,
                          plpc.chargelossuniquepooldays, rv.calculationbasis,
                          plpc.residualvaluescheme_id, plpc.chargelossforpool,
                          pack_price.replacement_price(plpc.customer_id, plpc.product_id,
                                                        plpc.sizedefinition_id, plpc.finishingmethod_id) price
                   from   productlistpercustomer plpc
                   join   residualvaluescheme rv
                   on     rv.residualvaluescheme_id = plpc.residualvaluescheme_id
                   where  plpc.chargelossforpool = 'Y') ap
      on     ap.customer_id = dep.customer_id
      and    ap.product_id = ui.product_id
      and    ap.sizedefinition_id = ui.sizedefinition_id
      and    ap.finishingmethod_id = ui.finishingmethod_id
      and    sysdate between ap.dateactive and ap.dateinactive
      left   join (select plpc.customer_id, plpc.product_id, plpc.sizedefinition_id,
                          plpc.finishingmethod_id, plpc.dateactive, plpc.dateinactive,
                          plpc.chargelossuniquepooldays, rv.calculationbasis,
                          plpc.residualvaluescheme_id, plpc.chargelossforpool,
                          pack_price.replacement_price(plpc.customer_id, plpc.product_id,
                                                        plpc.sizedefinition_id, plpc.finishingmethod_id) price
                   from   productlistpercustomer plpc
                   join   residualvaluescheme rv
                   on     rv.residualvaluescheme_id = plpc.residualvaluescheme_id
                   where  plpc.chargelossforpool = 'Y'
                   and    plpc.sizedefinition_id = gv_sizestarid) aps
      on     aps.customer_id = dep.customer_id
      and    aps.product_id = ui.product_id
      and    aps.sizedefinition_id = gv_sizestarid
      and    aps.finishingmethod_id = ui.finishingmethod_id
      and    sysdate between aps.dateactive and aps.dateinactive
      where  ui.poolitem = 1 --(pool item)
      and    nvl(ap.chargelossforpool, aps.chargelossforpool) = 'Y'
      and    nvl(ap.chargelossuniquepooldays, aps.chargelossuniquepooldays)>0
      and    bu.plant_id = gv_plantid
      and    p.chargelossforpool = 'Y'
      and    c.chargelossforpoolitems = 1
      and    ui.lastoutscandate is not null
      and    ((c.losschargetrigger = 0 -- based on outscan date
            and nvl(ap.dateactive, aps.dateactive) <= trunc(ui.lastoutscandate) and
            nvl(ap.dateinactive, aps.dateinactive) >= trunc(ui.lastoutscandate) and
            trunc(ui.lastoutscandate) <= ((case
              when lv_lossforpoolmethod = 1 then
               (select iflp.cutoffdate
                from   invoicefrequencylossperiod iflp
                where  iflp.invoicefrequency_id = c.invoicefrequency_id
                and    iflp.enddate = (select max(iflp2.enddate)
                                       from   invoicefrequencylossperiod iflp2
                                       where  iflp2.invoicefrequency_id = iflp.invoicefrequency_id
                                       and    iflp2.enddate <= trunc(sysdate)))
              else
               trunc(sysdate) - nvl(ap.chargelossuniquepooldays, aps.chargelossuniquepooldays)
            end)) -- most important: lastoutscandate before cutoffdate
            and trunc(ui.lastoutscandate) >= c.losschargestartdate) or
            (c.losschargetrigger = 1 -- based on outscan date
            and nvl(ap.dateactive, aps.dateactive) <= trunc(ui.lastscandate) and
            nvl(ap.dateinactive, aps.dateinactive) >= trunc(ui.lastscandate) and
            trunc(ui.lastscandate) <= ((case
              when lv_lossforpoolmethod = 1 then
               (select iflp.cutoffdate
                from   invoicefrequencylossperiod iflp
                where  iflp.invoicefrequency_id = c.invoicefrequency_id
                and    iflp.enddate = (select max(iflp2.enddate)
                                       from   invoicefrequencylossperiod iflp2
                                       where  iflp2.invoicefrequency_id = iflp.invoicefrequency_id
                                       and    iflp2.enddate <= trunc(sysdate)))
              else
               trunc(sysdate) - nvl(ap.chargelossuniquepooldays, aps.chargelossuniquepooldays)
            end)) -- most important: lastscandate before cutoffdate
            and trunc(ui.lastscandate) >= c.losschargestartdate) or
            (c.losschargetrigger = 2 and nvl(ap.dateactive, aps.dateactive) <=
            trunc(nvl(ui.lastdeliverydate, ui.lastoutscandate)) and
            nvl(ap.dateinactive, aps.dateinactive) >=
            trunc(nvl(ui.lastdeliverydate, ui.lastoutscandate)) and
            nvl(ui.lastdeliverydate, ui.lastoutscandate) <= ((case
              when lv_lossforpoolmethod = 1 then
               (select iflp.cutoffdate
                from   invoicefrequencylossperiod iflp
                where  iflp.invoicefrequency_id = c.invoicefrequency_id
                and    iflp.enddate = (select max(iflp2.enddate)
                                       from   invoicefrequencylossperiod iflp2
                                       where  iflp2.invoicefrequency_id = iflp.invoicefrequency_id
                                       and    iflp2.enddate <= trunc(sysdate)))
              else
               trunc(sysdate) - nvl(ap.chargelossuniquepooldays, aps.chargelossuniquepooldays)
            end)) and nvl(ui.lastdeliverydate, ui.lastoutscandate) >= c.losschargestartdate))
      and    not exists -- and not already marked as lost via outscan date
       (select uil.uniqueitemloss_id
              from   uniqueitemloss uil
              where  uil.uniqueitem_link_id = ui.uniqueitem_id
              and    uil.lossstatus <= 1
              and    trunc(uil.outscandate) = trunc(ui.lastoutscandate))
      and    not exists -- and not already marked as lost via last scan date
       (select uil.uniqueitemloss_id
              from   uniqueitemloss uil
              where  uil.uniqueitem_link_id = ui.uniqueitem_id
              and    uil.lossstatus <= 1
              and    trunc(uil.lastscandate) = trunc(ui.lastscandate))
      and    not exists
       (select uil.uniqueitemloss_id
              from   uniqueitemloss uil
              where  uil.uniqueitem_link_id = ui.uniqueitem_id
              and    uil.lossstatus <= 1
              and    uil.lastdeliverydate = trunc(nvl(ui.lastdeliverydate, ui.lastoutscandate)));
    commit;



-- STEP 4 Service charge Loss for pool--------------------------------------------------------------
    gv_message := 'STEP 4 Loss for pool item';
    write_log(gv_message);
    Begin
     merge into repairhistory rh
     using (select buse.variableservice_id, c.customer_id, dp.distributionpoint_id, ui.customerowned,
         c.variableservices,  rt.defaulttime, ui.uniqueitem_id,ui.primaryid,ui.businessunit_id,p.product_id,
         F_RepairPrice(plpc.customer_id,rt.repairtype_id, sysdate,1) repairprice,c.currency_id,
         p.supplier_id,
         (select min(CUSTOMERACTIVITIES.INVOICEBUSINESSUNIT_ID)
             from CUSTOMERACTIVITIES, PRODUCTGROUP, PRODUCT
           where CUSTOMERACTIVITIES.CUSTOMER_ID = c.customer_id and
                 CUSTOMERACTIVITIES.ACTIVITY_ID = PRODUCTGROUP.ACTIVITY_ID and
                 PRODUCT.PRODUCTGROUP_ID = PRODUCTGROUP.PRODUCTGROUP_ID and
                 PRODUCT.PRODUCT_ID = p.product_id)invbu_id
       from  uniqueitem ui,
             uniqueitemloss uil,
             department dep,
             distributionpoint dp,
             productlistpercustomer plpc,
             product                p,
             customer  c,
             buservicechargeevent buse, businessunit bu, repairtype rt
       where ui.poolitem = 1 --(pool item)
         and ui.distributionpoint_id = dp.distributionpoint_id
         and dp.department_id = dep.department_id
         and dep.customer_id = c.customer_id
         and uil.uniqueitem_link_id = ui.uniqueitem_id
         and uil.lossstatus=0 --to be charged
         and ui.lastoutscandate is not null
         and plpc.customer_id = dep.customer_id
         and plpc.product_id = ui.product_id
         and plpc.dateactive <= trunc(ui.lastoutscandate)
         and plpc.dateinactive >= trunc(ui.lastoutscandate)
         and plpc.customer_id = c.customer_id
         and p.product_id = plpc.product_id
         and p.chargelossforpool = 'Y'
         and plpc.chargelossforpool = 'Y'
         and ((plpc.sizedefinition_id = ui.sizedefinition_id)
             or (plpc.sizedefinition_id=(select a.sizedefinition_id from sizedefinition a where a.code='*')))
         and plpc.finishingmethod_id = ui.finishingmethod_id
         and buse.businessunit_id=ui.businessunit_id
         and buse.servicechargeevent_id=7--Loss for pool item
         and buse.variableservice_id =rt.repairtype_id
         and ui.businessunit_id=bu.businessunit_id
         and bu.plant_id= gv_plantid
         and c.variableservices in (1,2)
         and (c.variableservices =1  or (c.variableservices=2 and F_RepairPrice(plpc.customer_id,rt.repairtype_id, sysdate,1) is not null ))
         order by bu.businessunit_id, c.customer_id,dp.distributionpoint_id,p.product_id,  ui.uniqueitem_id ) MERGE_SUBQUERY
           on  (rh.uniqueitem_link_id=MERGE_SUBQUERY.uniqueitem_id
           and rh.customer_link_id=MERGE_SUBQUERY.customer_id
           and rh.distributionPoint_Link_id=MERGE_SUBQUERY.distributionpoint_id
           and rh.repairtype_id=MERGE_SUBQUERY.variableservice_id
           and rh.customerowned=MERGE_SUBQUERY.customerowned
           and trunc(rh.timestamp)=trunc(sysdate)
          and ((rh.status= 1 and MERGE_SUBQUERY.variableservices  = 1) or
            (rh.status= 0 and MERGE_SUBQUERY.variableservices  = 2))  )
    when matched then
      Update
      set rh.quantity=rh.quantity+1
      WHEN NOT MATCHED THEN
        INSERT
                (REPAIRHISTORY_ID,
                SUPPLIER_ID,
                CURRENCY_ID,
                PRODUCT_LINK_ID,
                DISTRIBUTIONPOINT_LINK_ID,
                WEAREREMPLOYMENT_LINK_ID,
                CUSTOMER_LINK_ID,
                REPAIRTYPE_ID,
                UNIQUEITEM_LINK_ID,
                BUSINESSUNIT_ID, REPAIRDATE,
                MINUTES,
                YEAR, WEEK, DAY,
                POOL,
                UNITPRICE,
                PRICEPERMINUTE,
                SYSTEMUSER_ID,
                TIMESTAMP,
                STATUS,
                INVOICEBUSINESSUNIT_ID,
                INVOICEHEADER_ID,
                PRIMARYID,
                AMOUNT,
                QUANTITY,
                CUSTOMEROWNED)
         VALUES
               (SEQ_REPAIRHISTORY.NEXTVAL,
               MERGE_SUBQUERY.SUPPLIER_ID,
               MERGE_SUBQUERY.CURRENCY_ID,
               MERGE_SUBQUERY.PRODUCT_ID,
               MERGE_SUBQUERY.DISTRIBUTIONPOINT_ID,
               NULL,
               MERGE_SUBQUERY.CUSTOMER_ID,
               MERGE_SUBQUERY.VARIABLESERVICE_ID,
               MERGE_SUBQUERY.UNIQUEITEM_ID,
               MERGE_SUBQUERY.BUSINESSUNIT_ID,
               SYSDATE,
               MERGE_SUBQUERY.DEFAULTTIME,
               YEAR(SYSDATE),GETISOWEEK(SYSDATE), GETDAYNUMBER(SYSDATE),
               'Y',
               NULL,
               NULL,
               gv_systemuserid ,
               SYSDATE,
               CASE  WHEN MERGE_SUBQUERY.VARIABLESERVICES= 1 THEN 1
                 ELSE 0 END ,--STATUS
               MERGE_SUBQUERY.INVBU_ID,
               NULL,
               MERGE_SUBQUERY.PRIMARYID,
               0,
               1,
               MERGE_SUBQUERY.CUSTOMEROWNED
              );
       commit;
       exception when no_data_found then null;
      end;

    write_log('END PACK_LOSSFORPOOL.LOSSFORPOOLPROCESS SUCCESSFUL');
    --close files
    end_log;
    commit;

    return gv_returnvalue;
  exception
    when gv_userexception then
      begin
        rollback;
        write_log('...return1 ' || to_char(gv_returnvalue));
        end_log;
        if gv_returnvalue = return_ok then
          gv_returnvalue := 2;
        end if;
        return gv_returnvalue;
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log(gv_message, priority_error);
        write_log('...return2 ' || to_char(gv_returnvalue));
        rollback;
        end_log;
        if gv_returnvalue = return_ok then
          gv_returnvalue := return_failed_unknown;
        end if;
        return gv_returnvalue;
      end;
  end lossforpoolprocess;

  ---------------------------------------------------------------------------------------------------
  procedure recalc_not_invoiced_lossforpool(fp_plant_id in plant.plant_id%type,
                                            fp_recalc_days number default 32) is
    lv_amount                 uniqueitemloss.lossamount%type;
    lv_price                  number;
    lv_residualvaluescheme_id residualvaluescheme.residualvaluescheme_id%type;
    lv_calculationbasis       residualvaluescheme.calculationbasis%type;
  begin
    gv_message := 'START PACK_LOSSFORPOOL.RECALC_NOT_INVOICED_LOSSFORPOOL';
    write_log(gv_message, priority_message);

    gv_plantid :=  fp_plant_id;
    initialise;

    for x in (select ul.uniqueitemloss_id,
                     ul.lossamount,
                     uif.daysincircprevissue,
                     uif.lastissuedate,
                     ui.washestotal,
                     cu.decimals,
                     dep.customer_id,
                     ui.product_id,
                     ui.sizedefinition_id,
                     ui.finishingmethod_id
                from uniqueitemloss ul
                join uniqueitem ui
                  on ui.uniqueitem_id = ul.uniqueitem_link_id
                join uniqueitemfixedinfo uif
                  on uif.uniqueitem_id = ui.uniqueitem_id
                join packingnote pn
                  on pn.notenumber = ui.lastdeliverynotenumber
                join distributionpoint dp
                  on ((dp.distributionpoint_id = ui.distributionpoint_id and
                     gv_lossforpooldepartment = 0) or
                     (dp.distributionpoint_id = pn.distributionpoint_id and
                     gv_lossforpooldepartment = 1 and
                     pn.deliverydate >=
                     nvl(trunc(ui.lastinscandate), pn.deliverydate - 1) and
                     ui.stay_id not in
                     (select st.stay_id
                          from stay st
                         where st.staytype = 1
                           and st.staynr in (29, 30))))
                join department dep
                  on dep.department_id = dp.department_id
                join customer c
                  on c.customer_id = dep.customer_id
                join businessunit bu
                  on bu.businessunit_id = c.defaultbusinessunit_id
                join currency cu
                  on cu.currency_id = c.currency_id
               where nvl(ul.losschargedate, pn.deliverydate) > trunc(sysdate) - fp_recalc_days
                 and ul.lossinvoiceheader_id is null
                 and ul.creditinvoiceheader_id is null
                 and bu.plant_id = gv_plantid) loop

      gv_message := 'uniqueiteloss: ' || x.uniqueitemloss_id;

      begin
        select (select pack_price.replacement_price(plpc.customer_id,
                                            plpc.product_id,
                                            plpc.sizedefinition_id,
                                            plpc.finishingmethod_id,
                                            sysdate) from dual),
               rv.residualvaluescheme_id,
               rv.calculationbasis
          into lv_price, lv_residualvaluescheme_id, lv_calculationbasis
          from productlistpercustomer plpc
          join residualvaluescheme rv
            on rv.residualvaluescheme_id = plpc.residualvaluescheme_id
         where plpc.customer_id = x.customer_id
           and plpc.product_id = x.product_id
           and plpc.sizedefinition_id = x.sizedefinition_id
           and plpc.finishingmethod_id = x.finishingmethod_id
           and plpc.chargelossforpool = 'Y'
           and sysdate between plpc.dateactive and plpc.dateinactive;
      exception
        when no_data_found then
          begin
            select (select pack_price.replacement_price(plpc.customer_id,
                                                plpc.product_id,
                                                plpc.sizedefinition_id,
                                                plpc.finishingmethod_id,
                                                sysdate) from dual),
                   rv.residualvaluescheme_id,
                   rv.calculationbasis
              into lv_price, lv_residualvaluescheme_id, lv_calculationbasis
              from productlistpercustomer plpc
              join residualvaluescheme rv
                on rv.residualvaluescheme_id = plpc.residualvaluescheme_id
             where plpc.customer_id = x.customer_id
               and plpc.product_id = x.product_id
               and plpc.sizedefinition_id = gv_sizestarid
               and plpc.finishingmethod_id = x.finishingmethod_id
               and plpc.chargelossforpool = 'Y'
               and sysdate between plpc.dateactive and plpc.dateinactive;
          exception
            when no_data_found then
              begin
                gv_message := 'No PLPC for custid/prodid: ' || x.customer_id || '/' || x.product_id;
                write_log(gv_message, priority_error);
              end;
          end;
      end;

      lv_amount := case
                     when gv_lossforpoolprice = 2 -- then charge residual value, else full replacement price
                      then
                      round(lv_price * (case
                              when lv_calculationbasis = 1 -- 1=weeks in use, 2=washes
                               then
                               get_depreciation_percent(lv_residualvaluescheme_id,
                                                        ceil((x.daysincircprevissue +
                                                             (trunc(sysdate) -
                                                             x.lastissuedate)) / 7))
                              else
                               get_depreciation_percent(lv_residualvaluescheme_id,
                                                        x.washestotal)
                            end) / 100,
                            x.decimals)
                     else
                      lv_price
                   end;

      if (x.lossamount <> lv_amount) then
        update uniqueitemloss ul
           set ul.lossamount = lv_amount, ul.timestamp = sysdate
         where ul.uniqueitemloss_id = x.uniqueitemloss_id;
      end if;

    end loop;
    commit;

    gv_message := 'END PACK_LOSSFORPOOL.RECALC_NOT_INVOICED_LOSSFORPOOL SUCCESSFUL';
    write_log(gv_message, priority_message);

  exception
    when others then
      begin
        write_log(sqlerrm || '/' || gv_message, priority_error);
        rollback;
      end;

  end recalc_not_invoiced_lossforpool;

end pack_lossforpool;
/
create or replace package pack_multiread is
  -- Version 3.39 Pack_MultiRead
  -- Purpose : Contains logic for validation and processing multi read batches
  -- Created : 28-09-2012 HVH New
  -- Updated : 21-06-2013 HVH Fix issue for situation when same tag exists in multiple BU's
  -- Updated : 08-07-2013 HVH Fix issue with finding ragged items
  -- Updated : 17-07-2013 HVH Fix issue with not creating inscans for pool items that were never outscanned
  -- Updated : 01-08-2013 HVH Fix issue with outscan pool items - mark processed
  -- Updated : 02-08-2013 HVH Fix issue with in/outscan garments for customers without route
  -- Updated : 27-11-2013 HVH Add f_domultireadrewashbatch and f_domultireadragscanbatch
  --                          Fix issue in inscan with populating uniqueitemroute lastinroutestop_id
  --                          when systemsetting deliverydetermination=1
  --                          Optimized peformance for inscan/outscan when deliverdetermination=1
  -- Updated : 06-12-2013 HVH Todo 23777 Look at system setting UHFPOOLITEMSTARTUPPHASE
  -- Updated : 11-12-2013 HVH Order 20014643 Added f_domultireadstackprocess
  -- Updated : 12-12-2013 HVH Todo 23777 Also for pool items look at INSCANALLOWHOURINTERVAL
  -- Updated : 19-12-2013 HVH Order 20014643 Do not create deliveryscan for pool items instead link scan to packingnote
  -- Updated : 24-12-2013 HVH Order 20014316 Allow outscan garments at the delivery note
  -- Updated : 08-01-2014 HVH Todo 23045 Solve exception in inscan when creating delvar's when del.date could not be determined
  -- Updated : 31-01-2014 HVH Todo 24060 Fix issue with delivered qty too low when uhfpoolitemstartupphase = 'N'
  -- Updated : 18-02-2014 HVH Order 20014316 Allow outscan garments at the delivery note check customer
  -- Updated : 03-06-2014 HVH Order 20015191 Add function f_domultireadonsiteinventscan
  -- Updated : 16-06-2014 HVH Order 20015191 Add feature for returndate uniqueitemloss based on last scan date
  -- Updated : 23-06-2014 HVH Order 20015466 Add recievescan implementation function f_domultireadreceivescan
  -- Updated : 16-07-2014 HVH Todo 25301 Fix performance issue inscan: added hints in decrease_onsite_inventory and improved create_flags_maxwash
  --                                     also added hint for step 1A validate outscan pool batch
  -- Updated : 25-07-2014 HVH Todo 25414 Implemented remove flags
  -- Updated : 03-08-2014 HVH Todo 25560 Populate ScanFlag table
  -- Updated : 28-08-2014 HVH Order 20013062 Extend f_domultireadonsiteinventscan for garment assistant processing
  -- Updated : 30-08-2014 HVH Todo 25644 OutscanPoolBatch: also treat uniqueitems in packs
  -- Updated : 10-09-2014 PVD Todo 25693 f_validatestack step 1B on secondary id
  -- Updated : 26-09-2014 HVH Todo 25812 Fix issue cannot insert null into scanflag.scan_ID
  -- Updated : 26-09-2014 HVH Order 20015650 Add sendtolaundryscan implementation function f_domultireadsendscanbatch
  -- Updated : 28-10-2014 HVH Order 20015606 Add condition to only update onsite inventory when plpc.onsiteiventorycheck=Y
  -- Updated : 25-11-2014 HVH BF 20015914 - Delivery note is not refreshing
  -- Updated : 26-11-2014 AAL BF 20015914 - Delivery note is not refreshing
  -- Updated : 29-12-2014 HVH Order 20014317 Update BU at inscan only for pool items and only if they do not have a sec.ID
  --                                         Same BU update logic implmented for outscan and rewashscan
  --                                         Performance improvements on all validations (requires extra indexes)
  --                                         Automatically clean up batches older than 5 days
  -- Updated : 21-01-2015 AAL Order 20012675 - Behind the folders
  -- Updated:  24-02-2015 HVH Order 20016093 Create Delivery Variations with SendtoLaundry Scan
  --                                         Also solved issues of wrong delivery date on delivery variations and wrong customer_id
  --                                         in scan table for items that are customer related
  --                                         wrong related customer ID restored when undoing a rag that was customer related
  -- Updated : 20-03-2015 HVH Todo 26828 Fix issue: Primary ID in scan table was populated with secondary ID in case secondary ID was scanned
  --                                     Fix issue: createscanflag for send and receive scans gave parent key not found error
  -- Updated : 13-04-2015 HVH Order 20016281 Add optional parameter pickupdate to f_domultireadinscanbatch
  -- Updated : 17-04-2015 HVH Todo 25812 Fix peformance issue with updating uniqueitemloss
  -- Updated : 01-05-2015 HVH Order 20016361 Change finishingmethod of unique pool item during outscan depending on syst.setting CHANGEFMFORPOOLMULTIREAD
  -- Updated : 19-05-2015 HVH Todo ABS-6271 Fix issue determining planned delivery date in case items had different delayed even exchange settings in plpc
  -- Updated : 26-06-2015 HVH Todo ABS-3893 Fix issue not allowing to outscan pool items that are in plpc with size *
  -- Updated : 01-07-2015 HVH Order ABS-9431 Don't update uniqueitem for send to laundry and receive from laundry, when another scan was done meanwhile
  -- Updated : 21-07-2015 HVH Order ABS-7199 Implement handling partly tagged bundled in CompleteBundleOutscan
  -- Updated : 21-07-2015 HVH Order ABS-11318 Implement less strict check on outscanning customer related pool items
  -- Updated : 10-09-2015 JVL ABS-14203 Temp change in pack_multiread for scan on deliverynote for FIS
  -- Updated : 20-10-2015 PVD Order ABS-15038 Version 1.1 UHF Receive scan with Portal at Customer icw Virtual Bundle functionality
  -- Updated : 29-10-2015 JVL ABS-17369 No del var based on Inscan multi read for FIS
  -- Updated : 04-11-2015 PVD take into account the timedifference of the plant as well
  -- Updated : 06-11-2015 HVH ABS-13664 Automatic Assign via Stack Check
  -- Updated : 12-11-2015 PVD ABS-17580 UHF Report Average Circulation Speed, add scan since days to scan table
  -- Updated : 13-11-2015 PVD ABS-10962 Automatically undo rag for pooled items at inscan
  -- Updated : 17-11-2015 PVD ABS-11726 Do not decrease onsite inventory upon inscan when customer is setup for allocation
  -- Updated : 06-01-2016 PVD ABS-20686 Unrag changing FM of product, take finishingmethod_id from raggeditem, requires update script!
  -- Updated : 15-01-2016 HVH ABS-16905 Add UHF container recording (KNT module uses multireadbatchcontKNT table)
  -- Updated : 01-02-2016 HVH ABS-22037 Customer ID not always populated in rejectedscan for send and receive scans
  -- Updated : 11-03-2016 ARC ABS-24348 Inscan Multi Read empty grid
  -- Updated : 02-05-2016 HVH ABS-25146 Solved issue not processing inventory counts because of following error message:
  --                                    Error in Process On-site Inventory Batch - Create on-site inventory adjustments -1722 ORA-01722: invalid number
  -- Updated : 02-05-2016 HVH ABS-27873 Solved issue of slow processing inscans due to Oracle using wrong index on deliveryvariations
  -- Updated : 03-05-2016 HVH ABS-27609 Support KNT scans in receive from laundry and send to laundry
  -- Updated : 04-05-2016 HVH ABS-27609 Fix issue that secondary container ID's were not always validated
  -- Updated : 17-05-2016 HVH ABS-27596 For receive from and send to laundry changed that items that are not scanned out are no longer rejected
  --                                    depending on system setting SHIPMENTCHECKPERDELNOTE
  -- Updated : 17-05-2016 HVH ABS-27596 Also populate lastoutscandate so that losscharge billing will work based on receive/send date
  -- Updated : 09-06-2016 PVD ABS-29489 Production - Incorrect delivery date of delivery variations, intialize gv_pickupdate
  -- Updated : 29-06-2016 ICG ABS-30808 Added Exception for duplicate values in procedure create_reject_scans
  -- Updated : 29-06-2016 HVH ABS-26114 For bulkpackingnotes distribute the items to the child packingnotes to link them as much as possible to the right cons.point
  -- Updated : 11-07-2016 HVH ABS-31879 When system setting UHFINSCANTRACKINGONLY is set to Y then do not create delivery variations or decrease on-site inventory upon inscan
  -- Updated : 03-08-2016 HVH ABS-33264 Populate scan.scandateoffset in case a pickupdate was passed.
  -- Updated : 03-08-2016 HVH ABS-21481 Add virtual scans caused by bundle mechanism during validation
  -- Updated : 04-08-2016 HVH ABS-32995 Populate packingnoteline.scannedqty and link not ordered items to child PN with highest note#
  -- Updated : 09-08-2016 HVH ABS-33538 Improved query for finding old to-be-cleaned-up batches
  -- Updated : 11-08-2016 HVH ABS-32995 Fix issue that overdeliveries where not always linked to the childnote with the highest note# and fixed that scanned qty was not always updated
  -- Updated : 11-08-2016 HVH ABS-33834 When parameter fp_trackonly=Y then leave packingnote/packingnotelines untouched for outscanpool
  -- Updated : 05-09-2016 HVH ABS-32995 Fix issue that delivedqty field was not updated for child packingnotes
  -- Updated : 05-09-2016 HVH ABS-21030 New function for unattended scanning domultireadunattended
  -- Updated : 15-09-2016 ARC ABS-35896 Removed duplicates in selecting unique items with prohibit delivery flags while outscanning, to mark the exception reason
  -- Updated : 26-09-2016 HVH ABS-35219 Support value 3 for system setting UHFPOOLITEMSSTARTUPCALC always ordered qty
  -- Updated : 06-10-2016 PVD ABS-6155 ABS-36289. do not create outscan but checkpoint scan for garmentdispenser wearers, with noregularoutscan set
  -- Updated : 10-10-2016 HVH ABS-30808 Fix issue with duplicate rejectscan on inscan + fix null insert in OUTOFCIRCULATIONHISTORY.WEEKSINUSETHISISSUE + update uniqueitem_link.timestamp during rag
  -- Updated : 25-10-2016 HVH ABS-38520 Check on customer in validate_stack for personalized garments
  -- Updated : 31-10-2016 HVH ABS-38833 For customer PLS do not create delivery variations nor update onsite inventory
  -- Updated : 31-10-2016 HVH ABS-38164 Fix incorrect date for delivery variations caused by send to laundry scan
  -- Updated : 04-11-2016 HVH ABS-7437  Implemented UHF buffer tracking
  -- Updated : 09-11-2016 HVH ABS-39293 In case onsite inventory scans from LA are resend, do not return an error
  -- Updated : 14-12-2016 HVH ABS-30808 Added extra logging to store batch# and subbatch#
  -- Updated : 19-01-2017 HVH ABS-43999 Fix issue with UHF buffer tracking in stack check and when processing was not done immediately with validation (so when subbatch was 0)
  --                                    + clean up batches based on scantimestamp, not on lastscantimestamp
  -- Updated : 25-01-2017 HVH ABS-44277 Fill scan.distributionpoint_id during inscan with ui.lastdistrib for items that were inscanned before without outscan in between
  -- Updated : 23-02-2017 HVH ABS-46385 Fix issue that some not found items do not get any exeception reason and cause the buttons to remain inactive for outscan and recieve scan
  -- Updated : 27-02-2017 HVH ABS-36825 Implement outscan via Scans and Counts  + store soilcountsubtype 7 (inscan) in delivery variations
  --                                    Also fixed: do not calculate time zone difference when creating virtual scans + removal of undeeded read of OVERALLUNIQUEGARMENTID setting
  --                                    Also implemented: create GDtransaction for items not inscanned for interface Std+WnC for outscanpool
  -- Updated : 02-03-2017 HVH ABS-40156 Pack_check
  -- Updated : 08-03-2017 HVH ABS-41358 Store business unit of unique item instead of BU of workstation in scan table for send and receive from laundry. To prevent reporting problems when scanning with LA
  -- Updated : 08-03-2017 HVH ABS-22517 Do not charge washing in case of garmentdispenser that has NoRegularOutScanCustPool or NoRegularOutScanGenPool activated
  -- Updated : 15-03-2017 HVH ABS-40156 Fixed Issues on Pack_check
  -- Updated : 24-03-2017 HVH ABS-40156 Fixed division by zero in outscan packs
  -- Updated : 17-05-2017 PVD ABS-11734 Exchange Cart Solution for UHF scanning
  -- Updated : 18-05-2017 PVD ABS-49247 Exchange Cart Clean Return Touchscreen
  -- Updated : 26-05-2017 VPA ABS-35896 Removed duplicates in selecting unique items with prohibit delivery flags while outscanning, to mark the exception reason (rework for the remaining 3 scenarios)
  -- Updated : 16-06-2017 PVD ABS-47625 Duplicate scans ignored
  -- Updated : 11-07-2017 MBA ABS-53168 pool towels are not on TEST invoioce
  -- Updated : 12-07-2017 HVH ABS-46769 Fixed issue receive scan screen buttons not active because of incomplete validation due to combination of unknown tags and add virtual scans
  -- Updated : 20-07-2017 HVH LASA-256  Other scan transactiontype for stockcount transactions and optionally update onsite inventory
  -- Updated : 03-08-2017 HVH ABS-54172 Fixed issue in stackcheck when a tag that is known in database, but has an exception, is scanned as only tag
  -- Updated : 06-09-2017 HVH ABS-55410 Create delivery variations for pool items not outscanned but are related to customer with 1 department
  -- Updated : 06-09-2017 HVH ABS-55411 Improved performance outscanpool multiread when virtual bundles are used
  -- Updated : 27-09-2017 HVH ABS-56030 Fixed issue that sometimes too many virtual non unique items were created
  -- Updated : 25-10-2017 DCI ABS-53261 Changes to customer packing note
  -- Updated : 30-10-2017 PVD ABS-54916 Create Outscans via Stack Check Multi Read
  -- Updated : 13-12-2017 PVD ABS-53700/ABS-59484 MultiRead + SingleRead UHF support for CleanRoomBatch module
  -- Updated : 27-12-2017 HVH ABS-59122 Create delivery variations for cons.point the item was originally delivered to
  -- Updated : 22-01-2018 HVH ABS-53725 Various new features for various use cases
  -- Updated : 13-02-2018 PVD ABS-62337/ABS-62385 Garment Assistant => Locker feeding PART-2 MOBILE
  -- Updated : 16-02-2018 HVH ABS-53725 Correction for personalized garment stacks do not look at customer.allowmixedproducts
  -- Updated : 21-02-2018 HVH ABS-32402 Use virtual bundle % to prevent stray reads
  -- Updated : 02-06-2018 PVD ABS-65360 Stack check and Direct Load, adding fp_reason_id to f_domultireadrewashscanbatch
  -- Updated : 03-07-2018 HVH ABS-68541 Duplicate containers causing eternal loop
  -- Updated : 10-07-2018 HVH ABS-68424 Stack check and direct load, populate addition columns in uhfbundle and populate packingnotecontainercont during outscan pool
  -- Updated : 27-08-2018 HVH ABS_60194 Additional unattended transactiontype: soiled in garment dispenser
  -- Updated : 30-08-2018 HVH ABS-64092 Containers inscan and disinfection scan via unattended scanning
  -- Updated : 03-09-2018 JVL ABS-46843 Added features for Multiread Scan Clean Returned Linen
  -- Updated : 04-09-2018 HVH ABS-64092 Correction for disinfection scan
  -- Updated : 06-02-2019 HVH ABS-71968 Implementation pool stack flow with module STACKLABEL
  -- Updated : 14-02-2019 CTI ABS-71608 (New) Modules Guaranteed Delivery Minimum + Temporary Assignment of Pool Garments
  -- Updated : 18-02-2019 HVH ABS-71968 Fix for pool stack flow with module STACKLABEL
  -- Updated : 20-02-2019 CTI ABS-71608 (New) Modules Guaranteed Delivery Minimum + Temporary Assignment of Pool Garments
  -- Updated : 08-03-2019 DLA ABS-71968 Fix for customer related stack when no packingnote available with module STACKLABEL
  -- Updated : 11-03-2019 DLA ABS-71968 Fix for creating uhfbundle when packingnoteid = -1
  -- Updated : 24-06-2019 JVL ABS-78288 in Shipmentcheckscan Module no Garments can't be scant in Receive from laundry and send to laundry
  -- Updated : 26-08-2019 EGA ABS-81312 Automatic generation PN with reason REWASH in Rewash Multi Read
  -- Updated : 09-09-2019 ARC ABS-89144 PACK_MULTIREAD does not delete empty MULTIREADSCANBATCH records (older than 5 days)
  -- Updated : 20-09-2019 PVD ABS-89032 Add extra scans to PN
  -- Updated : 11-10-2019 ARC ABS-89144 PACK_MULTIREAD does not delete empty MULTIREADSCANBATCH records (older than 5 days) - rework programming: usage of month number + format instead of month name
  -- Updated : 05-11-2019 LAC ABS-83581 Pack Multiread generates too much log information - replaced the system settting DEBUG_LEVEL with MULTIREAD_DEBUG_LEVEL
  -- Updated : 11-10-2019 HVH ABS-90735 for poolitems with stay in laundry outside hour interval prevent that delivery variations are created
  -- Updated : 29-01-2020 DLA ABS-95739 Reject customer related stack if NO PN
  -- Updated : 26-05-2020 HVH ABS-97301 Populate multireadscanbatch.relatedcustomer_id with customer related to most items in stack for improved mixed customer check in v_multireadstackorpack
  -- Updated : 11-06-2020 PVD ABS-103336 Fill deliveryscan.planneddeliverydate
  -- Updated : 03-07-2020 GAL ABS-104529 Issue delivered quantity
  -- Updated : 07-07-2020 VPA ABS-103019 Throw correct multireadexception reason when Pool Item is ragged
  -- Updated : 16-07-2020 VPA ABS-94756 Rewash column in Packing Production overview
  -- Updated : 29-09-2020 DLA ABS-108518 Delivery variations processbusinessunit_id and internalprocessingbu_id are not filled when creating DV from Pack_multiread
  -- Updated : 29-09-2020 DLA ABS-99714 Ignore already inscanned items with stay "in laundry"
  -- Updated : 26-10-2020 GAL ABS-109721 INDEX to improve performance
  -- Updated : 10-03-2021 APA ABS-47292 Container Rent create&update
  -- Updated : 20-04-2021 HVH ABS-98586 Reject items for other customer in validate outscan
  -- Updated : 30-04-2021 HVH ABS-118650 Do not increase washes at inscan when configured at outscan when inscan within 16 hrs
  -- Updated : 30-04-2021 HVH ABS-99779 Reject inscans within x plant operation hours after processing delivery note UI was outscanned on
  -- Updated : 28-06-2021 MCI ABS-119891 Remove check on database code for ANG and TLK
  -- Updated : 23-09-2021 DMO ABS-117907 Create / Update Container Charge records
  -- Updated : 27-09-2021 DMO ABS-124724 ReturnDate is now updated for container that is returned in the same day
  -- Updated : 25-11-2021 DMO ABS-127875 Wrong ContainerRent.ReturnDate is calculated at Inscan Multi Read when DeliveryDate is today
  -- Updated : 24-02-2022 MCU ABS-128538 Delivery variations are not created for rejects when INscan is done first
  -- Updated : 04-03-2022 EGA ABS-132330 Connection pool exhausted
  -- Updated : 10-03-2022 EGA ABS-132719 Correction needed in pack_multiread.f_domultireadunattended
  -- Updated : 16-03-2022 APE ABS-127596 Ragged item cannot be re-used
  -- Updated : 11-03-2022 HVH ABS-130871 Check on outscan interval for containers + added commit in Step 2 of f_validateoutscanbatchKNT
  -- Updated : 29-03-2022 DLA ABS-125632 Extra UHF MultiRead outscan will make Deliver Qty too high
  -- Updated : 04-05-2022 APA ABS-134144 [QF][EU_UHF] Wrong Multi Read Exception reason when scanning a ragged item in Multi Read Stack Check
  -- Updated : 16-06-2022 PVD ABS-134310 Improvement of stack check multiread regarding bundle quantities
  -- Updated : 11-08-2022 HVH ABS-138205 Reject scans are not storing the consumptionpoint_id
  -- Updated : 27-04-2023 DLA ABS-141932 Deadlock related to UHF function
  -- Updated : 19-12-2023 DLA ABS-141401 Possibility to scan pool items in OutScan SortBatch
  -- Updated : 09-02-2024 MBA ABS-157099 Add RouteStatusControl ExtraInfo for virtual routes
  -- Updated : 14-02-2024 DLA ABS-161272 Container billing
  -- Updated : 19-04-2024 MBA ABS-163303 ABSSolute ELI - Blocking sessions (Revert changes for ABS-141932)
  -- Updated : 04-06-2024 MBA ABS-164590 Prevent deadlocks between merge in MultireadScanBatchContent and delete from MultireadScanBatch
  -- Updated : 14-06-2024 IBA ABS-164267 Update last delivery date on Outscan items with UHF
  -- Updated : 19-06-2024 HVH ABS-156248 Stack check allow mix of products
	-- Updated : 26-06-2024 CMU ABS-156251 PED Outscan based on virtual bundle ID and link to Packing note
  -- Updated : 04-07-2024 HVH ABS-156248 Stack check allow mix of products - correction
  -- Updated : 08-07-2024 HVH ABS-156248 Stack check allow mix of products - correction
  -- Updated : 12-07-2024 IBA ABS-164372 Update UniqueItemloss from client vs pack_multiread
  -- Updated : 10-09-2024 MBA ABS-168914 Improved delete mechanism for PRODUCTIONPROCESSSCAN to prevent/reduce blocking sessions
  -- Updated : 18-09-2024 PVD ABS-169035 Adjustment to pack_multiread.f_domultireadoutscanpoolbatch / ABS-159186 PHL powered by ABS
  -- Updated : 24-10-2024 MBA ABS-169875 Deadlock from Concentrator (prevent long blocking sesssions for delete batch)
  -- Updated : 29-10-2024 MBA ABS-170741 ORA-01403: not data found when use Multiread stack check
  -- Updated : 21-01-2025 EGA ABSN-256 Confirm Container Packing Backend / ABSN-772 API Endpoint for multiread functionality
  -- Updated : 18-07-2025 ABSN-5540 Scan history exception reason
  -- Updated : 27-03-2026 ABSN-12565 No Issue Date in Scan History

 function plantoperatingtimeoverlap(fp_plant_id           in number,
                                     fp_scanstarttimestamp in date,
                                     fp_scanendtimestamp in date)
  return number;
  -- calculates the duration (rounded to minutes) between the passed timestamps, for the time
  -- the passed plant was operating using plantoperatinghours definitions.

  function f_domultireadinscanbatch(fp_multireadscanbatch_id number,
                                    fp_subbatchnumber        number,
                                    fp_action                number,
                                    fp_pickupdate            date default trunc(sysdate),
                                    fp_exchangecart_id       in number default null)
    return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadcleanreturnbatch(fp_multireadscanbatch_id in number,
                                         fp_subbatchnumber        in number,
                                         fp_action                in number,
                                         fp_pickupdate            in date default trunc(sysdate),
                                         fp_exchangecart_id       in number)
    return number;
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

  function f_domultireadoutscanbatch(fp_multireadscanbatch_id number,
                                     fp_subbatchnumber        number,
                                     fp_action                number,
                                     fp_customer_id           number default null)
  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadoutscanpoolbatch(fp_multireadscanbatch_id number,
                                         fp_subbatchnumber        number,
                                         fp_action                number,
                                         fp_trackonly             varchar2 default 'N',
                                         fp_exchangecart_id       number default null)
  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadscanandcountbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number,
                                          fp_consumptionpoint_id   number,
                                          fp_route_id              number,
                                          fp_planneddeliverydate   date,
                                          fp_trackonly             varchar2 default 'N',
                                          fp_batchnumber          varchar2 default null)
  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_docompletebundleoutscan(fp_multireadscanbatch_id number)
  return number;
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_docompletebundlereceivescan(fp_multireadscanbatch_id number)
    return number;
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_douhfstartupphaseprocessing(fp_multireadscanbatch_id number, fp_plant_id number)
  return number;
  -- output result:
  -- 0 = okay
  -- <> 0 = ORA error

  function f_domultireadstackcheck(fp_multireadscanbatch_id number,
                                   fp_subbatchnumber        number,
                                   fp_stacksize             number,
                                   fp_findpack_YN           varchar2)
  return number;
  -- input parameter fp_stacksize:
  -- >0 = selected stacksize from button, 0 = Automatic determined from product, -1 = No check on size
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error
  -- 4 = Stack contents related to other customer than customer of multireadscanbatch.packingnote_id
  -- 5 = Product/size of stack not ordered at multireadscanbatch.packingnote_id
  -- 6 = Exceeded ordered qty at multireadscanbatch.packingnote_id
  -- 7 = Customer related stack while in pool mode with STACKLABEL (multireadscanbatch.packingnote_id = -1)

  function f_domultireadstackprocess(fp_multireadscanbatch_id number,
                                     fp_stacksize number,
                                     fpo_virtualbundle_id out number,
                                     fp_result    number default 0)
  return number;
  -- input result:
  -- 0 = okay
  -- 1 = rejected

  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error


  function f_domultireadrewashscanbatch(fp_multireadscanbatch_id number,
                                        fp_subbatchnumber        number,
                                        fp_action                number,
                                        fp_reason_id             number default null)

  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadragscanbatch(fp_multireadscanbatch_id number,
                                     fp_subbatchnumber        number,
                                     fp_action                number,
                                     fp_reason_id             number,
                                     fp_ragreason_id          number)
  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadonsiteinventscan(fp_multireadscanbatch_id    number,
                                         fp_garmentassistantbatch_yn varchar2 default 'N',
                                         fp_istockcount_yn           varchar2 default 'N')
    return number;
  -- input parameter garmentassistantbatch_yn:
  -- N or or not passed for Linen Assisant. Y for garment Assistant
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadreceivescanbatch(fp_multireadscanbatch_id number,
                                         fp_subbatchnumber        number,
                                         fp_action                number)
  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadonsitelockerscan(fp_multireadscanbatch_id number)
    return number;
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

  function f_domultireadsendscanbatch(fp_multireadscanbatch_id number,
                                      fp_subbatchnumber        number,
                                      fp_action                number)
  return number;
  -- input parameter action  1=validate only 2=process only 3=validate and process
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error

  function f_domultireadunattended(fp_multireadscanbatch_id number,
                                   fp_subbatchnumber        number)
  return number;
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error
  -- 4 = no production process buffer defined for workstation

  function f_domultireadcleanroombatch(fp_multireadscanbatch_id in number,
                                       fp_subbatchnumber        in number,
                                       fp_cleanroombatch_id     in number) return number;
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ORA error
  -- 4 = no production process buffer defined for workstation

  function f_domultireadinscanrejectbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number,
                                          fp_pickupdate            date default trunc(sysdate))
    return number;
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

  function f_domultireadcleanreturnbatch(fp_multireadscanbatch_id in number,
                                         fp_subbatchnumber        in number,
                                         fp_action                in number)
    return number;
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
function f_dostackcheck_secondws(fp_multireadscanbatch_id number,
                                 fp_subbatchnumber        number,
                                 fp_stacksize             number,
                                 fp_findpack_yn           varchar2)
          return number;

function f_getprocessbusinessunit(distributionpointid number, productid number)
  return number;

function f_outscanforvirtualbundle( fp_packingnoteid  number,
                                    fp_businessunitid number,
                                    fp_systemuserid   number,
                                    fp_workstationid  number,
                                    fp_internalcalc   varchar2)
  return number;
  -- output result:
  -- 0 = okay
  -- <> 0 = ORA error

end pack_multiread;
/
create or replace package body pack_multiread is

  -- global constants
  gc_duplicate_exception        exception;
  gc_result_batch_not_found     NUMBER := 1;
  gc_result_empty_batch         NUMBER := 2;
  gc_result_ora_error           NUMBER := 3;
  gc_result_no_prodprocbuffer   NUMBER := 4;
  gc_result_duplicate_scan_err  NUMBER := 5;

  -- global constants populated in initialise_constants
  gc_stay_id_in_stock           NUMBER := 0;
  gc_stay_id_in_laundry         NUMBER := 0;
  gc_stay_id_in_rewash          NUMBER := 0;
  gc_stay_id_at_customer        NUMBER := 0;
  gc_stay_id_soil_in_gd         NUMBER := 0;
  gc_stay_id_onsite_inv         NUMBER := 0;
  gc_stay_id_sent_to_laundry    NUMBER := 0;
  gc_stay_id_knt_in_laundry     NUMBER := 0;
  gc_stay_id_knt_disinfect      NUMBER := 0;
  gc_stay_id_knt_at_customer    NUMBER := 0;
  gc_stay_id_knt_receive        NUMBER := 0;
  gc_stay_id_knt_send           NUMBER := 0;
  gc_stay_id_inscan_cleanreturn NUMBER := 0;
  gc_stay_id_lockerfed          NUMBER := 0;
  gc_stay_id_reject             NUMBER := 0;
  gc_status_id_in_circ          NUMBER := 0;
  gc_status_id_assigned         NUMBER := 0;
  gc_status_id_ragged           NUMBER := 0;
  gc_status_id_or_used          NUMBER := 0;
  gc_status_id_gd_new           NUMBER := 0;
  gc_pn_inprogress_statusid     NUMBER := 0;
  GC_PN_PACKINGNOTE_STATUS_ID   NUMBER := 0;
  gc_minimum_hour_interval      NUMBER := 16; -- ABS-118650

  -- global constants system settings populated in read_systemsettings
  gc_ss_scanbyroute             varchar2(1);
  gc_ss_inscanhourinterval      number;
  gc_ss_outscanhourinterval     number;
  gc_ss_rewashscantimeinterval  number;
  gc_ss_countwashesat           varchar2(1);
  gc_ss_routecontrolcreation    number;
  gc_ss_debuglevel              number := 0;
  gc_ss_reissueraggeditem       varchar2(1);
  gc_ss_usetreatmentcheck       number;
  gs_ss_recordonsiteinventory   varchar2(1);
  gs_ss_bringincircatinscan     number;
  gs_ss_receivescanusvirtbundle number;
  gg_ss_uhfpoolitemstartupphase varchar2(1);
  -- order 20014102
  gs_ss_deliverydetermination   number;
  gs_ss_outconfirmedplannedroute number;
  -- to do 23777
  gc_ss_uhfpoolitemstartupphase varchar2(1);
  -- order 20014643
  gc_ss_uhfoutscanbundleperc    number;
  -- order 20016361
  gs_ss_changefmforpoolmultiread number;
 --------- HVH ABS-13664
  gv_ss_auto_assign_unkown_tags varchar2(1);
  gv_ss_auto_assign_min_percent number;
--------- HVH ABS-13664 END
  gc_ss_shipmentcheckperdelnote number;
  --------- HVH ABS-31879
  gv_ss_uhfinscantrackingonly   varchar2(1);
  ---- HVH ABS-22517
  gv_ss_chargewashcogchgperweek varchar2(1);
  ---- HVH LASA-256
  gv_ss_stockcntupdateonsiteinv number;
  gv_ss_createdelnotestackcheck number;
  gv_ss_stackchkpersonalbundle  varchar2(1);
  gv_ss_stackchkpersonalmixed   varchar2(1);
  gv_ss_uhfstrayreadreduction   number;
  ---DLA ABS-68455
  gv_ss_rewashmax               number;
  -- HVH ABS-99779
  gv_ss_hrsnoinscanaftrdelnote  number;
  -- HVH ABS-130871
  gv_ss_uhfkntoutscaninterval   number;
	--CMU ABS-156251
  gv_ss_uhfoutscantrackingonly   varchar2(1);

  gc_transtype_inscan           number := 1;
  gc_transtype_receive          number := 2;
  gc_transtype_send             number := 3;
  gc_transtype_disinfect        number := 4;

  gc_daystokeepinprodprocbufscan number := 1;

  -- global variables declaration
  gv_multireadscanbatch_id      number := 0;
  gv_subbatchnumber             number := 0;
  gv_pickupdate                 date;
  gv_plant_id                   number := 0;
  gv_businessunit_id            number := 0;
  gv_systemuser_id              number := 0;
  gv_workstation_id             number := 0;
  gv_workstation_code           workstation.code%type := '';
  gv_packingnote_id             number := 0;
  gv_consumptionpoint_id        number := 0;
  gv_route_id                   number := 0;
  gv_planneddeliverydate        date   := null;
  gv_prodprocessbuffer_id       number := null;
  gv_secondary_id_range_exists  varchar2(1) := 'N';
  gv_secon_id_range_exists_knt  varchar2(1) := 'N';
  gv_items_in_batch             number := 0;
  gv_items_in_batch_knt         number := 0;
  gv_items_found                number := 0;
  gv_items_found_knt            number := 0;
  gv_last_error_number          NUMBER := 0;
  gv_last_error_message         VARCHAR2(2000) := '';
  gv_main_code_block            VARCHAR2(100) := '';
  gv_code_block                 VARCHAR2(1000) := '';
  gv_result                     number := 0;
  gv_size_star_id               number := 0;
  gv_auto_flag_prod_contr_end   number := 0;
  gv_auto_flag_cust_inactive    number := 0;
  gv_auto_flag_before_replace   number := 0;
  gv_isbulkshipmentnote         VARCHAR2(1) := 'N';
  gv_exit_loop                  boolean;
  gv_outscangarmentsaswell      boolean;
  gv_garmentassistantbatch      boolean;
  gv_istockcountbatch           boolean;
  gv_knt_inscan_YN              VARCHAR2(1) := 'Y';
  gv_prod_inscan_YN             VARCHAR2(1) := 'Y';
  gv_databasecode               databasesettings.code%type;
  gv_outscantrackonly           varchar2(1) := 'N';
  gv_stacksize                  number := 0;
  gv_findpack_YN                varchar2(1) := 'N';
  gv_iscustomernote             VARCHAR2(1) := 'N';
  gv_ischildcustomernote        VARCHAR2(1) := 'N';
  gv_dbSetting                  VARCHAR2(3) := '';
  gv_unatendedscantransactypeid number;
  gv_internalcalcactive         multireadscanbatch.internalcalcactive%type;
  gv_batchnumber                VARCHAR(24) := null;

  duplicates_detected           EXCEPTION;
  PRAGMA EXCEPTION_INIT(duplicates_detected, -30926); -- ORA-30926 = unable to get a stable set of rows in the source

  ---------------------------------------------------------------------------------------------------
  procedure writemultireaderrorlog is
  begin
   abslogwrite.abslog_write(5,'PACK_MULTIREAD',gv_plant_id,3, to_char(systimestamp, 'HH24:MI:SS.FF6') ||' Error in ' || gv_main_code_block || ' - '

|| gv_code_block || ' ' || to_char(gv_last_error_number) || ' ' || substr(gv_last_error_message, 1,

1024) || ' BatchID '|| to_char(gv_multireadscanbatch_id) || '/' || to_char(gv_subbatchnumber),gv_systemuser_id);
  end;

  procedure writemultireadwarninglog is
  begin
   abslogwrite.abslog_write(5,'PACK_MULTIREAD',gv_plant_id,2, to_char(systimestamp, 'HH24:MI:SS.FF6') ||' Warning in ' || gv_main_code_block || ' - '

|| gv_code_block || ' ' || to_char(gv_last_error_number) || ' ' || substr(gv_last_error_message, 1,

1024),gv_systemuser_id);
  end;


  procedure writemultireaddebuglog(fp_message varchar2) is
  begin
   gv_code_block := fp_message;
   if gc_ss_debuglevel = 6 then
     abslogwrite.abslog_write(5,'PACK_MULTIREAD',gv_plant_id,1, to_char(systimestamp, 'HH24:MI:SS.FF6') ||' BatchID '|| to_char

(gv_multireadscanbatch_id) || '/' || to_char(gv_subbatchnumber) ||  ' ' || gv_main_code_block || ' - '

|| gv_code_block,gv_systemuser_id);
   end if;
  end;

  ------------------------------
  procedure initialize_constants is
  begin
   begin
    writemultireaddebuglog('Initialize constants');
    select st.stay_id
      into gc_stay_id_in_stock
      from stay st
     where st.staytype = 1
       and st.staynr = 10; -- in stock

    select st.stay_id
      into gc_stay_id_at_customer
      from stay st
     where st.staytype = 1
       and st.staynr = 20; -- outscan/at customer

    select st.stay_id
      into gc_stay_id_soil_in_gd
      from stay st
     where st.staytype = 1
       and st.staynr = 25; -- Soil in GD

    select st.stay_id
      into gc_stay_id_onsite_inv
      from stay st
     where st.staytype = 1
       and st.staynr = 27; -- onsite inventory

    select st.stay_id
      into gc_stay_id_sent_to_laundry
      from stay st
     where st.staytype = 1
       and st.staynr = 28; -- sent to laundry

    select stay_id
      into gc_stay_id_in_laundry
      from stay
     where stay.staytype = 1
       and stay.staynr = 30; --inscan/soil received

    select stay_id
      into gc_stay_id_in_rewash
      from stay
     where stay.staytype = 1
       and stay.staynr = 31; --rewash

    select stay_id
      into gc_stay_id_inscan_cleanreturn
      from stay
     where stay.staytype = 1
       and stay.staynr = 41; --Inscan / Clean return

    select status_id
      into gc_status_id_in_circ
      from status
     where status.statustype = 'UI'
       and status.code = '20'; --in circulation

    select status_id
      into gc_status_id_assigned
      from status
     where status.statustype = 'UI'
       and status.code = '30'; --assigned

    select status_id
      into gc_status_id_ragged
      from status
     where status.statustype = 'UI'
       and status.code = '40'; --ragged

    select status_id
      into gc_status_id_or_used
      from status
     where status.statustype = 'OR'
       and status.code = '50'; --used

    select status_id
      into gc_status_id_gd_new
      from status
     where status.statustype = 'GD'
       and status.code = '10'; --new

    select stay_id
      into gc_stay_id_knt_in_laundry
      from stay
     where stay.staytype = 2
       and stay.staynr = 10; --inscan/soil received

    select st.stay_id
      into gc_stay_id_knt_at_customer
      from stay st
     where st.staytype = 2
       and st.staynr = 20; -- outscan/at customer

    select st.stay_id
      into gc_stay_id_knt_receive
      from stay st
     where st.staytype = 2
       and st.staynr = 23; -- received

    select st.stay_id
      into gc_stay_id_knt_send
      from stay st
     where st.staytype = 2
       and st.staynr = 24; -- send

    select stay_id
      into gc_stay_id_knt_disinfect
      from stay
     where stay.staytype = 2
       and stay.staynr = 30; --disinfection

    select st.stay_id
      into gc_stay_id_lockerfed
      from stay st
     where st.staytype = 1
       and st.staynr = 42; -- Locker fed

    select st.stay_id
      into gc_stay_id_reject
      from stay st
     where st.staytype = 1
       and st.staynr = 44; -- Rejected from Customer / At Inscan

    select sd.sizedefinition_id
      into gv_size_star_id
      from sizedefinition sd
     where sd.code = '*';

    select nvl(af.flag_id,0)
      into gv_auto_flag_prod_contr_end
      from automaticflag af
     where af.automaticflag_id = 17; -- 'Product contract ended for customer'

    select nvl(af.flag_id,0)
      into gv_auto_flag_cust_inactive
      from automaticflag af
     where af.automaticflag_id = 18; -- 'Customer no longer active'

    select nvl(af.flag_id,0)
      into gv_auto_flag_before_replace
      from automaticflag af
     where af.automaticflag_id = 20; -- 'Show on replaced item before replacement is active'

     select ST.STATUS_ID
       into GC_PN_INPROGRESS_STATUSID
       from STATUS ST
      where ST.STATUSTYPE = 'PN' --Packingnote
        and ST.CODE = '20'; -- In progress

     select ST.STATUS_ID
       into GC_PN_PACKINGNOTE_STATUS_ID
       from STATUS ST
      where ST.STATUSTYPE = 'PN' --Packingnote
        and ST.CODE = '10'; -- PackingNote

     select dbs.code
     into gv_dbSetting
     from databasesettings dbs;
   exception
     when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
      end;
   end;
  end; --initialize_constants
  ---------------------------------------------------------------------------------------------------
  procedure read_systemsettings is
  begin
    writemultireaddebuglog('Read system settings');
    begin
      select to_number(s.value)
        into gc_ss_debuglevel
        from systemsetting s
       where s.name = 'MULTIREAD_DEBUG_LEVEL'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_debuglevel := 0;
    end;
    begin
      select s.value
        into gc_ss_scanbyroute
        from systemsetting s
       where s.name = 'SCANBYROUTE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_scanbyroute := 'Y';
    end;
    begin
      select to_number(s.value)
        into gc_ss_inscanhourinterval
        from systemsetting s
       where s.name = 'INSCANALLOWHOURINTERVAL'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_inscanhourinterval := 24;
    end;
    begin
      select to_number(s.value)
        into gc_ss_outscanhourinterval
        from systemsetting s
       where s.name = 'OUTSCANALLOWHOURINTERVAL'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_outscanhourinterval := 24;
    end;
    begin
      select to_number(s.value)
        into gc_ss_rewashscantimeinterval
        from systemsetting s
       where s.name = 'REWASHSCANTIMEINTERVAL'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_rewashscantimeinterval := 30;
    end;
    begin
      select s.value
        into gc_ss_countwashesat
        from systemsetting s
       where s.name = 'COUNTWASHESAT'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_countwashesat := 'I';
    end;
    begin
      select to_number(s.value)
        into gc_ss_routecontrolcreation
        from systemsetting s
       where s.name = 'ROUTECONTROLCREATION'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_routecontrolcreation := 1; -- manual
    end;
    begin
      select s.value
        into gc_ss_reissueraggeditem
        from systemsetting s
       where s.name = 'REISSUERAGGEDITEM'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_reissueraggeditem := 'N';
    end;
    begin
      select to_number(s.value)
        into gc_ss_usetreatmentcheck
        from systemsetting s
       where s.name = 'USETREATMENTCHECK'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_usetreatmentcheck := 0;
    end;
    begin
      select s.value
        into gs_ss_recordonsiteinventory
        from systemsetting s
       where s.name = 'RECORDONSITEINVENTORY'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gs_ss_recordonsiteinventory := 'N';
    end;
    begin
      select to_number(s.value)
        into gs_ss_bringincircatinscan
        from systemsetting s
       where s.name = 'BRINGINCIRCATINSCAN'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gs_ss_bringincircatinscan := 0;
    end;
    begin
      select s.value
        into gc_ss_uhfpoolitemstartupphase
        from systemsetting s
       where s.name = 'UHFPOOLITEMSTARTUPPHASE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_uhfpoolitemstartupphase := 'N';
    end;
    begin
      select s.value
        into gc_ss_uhfoutscanbundleperc
        from systemsetting s
       where s.name = 'UHFOUTSCANBUNDLEPERC'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_uhfoutscanbundleperc := 0;
    end;
    begin
      select max('Y')
        into gv_secondary_id_range_exists
        from uniqueidconfiguration u
       where u.packagetype = 1 -- products
         and u.type = 2 -- chip
         and u.primaryid = 'N'
         and u.businessunit_id = gv_businessunit_id;
    exception
      when no_data_found then
        gv_secondary_id_range_exists := 'N';
    end;
    begin
      select max('Y')
        into gv_secon_id_range_exists_knt
        from uniqueidconfiguration u
       where u.packagetype = 3 -- containers
         and u.type = 2 -- chip
         and u.primaryid = 'N';
    exception
      when no_data_found then
        gv_secon_id_range_exists_knt := 'N';
    end;
    -- order 20014102
    begin
      select s.value
        into gs_ss_deliverydetermination
        from systemsetting s
       where s.name = 'DELIVERYDETERMINATION'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gs_ss_deliverydetermination := 0;
    end;
    begin
      select s.value
        into gs_ss_outconfirmedplannedroute
        from systemsetting s
       where s.name = 'OUTCONFIRMPLANNEDROUTE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gs_ss_outconfirmedplannedroute := 1;
    end;
    begin
      select s.value
        into gs_ss_changefmforpoolmultiread
        from systemsetting s
       where s.name = 'CHANGEFMFORPOOLMULTIREAD'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gs_ss_changefmforpoolmultiread := 1;
    end;
    begin
      select s.value
        into gs_ss_receivescanusvirtbundle
        from systemsetting s
       where s.name = 'RECEIVESCANUSEVIRTBUNDLE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gs_ss_receivescanusvirtbundle := 0;
    end;
--------- HVH ABS-13664
    begin
      select s.value
        into gv_ss_auto_assign_unkown_tags
        from systemsetting s
       where s.name = 'AUTOASSIGNUNKNOWNTAGS'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_auto_assign_unkown_tags := 'N';
    end;

    begin
      select s.value
        into gv_ss_auto_assign_min_percent
        from systemsetting s
       where s.name = 'AUTOASSIGNUNKNOWNTAGPRC'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_auto_assign_min_percent := 100;
    end;
--------- HVH ABS-13664 END
--------- HVH ABS-27597
    begin
      select s.value
        into gc_ss_shipmentcheckperdelnote
        from systemsetting s
       where s.name = 'SHIPMENTCHECKPERDELNOTE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gc_ss_shipmentcheckperdelnote := 1;
    end;
--------- HVH ABS-27597 END
--------- HVH ABS-31879
    begin
      select s.value
        into gv_ss_uhfinscantrackingonly
        from systemsetting s
       where s.name = 'UHFINSCANTRACKINGONLY'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_uhfinscantrackingonly := 'N';
    end;
--------- HVH ABS-31879 END
--------- HVH ABS-22517
    begin
      select s.value
        into gv_ss_chargewashcogchgperweek
        from systemsetting s
       where s.name = 'CHARGEWASHCOGCHG/WEEK'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_chargewashcogchgperweek := 'N';
    end;
--------- HVH ABS-22517 END
    begin
      select nvl(max(s.value), 'N')
      into   gg_ss_uhfpoolitemstartupphase
      from   systemsetting s
      where  s.name = 'UHFPOOLITEMSTARTUPPHASE'
      and    s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gg_ss_uhfpoolitemstartupphase := 'N';
    end;
--------- HVH LASA-256
    begin
      select s.value
        into gv_ss_stockcntupdateonsiteinv
        from systemsetting s
       where s.name = 'STOCKCOUNTUPDATEONSITEINV'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_stockcntupdateonsiteinv := 1;
    end;
--------- HVH LASA-256 END
    begin
      --ABS-54916 Create outscans and delivery note for approved stacks for customer related items
      select s.value
      into   gv_ss_createdelnotestackcheck
      from   systemsetting s
      where  s.name = 'CREATEDELIVNOTESTACKCHECK'
      and    s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_createdelnotestackcheck := 0;
    end;
---------  ABS-53725
    begin
      select s.value
        into gv_ss_stackchkpersonalmixed
        from systemsetting s
       where s.name = 'STACKCHKPERSONALIZEDMIXED'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_stackchkpersonalmixed := 'Y';
    end;
    begin
      select s.value
        into gv_ss_stackchkpersonalbundle
        from systemsetting s
       where s.name = 'STACKCHPERSONALIZEDBUNDLE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_stackchkpersonalbundle := 'Y';
    end;
--------- ABS-32402
    begin
      select to_number(s.value)
        into gv_ss_uhfstrayreadreduction
        from systemsetting s
       where s.name = 'UHFSTRAYREADREDUCTION'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_uhfstrayreadreduction := 0;
    end;
    select max(t.code) into gv_databasecode from databasesettings t;
    --ABS-68455
    begin
      select to_number(s.value)
        into gv_ss_rewashmax
        from systemsetting s
       where s.name = 'REWASHMAX'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_rewashmax := 0;
    end;
    --ABS-99779
    begin
      select to_number(s.value)
        into gv_ss_hrsnoinscanaftrdelnote
        from systemsetting s
       where s.name = 'UHFHRSNOINSCANAFTRDELNOTE'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_hrsnoinscanaftrdelnote := 0;
    end;
    --ABS-130871
    begin
      select to_number(s.value)
        into gv_ss_uhfkntoutscaninterval
        from systemsetting s
       where s.name = 'UHFKNTOUTSCANINTERVAL'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_uhfkntoutscaninterval := 0;
    end;
		--ABS-156251
    begin
      select s.value
        into gv_ss_uhfoutscantrackingonly
        from systemsetting s
       where s.name = 'UHFOUTSCANTRACKINGONLY'
         and s.plant_id = gv_plant_id;
    exception
      when no_data_found then
        gv_ss_uhfoutscantrackingonly := 'N';
    end;
  end read_systemsettings;

 procedure purge_production_process_scans is
 PRAGMA AUTONOMOUS_TRANSACTION;
 lv_dummy number;
 lv_ref_date date;
 begin
    writemultireaddebuglog('Purge Production Process Buffer Scans');
    lv_ref_date := trunc(sysdate) - gc_daystokeepinprodprocbufscan;

    SELECT 1 into lv_dummy FROM productionprocessscan p
     WHERE nvl(p.uniqueitembufferinfo_id, -1) = -1
       and p.plant_id = gv_plant_id
       and p.scandate between lv_ref_date - 3 and lv_ref_date
       and rownum = 1;
    DELETE FROM productionprocessscan p
     WHERE nvl(p.uniqueitembufferinfo_id, -1) = -1
       and p.plant_id = gv_plant_id
       and p.scandate < lv_ref_date;
    commit;
  exception
    when no_data_found then
      null;
 end purge_production_process_scans;

 ------------------------------------------------------------------
 procedure initialize_batch(fp_multireadscanbatch_id number,
                            fp_subbatchnumber        number) is
 lv_outscanpoolitems varchar2(1);

 begin
    gv_main_code_block := 'Initialize Batch';
    -- initialisation
    gv_pickupdate := trunc(sysdate);
    gv_multireadscanbatch_id := fp_multireadscanbatch_id;
    gv_subbatchnumber := fp_subbatchnumber;

    -- initialize global variables from batch
    begin
      writemultireaddebuglog('Initialize global variables');
      select m.businessunit_id,
             w.outscanpoolitems,
             b.plant_id,
             m.workstation_id,
             w.code,
             m.packingnote_id,
             w.productionprocessbuffer_id,
             m.systemuser_id,
             w.unattendedscantransacttype_id,
             m.internalcalcactive
        into gv_businessunit_id,
             lv_outscanpoolitems,
             gv_plant_id,
             gv_workstation_id,
             gv_workstation_code,
             gv_packingnote_id,
             gv_prodprocessbuffer_id,
             gv_systemuser_id,
             gv_unatendedscantransactypeid,
             gv_internalcalcactive
        from multireadscanbatch m, businessunit b, workstation w, plant pt
       where m.multireadscanbatch_id=gv_multireadscanbatch_id
         and b.businessunit_id = m.businessunit_id
         and w.workstation_id = m.workstation_id
         and b.plant_id = pt.plant_id;

    if lv_outscanpoolitems = 'B'
      then gv_outscangarmentsaswell := true;
      else gv_outscangarmentsaswell := false;
    end if;

    -- cleanup old batches , created more than 5 days ago
    gv_code_block := 'Cleanup Old Batches';
    begin
      for c_batch in (select /*+rule*/
                             m.multireadscanbatch_id,
                             b.code bucode,
                             w.code workstationcode,
                             m.timestamp,
                             (select count(1)
                                from multireadscanbatchcontents mbc
                               where mbc.multireadscanbatch_id = m.multireadscanbatch_id) items
                        from workstation w
                        join multireadscanbatch m on m.workstation_id = w.workstation_id
                        join businessunit b on b.businessunit_id = m.businessunit_id
                       where m.workstation_id = gv_workstation_id
                         and trunc(m.timestamp) < trunc(sysdate) - 5
                         and m.multireadscanbatch_id <> gv_multireadscanbatch_id
                         and (nvl((select max(trunc(mbc.scantimestamp))
                                     from multireadscanbatchcontents mbc
                                    where mbc.multireadscanbatch_id = m.multireadscanbatch_id), to_date('01-01-1900', 'dd-mm-yyyy')) < trunc(sysdate) - 5))
      loop
        begin
          gv_last_error_number := -1;
          gv_last_error_message := 'Business Unit=' || c_batch.bucode ||
                                   ' Workstation=' || c_batch.workstationcode ||
                                   ' Batch#=' || c_batch.multireadscanbatch_id ||
                                   ' Timestamp=' || to_char(c_batch.timestamp,'YYYY-MM-DD HH24:MI:SS') ||
                                   ' #Items=' || c_batch.items;
          execute immediate 'select 1 from multireadscanbatchcontents bc where bc.multireadscanbatch_id = :1 for update nowait' using c_batch.multireadscanbatch_id;
          writemultireadwarninglog;
          delete from multireadscanbatch b where b.multireadscanbatch_id = c_batch.multireadscanbatch_id;
          commit;
        exception
          when others then
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM || ' for ' || gv_last_error_message;
            writemultireadwarninglog;
        end;
      end loop;
    exception
      when no_data_found then null;
    end;

    gv_code_block := 'Purge Production Process Buffer Scans';
    purge_production_process_scans;

    exception
      when no_data_found then
       begin
        gv_businessunit_id := null;
        gv_plant_id := null;
        gv_systemuser_id := 1;
        gv_outscangarmentsaswell := false;
        gv_result := gc_result_batch_not_found;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        gv_code_block := 'Batch ' || to_char(gv_multireadscanbatch_id) || '/' || to_char(gv_subbatchnumber) ||' not found';
        writemultireaderrorlog;
        return;
       end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
        return;
      end;
    end;

    -- check number of items in subbatch
    begin
      writemultireaddebuglog('Select batch contents');
      select count(*)
        into gv_items_in_batch
        from multireadscanbatchcontents m
       where m.multireadscanbatch_id = gv_multireadscanbatch_id
         and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0);
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
        return;
      end;
    end;

    -- check number of container items in subbatch
    begin
      writemultireaddebuglog('Select batch container contents');
      select count(*)
        into gv_items_in_batch_knt
        from multireadscanbatchcontknt m
       where m.multireadscanbatch_id = gv_multireadscanbatch_id
         and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0);
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
        return;
      end;
    end;

    if gv_items_in_batch = 0 and gv_items_in_batch_knt = 0 then
      gv_last_error_number  := null;
      gv_last_error_message := null;
      gv_code_block := 'No items in batch ' || to_char(gv_multireadscanbatch_id) || '/' || to_char(gv_subbatchnumber);
      writemultireaderrorlog;
      gv_result := gc_result_empty_batch;
      return;
    end if;

    begin
      gv_isbulkshipmentnote := 'N';
      select decode(p.origin,14,'Y','N')  -- origin 14 is considered a bulk multiread shipment note
        into gv_isbulkshipmentnote
        from multireadscanbatch mb,
             packingnote p
       where p.packingnote_id = mb.packingnote_id
         and mb.multireadscanbatch_id = gv_multireadscanbatch_id;
    exception
      when no_data_found then
       begin
         gv_isbulkshipmentnote := 'N';
       end;
    end;

  begin
      gv_iscustomernote := 'N';
      select decode(p.origin,16,'Y','N')  -- origin 16 is considered a bulk customer note
        into gv_iscustomernote
        from multireadscanbatch mb,
             packingnote p
       where p.packingnote_id = mb.packingnote_id
         and mb.multireadscanbatch_id = gv_multireadscanbatch_id;
    exception
      when no_data_found then
       begin
         gv_iscustomernote := 'N';
       end;
    end;

    begin
      gv_ischildcustomernote := 'N';
      select decode(p2.origin,16,'Y','N')
        into gv_ischildcustomernote
        from multireadscanbatch mb,
             packingnote p1,
             packingnote p2
       where p1.packingnote_id = mb.packingnote_id
         and p1.bulkpackingnote_id = p2.packingnote_id
         and mb.multireadscanbatch_id = gv_multireadscanbatch_id;
    exception
      when no_data_found then
       begin
         gv_ischildcustomernote := 'N';
       end;
    end;

    initialize_constants;
    read_systemsettings;
  end initialize_batch; -- intialize_batch

  ---------------------------------------------
  procedure mark_duplicate_scans(fp_transactiontype          in transactiontype.transactiontype_id%type,
                                 fp_multireadscanbatch_bu_yn in varchar) is
  begin
    --mark_duplicate_scans
    if fp_multireadscanbatch_bu_yn = 'Y' then
      begin
        --mb.businessunit_id
        update multireadscanbatchcontents mbc
        set    mbc.multireadexception_id = 12
        where  mbc.multireadscanbatch_id = gv_multireadscanbatch_id
        and    mbc.multireadexception_id is null
        and    mbc.uniqueitem_id is not null
        and    (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
        and    exists
         (select 1
                from   multireadscanbatch mb
                where  mb.multireadscanbatch_id = mbc.multireadscanbatch_id
                and    exists (select 1
                        from   scan s
                        where  s.businessunit_id = mb.businessunit_id
                        and    s.primaryid = mbc.idcode
                        and    s.scantimestamp = mbc.scantimestamp
                        and    s.treatmenttype_id is null
                        and    s.transactiontype_id = fp_transactiontype));
      end;
    else
      begin
        --mbc.businessunit_id
        update multireadscanbatchcontents mbc
        set    mbc.multireadexception_id = 12
        where  mbc.multireadscanbatch_id = gv_multireadscanbatch_id
        and    mbc.multireadexception_id is null
        and    mbc.uniqueitem_id is not null
        and    (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
        and    exists (select 1
                from   scan s
                where  s.businessunit_id = mbc.businessunit_id
                and    s.primaryid = mbc.idcode
                and    s.scantimestamp = mbc.scantimestamp
                and    s.treatmenttype_id is null
                and    s.transactiontype_id = fp_transactiontype);
      end;
    end if;
  end mark_duplicate_scans;

  procedure mark_duplicates(fp_range in number) is
  -- fp_range can be 1 for primary_ID or 2 for SECONDARY_ID
  begin
    -- Primary ID code range
    if fp_range=1 then
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
              USING (SELECT u.primaryid idcode
                       FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                            uniqueitem u
                      WHERE m1.idcode = u.primaryid
                        and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                   GROUP BY u.primaryid
                     HAVING count(1) > 1
                    ) MERGE_SUBQUERY
              ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
              AND m.subbatchnumber = gv_subbatchnumber
              AND m.idcode = MERGE_SUBQUERY.idcode)
              WHEN MATCHED THEN
                UPDATE
                   SET m.multireadexception_id = 14; -- duplicate ID Code
     COMMIT;
    end if;
    -- Secondary ID code range
    if fp_range=2 then
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
              USING (SELECT su.secondaryid  idcode
                       FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                            uniqueitem u, secondaryuniqueitem su
                      WHERE m1.idcode = su.secondaryid
                        and u.uniqueitem_id = su.uniqueitem_id
                        and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                        and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                   GROUP BY su.secondaryid
                     HAVING count(1) > 1
                    ) MERGE_SUBQUERY
              ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
              AND m.subbatchnumber = gv_subbatchnumber
              AND m.idcode = MERGE_SUBQUERY.idcode)
              WHEN MATCHED THEN
                UPDATE
                   SET m.multireadexception_id = 14; -- duplicate ID Code
     COMMIT;
    end if;
  end;

  ---------------------------------------------
  procedure mark_duplicates_knt(fp_range in number) is
  -- fp_range can be 1 for primary_ID or 2 for SECONDARY_ID
  begin
    -- Primary ID code range
    if fp_range=1 then
      MERGE /*+index(m XIE1MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
              USING (SELECT c.primaryid idcode
                       FROM multireadscanbatchcontknt m1, multireadscanbatch mb,
                            container c
                      WHERE m1.idcode = c.primaryid
                        and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                   GROUP BY c.primaryid
                     HAVING count(1) > 1
                    ) MERGE_SUBQUERY
              ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
              AND m.subbatchnumber = gv_subbatchnumber
              AND m.idcode = MERGE_SUBQUERY.idcode)
              WHEN MATCHED THEN
                UPDATE
                   SET m.multireadexception_id = 14; -- duplicate ID Code
     COMMIT;
    end if;
    -- Secondary ID code range
    if fp_range=2 then
      MERGE /*+index(m XIE1MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
              USING (SELECT sc.secondaryid  idcode
                       FROM multireadscanbatchcontknt m1, multireadscanbatch mb,
                            container c, secondarycontainer sc
                      WHERE m1.idcode = sc.secondaryid
                        and c.container_id = sc.container_id
                        and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                        and m1.container_id is null -- only for those items that are not yet found in previous step
                   GROUP BY sc.secondaryid
                     HAVING count(1) > 1
                    ) MERGE_SUBQUERY
              ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
              AND m.subbatchnumber = gv_subbatchnumber
              AND m.idcode = MERGE_SUBQUERY.idcode)
              WHEN MATCHED THEN
                UPDATE
                   SET m.multireadexception_id = 14; -- duplicate ID Code
     COMMIT;
    end if;
  end;

  ---------------------------------------------
  procedure create_uniqueitemflag(fp_uniqueitemid    in uniqueitem.uniqueitem_id%type,
                                  fp_flagid          in flag.flag_id%type,
                                  fp_startdate       in uniqueitemflag.startdate%type default sysdate,
                                  fp_freetextitem    in uniqueitemflag.freetextitem%type default null,
                                  fp_treatmenttypeid in uniqueitemflag.treatmenttype_id%type default null) is
      lvcounter number;
    begin
      writemultireaddebuglog('Create UniqueItemFlag');
      --check if flag did not already exist yes or no
      select count(u.flag_id)
      into   lvcounter
      from   uniqueitemflag u
      where  u.uniqueitem_id = fp_uniqueitemid
      and    u.flag_id = fp_flagid;
      --only add flag when it did not yet exist, then counter=0
      if lvcounter = 0 then
        --insert into uniqueitemflag
        insert into uniqueitemflag
          (uniqueitem_id, flag_id, startdate, freetextitem, systemuser_id, timestamp,
           treatmenttype_id)
        values
          (fp_uniqueitemid, fp_flagid, trunc(fp_startdate), fp_freetextitem, gv_systemuser_id, sysdate,
           fp_treatmenttypeid);
      end if; --lvcounter
    exception
      when dup_val_on_index then
        null;
        --does not matter when flag already exist
  end create_uniqueitemflag;

  ----------------------------------------------------------------------------------------------
  function process_plpctreatmntcheckschm(fp_plpcid                     in productlistpercustomer.productlistpercustomer_id%type,
                                         fp_checkpercentage            in treatmentcheckschemedetail.checkpercentage%type,
                                         fp_treatmentchkschemedetailid in plpctreatmentcheckscheme.treatmentcheckschemedetail_id%type)
    return plpctreatmentcheckscheme.factor%type is
    lv_plpc_treat_factor plpctreatmentcheckscheme.factor%type;
  begin
    --get factor
    select pt.factor + (fp_checkpercentage / 100)
    into   lv_plpc_treat_factor
    from   plpctreatmentcheckscheme pt
    where  pt.treatmentcheckschemedetail_id = fp_treatmentchkschemedetailid
    and    pt.productlistpercustomer_id = fp_plpcid;
    --check if update is needed
    if lv_plpc_treat_factor > 1 then
      update plpctreatmentcheckscheme pt
      set    pt.factor = lv_plpc_treat_factor - 1, pt.systemuser_id = gv_systemuser_id,
             pt.timestamp = sysdate
      where  pt.treatmentcheckschemedetail_id = fp_treatmentchkschemedetailid
      and    pt.productlistpercustomer_id = fp_plpcid;
    else
      update plpctreatmentcheckscheme pt
      set    pt.factor = lv_plpc_treat_factor, pt.systemuser_id = gv_systemuser_id,
             pt.timestamp = sysdate
      where  pt.treatmentcheckschemedetail_id = fp_treatmentchkschemedetailid
      and    pt.productlistpercustomer_id = fp_plpcid;
    end if;
    return lv_plpc_treat_factor;
  exception
    when no_data_found then
      begin
        lv_plpc_treat_factor := (fp_checkpercentage / 100);
        insert into plpctreatmentcheckscheme
          (treatmentcheckschemedetail_id, productlistpercustomer_id, factor, systemuser_id,
           timestamp)
        values
          (fp_treatmentchkschemedetailid, fp_plpcid, lv_plpc_treat_factor, gv_systemuser_id, sysdate);
        return lv_plpc_treat_factor;
      end;
  end process_plpctreatmntcheckschm;
  ----------------------------------------------------------------------------------------------
  procedure add_treatmentcheck_flags(fp_uniqueitemid           in uniqueitem.uniqueitem_id%type,
                                     fp_startdate              in uniqueitemflag.startdate%type default sysdate,
                                     fp_freetextitem           in uniqueitemflag.freetextitem%type default null,
                                     fp_treatmentcheckschemeid in out productlistpercustomer.treatmentcheckscheme_id%type,
                                     fp_nrofwashes             in number,
                                     fp_plpcid                 in productlistpercustomer.productlistpercustomer_id%type) is
    lv_plpc_treat_factor plpctreatmentcheckscheme.factor%type;
  begin
    for x in (select tsd.flag_id, tsd.checkpercentage, tsd.treatmentcheckschemedetail_id,
                     tsd.treatmenttype_id
                from treatmentcheckschemedetail tsd
               where tsd.treatmentcheckscheme_id = fp_treatmentcheckschemeid
                 and ((tsd.schemetype = 0 and tsd.washes = fp_nrofwashes) or -- schemetype 0 = Fixed  1= Repeated
                     (tsd.schemetype = 1 and fp_nrofwashes between tsd.fromwashes and tsd.towashes
                      and
                     (mod((fp_nrofwashes - tsd.fromwashes), tsd.repeatwashes) = 0)))
             ) loop
      begin
        if x.checkpercentage = 100 then
          lv_plpc_treat_factor := 1;
        else
          begin
            --get current factor
            lv_plpc_treat_factor := process_plpctreatmntcheckschm(fp_plpcid, x.checkpercentage,
                                                                  fp_treatmentcheckschemeid);
          end;
        end if;
        if lv_plpc_treat_factor >= 1 then
          create_uniqueitemflag(fp_uniqueitemid,x.flag_id, fp_startdate, fp_freetextitem,
                                x.treatmenttype_id);
        end if;
      end;
    end loop; --x
  end add_treatmentcheck_flags;

  ----------------------------------------------------------------------------------------------
  procedure create_route_control(plannedroute    in route.route_id%type,
                                 planneddate     in date) is
    routecontrolid        routecontrol.routecontrol_id%type;
    vpackingday           route.packingday_id%type;
    vrouteplant           route.plant_id%type;
    vloadingdock          route.loadingdock%type;
    vpackingdeadline      route.packingdeadline%type;
    driverid              employee.employee_id%type;
    vdrivernumber         employee.employeenumber%type;
    instructions          routestop.routelistinstructions%type;
    truckid               truck.truck_id%type;
    vtruckcode            truck.code%type;
  begin
   begin
    writemultireaddebuglog('Create Route Control for ' || to_char(planneddate,'dd-mm-yyyy') ||
                           ' Route_ID '  || plannedroute );
    select r.packingday_id, r.loadingdock, r.packingdeadline, r.driver_id, r.truck_id, r.plant_id
    into   vpackingday, vloadingdock, vpackingdeadline, driverid, truckid, vrouteplant
    from   route r
    where  r.route_id = plannedroute;
    if driverid is not null then
      select e.employeenumber into vdrivernumber from employee e where e.employee_id = driverid;
    end if;
    if truckid is not null then
      select t.code into vtruckcode from truck t where t.truck_id = truckid;
    end if;
    select seq_routecontrol.nextval into routecontrolid from dual;
    insert into routecontrol
      (routecontrol_id, route_id, routelistprinted, soilticketsprinted, soilcountstatus,
       settlementstatus, packingstatus, originaldrivingdate, drivingdate, packingday_id, timestamp,
       systemuser_id, overageamount, voucheramount, totalcashcollected, totalcoddelayed,
       totalcodpaythisamnt, totalcodundelivered, totalcodplusadj, totalcodminusadj,
       totalcodprebilled, totalchargecollections, totalchargepaythisamnt, totalchargeundelivered,
       totalchargeplusadj, totalchargeminusadj, totalchargeprebilled, returntime, returndate,
       starttime, loadingdock, packingdeadline, truckcode, drivernumber, plant_id, invoicesgenerated,
       arbalance_id, pocketpcstatus, startmileage, endmileage, straightevenreturnstatus,
       routesettlementprinted, activestockcompleted, bulkputuproutecompleted, safetyremarks)
    values
      (routecontrolid, plannedroute, 'N', 'N', 1, 1, 1, trunc(planneddate), trunc(planneddate),
       vpackingday, sysdate, gv_systemuser_id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null,
       null, vloadingdock, vpackingdeadline, vtruckcode, vdrivernumber, vrouteplant, 1, null, 0,
       0, 0, 0, 'N', 'N', 'N', null);
    writemultireaddebuglog('Insert routecontrol for route ' || plannedroute);
    --insert stops for routecontrol
    for stopcursor in (select rs.routestop_id, rs.stopnumber, rs.customer_id, rs.deliverypoint_id,
                              rs.routelistinstructions, rs.instructionsstartdate,
                              rs.instructionsenddate, rs.contactperson_id, rs.stoptype
                         from routestop rs
                        where rs.route_id = plannedroute
                          and rs.dateactive <= planneddate
                          and rs.dateinactive >= planneddate
                          and rs.stoptype <> 4 -- not incidental
                      ) loop
      begin
        --check for customer active
        if pack_sort.iscustomeractive(stopcursor.customer_id, trunc(planneddate)) and
           pack_sort.iscustomervisitdate(stopcursor.customer_id, trunc(planneddate)) then
          if (trunc(planneddate) >= stopcursor.instructionsstartdate and
             trunc(planneddate) <= stopcursor.instructionsenddate) then
            instructions := stopcursor.routelistinstructions;
          else
            instructions := null;
          end if;
          insert into stop
            (stop_id, routecontrol_id, routestop_id, customer_link_id, stopnumber, arrivaltime,
             departuretime, travelminutes, visitminutes, routelistinstructions, systemuser_id,
             timestamp, movedtostop_id, status,deliverypoint_id, contactperson_id, stoptype)
          values
            (seq_stop.nextval, routecontrolid, stopcursor.routestop_id, stopcursor.customer_id,
             stopcursor.stopnumber, null, null, 0, 0, instructions, gv_systemuser_id, sysdate, null,0,
             stopcursor.deliverypoint_id,stopcursor.contactperson_id, stopcursor.stoptype);
          --link packingnotes to routecontrol
          update packingnote up
          set    up.routecontrol_id = routecontrolid,
                 up.stop_id = seq_stop.currval,
                 up.stopnumber = stopcursor.stopnumber,
                 up.timestamp = sysdate,
                 up.systemuser_id = gv_systemuser_id
          where  up.packingnote_id in (select p.packingnote_id
                                         from packingnote p, deliverypoint delp
                                        where p.route_id = plannedroute
                                          and p.deliverydate = planneddate
                                          and p.deliverypoint_id = coalesce(stopcursor.deliverypoint_id, p.deliverypoint_id)
                                          and p.routecontrol_id is null
                                          and p.deliverypoint_id = delp.deliverypoint_id
                                          and delp.customer_id = stopcursor.customer_id);
          if SQL%ROWCOUNT > 0 then
            -- update RouteControl packingstatus to 'Put Up Printed' when PN is linked to it
            update routecontrol rc
            set    rc.packingstatus = 2 -- put up printed
            where  rc.routecontrol_id = routecontrolid;
          end if;
          --link straightevenreturn to routecontrol
          update straightevenreturn us
          set    us.stop_id = seq_stop.currval,
                 us.timestamp = sysdate,
                 us.systemuser_id = gv_systemuser_id
          where  us.straightevenreturn_id in
                 (select s.straightevenreturn_id
                    from straightevenreturn s, status st,
                         distributionpoint di, department d
                   where s.stop_id is null
                     and s.pickupdate <= planneddate
                     and di.distributionpoint_id = s.distributionpoint_id
                     and d.department_id = di.department_id
                     and d.customer_id = stopcursor.customer_id
                     and (di.deliverypoint_id = stopcursor.deliverypoint_id
                         OR stopcursor.deliverypoint_id is null)
                     and s.status_id = st.status_id
                     and st.code = '10');
        end if;
      end;
    end loop;
    -- insert routecontrol internal bu
    if (gv_internalcalcactive = 'Y') then
       createroutecontrolinternalbu(routecontrolid , gv_systemuser_id, gv_plant_id);
    end if;
    -- insert RSC ExtraInfo for virtual route (if missing)
    createroutecontrolextrainfo(routecontrolid, gv_systemuser_id);
   exception
    when others then
     begin
      gv_result := gc_result_ora_error;
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      ROLLBACK;
      writemultireaderrorlog;
     end;
   end;
  end create_route_control;

  ----------------------------------------------------------------------------------------------
   procedure bring_in_circ_assigned_items is
   begin
    -- part 1 create scan
    begin
      writemultireaddebuglog('Create in circ scan for assigned items');
      begin
      insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan)
        select seq_scan.nextval,
               mb.businessunit_id,
               mbc.scantimestamp  - 0.00001,
               mbc.idcode,
               mbc.customer_id,
               mbc.weareremployment_id,
               mbc.distributionpoint_id,
               mbc.product_id,
               mbc.sizedefinition_id,
               gc_stay_id_in_laundry,
               gc_status_id_in_circ,
               w.code, -- workstation code
               trunc(mbc.scantimestamp),
               mbc.lastinroute_id,
               uf.reasoncode_id,
               mbc.customerowned,
               getyearofweek(trunc(mbc.scantimestamp)),
               getisoweek(trunc(mbc.scantimestamp)),
               getabsdaynumber(trunc(mbc.scantimestamp)),
               mbc.qualitygrade_id,
               mb.systemuser_id,
               sysdate,
               mbc.stay_id, -- prev stay
               26, -- transaction type incirc due to take in use
               0, -- days late
               mbc.uniqueitem_id,
               mbc.secondaryid,
               trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
               trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
               trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
          from multireadscanbatch         mb,
               multireadscanbatchcontents mbc,
               workstation                w,
               uniqueitemfixedinfo        uf
         where mb.multireadscanbatch_id = gv_multireadscanbatch_id
           and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
           and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and mbc.status_id = gc_status_id_assigned -- only assigned ones
           and mbc.multireadexception_id is null
           and w.workstation_id = mb.workstation_id
           and uf.uniqueitem_id = mbc.uniqueitem_id;
       exception
          when dup_val_on_index then
             raise gc_duplicate_exception;
       end;

    -- part 2 update uniqueitemfixedinfo
    -- note uniqueitem is updated with inscan_update_uniqueitem
    writemultireaddebuglog('Update uniqueitemfixedinfo for put in circ');
      MERGE INTO uniqueitemfixedinfo u
      USING (SELECT m1.uniqueitem_id,
                    case when uf.firstissuedate is null
                     then trunc(m1.scantimestamp)
                     else firstissuedate
                    end firstissuedate,
                    trunc(m1.scantimestamp) lastissuedate,
                    case when uf.lastonstockdate is not null
                     then trunc(m1.scantimestamp) - uf.lastonstockdate
                     else 0
                    end daysinstockprevious,
                    case when u1.startrentfrom in (4,5)
                     then uf.enddatefullrent -- do not overwrite
                     else
                        nvl(
                            nvl(getenddatefullrent(trunc(m1.scantimestamp),
                                               m1.customer_id,
                                               m1.product_id,
                                               m1.sizedefinition_id,
                                               m1.finishingmethod_id,
                                               uf.daysincircprevissue),
                                getenddatefullrent(trunc(m1.scantimestamp),
                                               m1.customer_id,
                                               m1.product_id,
                                               gv_size_star_id,
                                               m1.finishingmethod_id,
                                               uf.daysincircprevissue)
                               ),
                            to_date('31-12-2099','dd-mm-yyyy')
                           )
                    end enddatefullrent
               FROM multireadscanbatchcontents m1, uniqueitemfixedinfo uf, uniqueitem u1
              WHERE m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.status_id = gc_status_id_assigned -- only assigned ones
                and uf.uniqueitem_id = m1.uniqueitem_id
                and u1.uniqueitem_id = m1.uniqueitem_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.firstissuedate = MERGE_SUBQUERY.firstissuedate,
                u.lastissuedate = MERGE_SUBQUERY.lastissuedate,
                u.numberofissues = u.numberofissues + 1,
                u.daysinstockprevious = u.daysinstockprevious + MERGE_SUBQUERY.daysinstockprevious,
                u.enddatefullrent = MERGE_SUBQUERY.enddatefullrent,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;

    -- part 3 update incirc history
      writemultireaddebuglog('Update incirc history');
      MERGE INTO issuehistory i
      USING (SELECT ih.issuehistory_id,
                    m1.uniqueitem_id,
                    trunc(m1.scantimestamp) incircdate,
                    getyearofweek(trunc(m1.scantimestamp)) year,
                    getisoweek(trunc(m1.scantimestamp)) week,
                    getabsdaynumber(trunc(m1.scantimestamp)) dayno
               FROM multireadscanbatchcontents m1, issuehistory ih
              WHERE m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.status_id = gc_status_id_assigned -- only assigned ones
                and ih.uniqueitem_link_id = m1.uniqueitem_id
                and ih.incircdate is null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (i.issuehistory_id = MERGE_SUBQUERY.issuehistory_id)
      WHEN MATCHED THEN
        UPDATE
           SET  i.incircdate = MERGE_SUBQUERY.incircdate,
                i.incircyear = MERGE_SUBQUERY.year,
                i.incircweek = MERGE_SUBQUERY.week,
                i.incircday = MERGE_SUBQUERY.dayno,
                i.systemuser_id = gv_systemuser_id,
                i.timestamp = sysdate;

    -- part 4 update last issue date in multireadscanbatchcontents
    UPDATE multireadscanbatchcontents m1
       SET m1.lastissuedate = trunc(m1.scantimestamp)
     WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m1.uniqueitem_id is not null
       and m1.status_id = gc_status_id_assigned -- only assigned ones
       and m1.multireadexception_id is null;
    commit;

    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(26, 'Y');
          gv_result := gc_result_duplicate_scan_err;
        end;
      when no_data_found then
        null;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
      end;
    end;
   end bring_in_circ_assigned_items;

  ----------------------------------------------------------------------------------------------
  procedure incr_qty_returned_unrel_loans is
   begin
    begin
      writemultireaddebuglog('Incr qty returned unrelated loans');
      MERGE INTO unrelatedloan u
      USING (SELECT m1.unrelatedloan_id,
                    min(trunc(m1.scantimestamp)) returndate,
                    min(m1.systemuser_id) systemuser_id,
                    count(*) qty
               FROM multireadscanbatchcontents m1
              WHERE m1.unrelatedloan_id is not null
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           GROUP BY m1.unrelatedloan_id
            ) MERGE_SUBQUERY
      ON (u.unrelatedloan_id = MERGE_SUBQUERY.unrelatedloan_id)
      WHEN MATCHED THEN
        UPDATE
           SET u.returnedqty = u.returnedqty + MERGE_SUBQUERY.qty,
               u.returndate = MERGE_SUBQUERY.returndate,
               u.systemuser_id = MERGE_SUBQUERY.systemuser_id,
               u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
  end; -- incr_qty_returned_unrel_loans

   ----------------------------------------------------------------------------------------------
   procedure create_scanflags is
   begin
     begin
       writemultireaddebuglog('Create Scan Flags');
       merge into scanflag sf using
       (select m.scan_id,
               uf.flag_id
          from multireadscanbatchcontents m
               join uniqueitemflag uf on m.uniqueitem_id = uf.uniqueitem_id
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and m.scan_id is not null
           and uf.startdate >= trunc(sysdate)) merge_query
       on (sf.scan_id = merge_query.scan_id and sf.flag_id = merge_query.flag_id)
       when not matched then insert
       (scan_id,
        flag_id,
        flagresponse,
        systemuser_id,
        timestamp)
       values
       (merge_query.scan_id,
        merge_query.flag_id,
        null,
        gv_systemuser_id,
        sysdate
       );
     exception
      when no_data_found then
        null;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
      end;
     end;
   end; -- create_scanflags

   ----------------------------------------------------------------------------------------------
   procedure remove_flags(fp_dialogcode varchar2) is
   begin
     begin
       delete
         from uniqueitemflag uf
        where uf.uniqueitem_id in (select m.uniqueitem_id
                                     from multireadscanbatchcontents m
                                    where m.multireadscanbatch_id = gv_multireadscanbatch_id
                                      and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                                      and m.uniqueitem_id is not null
                                      and m.multireadexception_id is null)
          and uf.flag_id in (select f.flag_id
                               from flag f,
                                    flagoptions fo,
                                    dialogs d
                              where fo.flag_id = f.flag_id
                                and fo.dialog_id = d.dialog_id
                                and f.flagtype = 1
                                and fo.remove = 'Y'
                                and fo.confirm = 'N'
                                and d.code = fp_dialogcode
                                and f.flag_id <> gv_auto_flag_before_replace);
     exception
       when no_data_found then
         null;
     end;
   end; -- remove_flags


   ----------------------------------------------------------------------------------------------
   procedure add_flag_for_decrease_max_inv is
   vqtytobereturneddecreasemax number;
   vflagid number;
   cursor wi is  SELECT wi.wearerinventory_id,
                        m1.uniqueitem_id,
                        m1.scan_id
                   FROM multireadscanbatchcontents m1, wearerinventory wi
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and wi.weareremployment_id = m1.weareremployment_id
                    and wi.product_id = m1.product_id
                    and wi.sizedefinition_id = m1.sizedefinition_id
                    and wi.finishingmethod_id = m1.finishingmethod_id
                    and wi.qtytobereturneddecreasemax > 0
                    and m1.uniqueitem_id is not null
                    and m1.multireadexception_id is null
                    and not exists (select 1
                                      from uniqueitemflag uf
                                     where uf.uniqueitem_id = m1.uniqueitem_id
                                       and uf.flag_id = vflagId)
                  ORDER BY wi.wearerinventory_id;
   begin
     begin
       writemultireaddebuglog('Add flag decrease max inv');
       select nvl(a.flag_id, 0)
         into vflagid
         from automaticflag a
        where a.automaticflag_id = 7;
       if vflagid <> 0 then
         for vcursor in wi loop
           select a.qtytobereturneddecreasemax
             into vqtytobereturneddecreasemax
             from wearerinventory a
            where a.wearerinventory_id = vcursor.wearerinventory_id
              for update of a.qtytobereturneddecreasemax;
           if vqtytobereturneddecreasemax > 0 then
             create_uniqueitemflag(vcursor.uniqueitem_id, vflagid, sysdate);
             update wearerinventory winv
                set winv.qtytobereturneddecreasemax = winv.qtytobereturneddecreasemax - 1
              where winv.wearerinventory_id = vcursor.wearerinventory_id;
           end if;
         end loop;
       end if;
     exception
       when no_data_found then
         null;
     end;
   end; -- add_flag_for_decrease_max

  ----------------------------------------------------------------------------------------------
  procedure create_flags_maxwash_spectreat is
   lv_maxwashflag_id number := 0;
   begin
    if gc_ss_usetreatmentcheck = 0 then
     begin
     writemultireaddebuglog('Create flag max washes');
     select nvl(flag_id,0)
       into lv_maxwashflag_id
       from automaticflag a
      where a.automaticflag_id = 1;
     if lv_maxwashflag_id <> 0 then
     for vcursorF in (SELECT m1.uniqueitem_id,
                              m1.scan_id,
                              trunc(m1.scantimestamp) scandate
                         FROM multireadscanbatchcontents m1, uniqueitem u,
                              product p, productlistpercustomer plpc
                        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                          AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                          AND m1.uniqueitem_id is not null
                          AND p.product_id = m1.product_id
                          AND plpc.productlistpercustomer_id = m1.plpc_id
                          AND u.uniqueitem_id = m1.uniqueitem_id
                          AND m1.multireadexception_id is null
                          AND u.washestotal >=
                              (case when plpc.maxwashes=0
                                   then p.maxwashes
                                   else plpc.maxwashes
                              end)
                          AND (case when plpc.maxwashes=0
                                   then p.maxwashes
                                   else plpc.maxwashes
                              end) <> 0
                      )
     loop
        create_uniqueitemflag(vcursorF.uniqueitem_id,
                              lv_maxwashflag_id,
                              vcursorF.scandate);
     end loop;
      end if;
     exception
        when no_data_found then
          null;
     end;
    end if; -- gc_ss_usetreatmentcheck = 0
    if gc_ss_usetreatmentcheck <> 0 then
     begin
     writemultireaddebuglog('Create flag special treatment');
     for vcursorF in  (SELECT m1.uniqueitem_id,
                              trunc(m1.scantimestamp) scandate,
                              m1.scan_id,
                              nvl(nvl(plpc.treatmentcheckscheme_id,
                                      (select ps.treatmentcheckscheme_id
                                         from plantproductsettings ps
                                        where ps.plant_id = gv_plant_id
                                          and ps.product_id = p.product_id)),
                                      p.treatmentcheckscheme_id) treatmentcheckscheme_id,
                              u.washestotal,
                              m1.plpc_id
                         FROM multireadscanbatchcontents m1, uniqueitem u,
                              product p, productlistpercustomer plpc
                        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                         AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                          AND m1.uniqueitem_id is not null
                          AND p.product_id = m1.product_id
                          AND plpc.productlistpercustomer_id = m1.plpc_id
                          AND u.uniqueitem_id = m1.uniqueitem_id
                          AND m1.multireadexception_id is null
                          AND (p.treatmentcheckscheme_id is not null
                               OR plpc.treatmentcheckscheme_id is not null
                               OR (select ps.treatmentcheckscheme_id
                                     from plantproductsettings ps
                                    where ps.plant_id = gv_plant_id
                                      and ps.product_id = p.product_id) is not null)
                      )
     loop
      add_treatmentcheck_flags(vcursorF.uniqueitem_id,
                               vcursorF.scandate,
                               null,
                               vcursorF.treatmentcheckscheme_id,
                               vcursorF.washestotal,
                               vcursorF.plpc_id);
     end loop;
     exception
        when no_data_found then
          null;
     end;
    end if; -- gc_ss_usetreatmentcheck <> 0
  end; -- create_flags_maxwash_spectreat

  ----------------------------------------------------------------------------------------------
  procedure create_reject_scans_knt(fp_transactiontype number) is
   begin
     begin
     writemultireaddebuglog('Create Reject Scans Container');
     insert into rejectedscan
           (rejectedscan_id,
            businessunit_id,
            scantimestamp,
            idcode,
            multireadexceptionreason_id,
            transactiontype_id,
            stay_id,
            scanstation,
            systemuser_id,
            timestamp,
            distributionpoint_link_id
            )
    select seq_rejectedscan.nextval,
           gv_businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.multireadexception_id,
           fp_transactiontype,
           mbc.stay_id,
           gv_workstation_code,
           gv_systemuser_id,
           sysdate,
           mbc.distributionpoint_id
      from multireadscanbatchcontknt mbc,
           multireadexceptionreason  mer
     where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mer.multireadexceptionreason_id = mbc.multireadexception_id
       and mer.storelogyn = 'Y';
     exception
        when no_data_found then
          null;
        when DUP_VAL_ON_INDEX then
           insert into rejectedscan
                 (rejectedscan_id,
                  businessunit_id,
                  scantimestamp,
                  idcode,
                  multireadexceptionreason_id,
                  transactiontype_id,
                  stay_id,
                  scanstation,
                  systemuser_id,
                  timestamp,
                  distributionpoint_link_id
                  )
          select seq_rejectedscan.nextval,
                 gv_businessunit_id,
                 mbc.scantimestamp,
                 mbc.idcode,
                 mbc.multireadexception_id,
                 fp_transactiontype,
                 mbc.stay_id,
                 gv_workstation_code,
                 gv_systemuser_id,
                 sysdate,
                 mbc.distributionpoint_id
            from multireadscanbatchcontknt mbc,
                 multireadexceptionreason  mer
           where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
             and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
             and mer.multireadexceptionreason_id = mbc.multireadexception_id
             and mer.storelogyn = 'Y'
             and not exists (select 1
                               from rejectedscan rj
                              where rj.idcode=mbc.idcode
                                and rj.businessunit_id=gv_businessunit_id
                                and rj.scantimestamp=mbc.scantimestamp);
      end;
  end; -- create_reject_scans_knt

  ----------------------------------------------------------------------------------------------
  procedure create_reject_scans(fp_transactiontype number) is
   begin
     begin
       writemultireaddebuglog('Create Reject Scans - update item id for exception 15');
       -- content with exception 15 is inserted by java code and is not processed by package
       update multireadscanbatchcontents mbc
              set mbc.uniqueitem_id = nvl((select ui.uniqueitem_id from uniqueitem ui where ui.primaryid = mbc.idcode), (select sui.uniqueitem_id from secondaryuniqueitem sui where sui.secondaryid = mbc.idcode))
       where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.idcode not like '#%' -- exclude the dummy codes
       and mbc.uniqueitem_id is null -- only set it if null
       and mbc.multireadexception_id = 15;
     end;

     begin
     writemultireaddebuglog('Create Reject Scans');
     insert into rejectedscan
           (rejectedscan_id,
            businessunit_id,
            scantimestamp,
            idcode,
            multireadexceptionreason_id,
            transactiontype_id,
            uniqueitem_link_id,
            status_id,
            stay_id,
            customer_link_id,
            weareremployment_link_id,
            distributionpoint_link_id,
            product_link_id,
            sizedefinition_link_id,
            scanstation,
            systemuser_id,
            timestamp
            )
    select seq_rejectedscan.nextval,
           gv_businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.multireadexception_id,
           fp_transactiontype,
           mbc.uniqueitem_id,
           mbc.status_id,
           mbc.stay_id,
           mbc.customer_id,
           mbc.weareremployment_id,
           nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id),
           mbc.product_id,
           mbc.sizedefinition_id,
           gv_workstation_code,
           gv_systemuser_id,
           sysdate
      from multireadscanbatchcontents mbc,
           multireadexceptionreason   mer
     where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.idcode not like '#%' -- exclude the dummy codes
       and mer.multireadexceptionreason_id = mbc.multireadexception_id
       and mer.storelogyn = 'Y';
     exception
        when no_data_found then
          null;
          when DUP_VAL_ON_INDEX then
             insert into rejectedscan
           (rejectedscan_id,
            businessunit_id,
            scantimestamp,
            idcode,
            multireadexceptionreason_id,
            transactiontype_id,
            uniqueitem_link_id,
            status_id,
            stay_id,
            customer_link_id,
            weareremployment_link_id,
            distributionpoint_link_id,
            product_link_id,
            sizedefinition_link_id,
            scanstation,
            systemuser_id,
            timestamp
            )
    select seq_rejectedscan.nextval,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.multireadexception_id,
           fp_transactiontype,
           mbc.uniqueitem_id,
           mbc.status_id,
           mbc.stay_id,
           mbc.customer_id,
           mbc.weareremployment_id,
           nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id),
           mbc.product_id,
           mbc.sizedefinition_id,
           w.code, -- workstation code
           mb.systemuser_id,
           sysdate
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           multireadexceptionreason   mer,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and w.workstation_id = mb.workstation_id
       and mer.multireadexceptionreason_id = mbc.multireadexception_id
       and mer.storelogyn = 'Y'
       and not exists (select 1 from rejectedscan rj
                              where rj.idcode=mbc.idcode
                              and rj.businessunit_id=mb.businessunit_id
                              and rj.scantimestamp=mbc.scantimestamp
       );
      end;
  end; -- create_reject_scans

   ---------------------------------------------
   procedure retrieve_item_info_for_delvar is
   lv_lastinroute               number;
   lv_lastinstop                number;
   lv_lastindate                date;
   lv_plannedoutroutestop_id    number;
   lv_plannedoutroute_id        number;
   lv_plannedoutdate            date;
   -- order 20014102
   lv_inroutecontrol_id         number;
   lv_inroutestop_id            number;
   lv_outroutecontrol_id        number;
   lv_outstop_id                number;
   begin
    -- find plpc
    begin
    writemultireaddebuglog('Retrieve item info step 2a plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.customer_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id,
               m.scan_id = seq_scan.nextval;
    exception
      when no_data_found then
         null;
    end;
    -- load delayed even exchange and related dee delivery scheme
    begin
    writemultireaddebuglog('Retrieve item info step 2b plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    p.delayedevenexchange,
                    p.deedeliveryscheme_id
               FROM multireadscanbatchcontents m1, productlistpercustomer p
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.productlistpercustomer_id = m1.plpc_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.delayedevenexchange = MERGE_SUBQUERY.delayedevenexchange,
               m.deedeliveryscheme_id = MERGE_SUBQUERY.deedeliveryscheme_id;
    exception
      when no_data_found then
        null;
    end;
    -- safety net1: when plpc not found put delayed even exchange to 1 for garments.
    begin
    writemultireaddebuglog('Retrieve item info step 2c plpc');
    UPDATE multireadscanbatchcontents m
       SET m.delayedevenexchange = 1
     WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
       AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       AND m.plpc_id is null
       AND m.typeofmerchandize=2;
    -- safety net2: when dee not populated put delayed even exchange to 1 for garments.
    UPDATE multireadscanbatchcontents m
       SET m.delayedevenexchange = 1
     WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
       AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       AND m.delayedevenexchange = 7
       AND m.deedeliveryscheme_id is null;
    exception
      when no_data_found then
        null;
    end;
    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;

    -- find last in date and route, batchwise, so not id by ID, but for all ID's of the
    -- same customer, deliverypoint and type of merchandize together.
    -- when gs_ss_deliverydetermination = 1 (order 20014102)then in 1 step, else in 2 steps
    if gs_ss_deliverydetermination = 1 then
      begin
       writemultireaddebuglog('Retrieve item info step 4 lastinroute and plannedoutroute');
       for vcursorI in  (SELECT m1.multireadscanbatch_id,
                                b.plant_id,
                                m1.customer_id,
                                m1.deliverypoint_id,
                                m1.typeofmerchandize,
                                m1.plpc_id,
                                m1.distributionpoint_id
                           FROM multireadscanbatchcontents m1
                           JOIN customer c
                             ON (c.customer_id = m1.customer_id)
                           JOIN product p
                             ON (p.product_id = m1.product_id)
                           JOIN productgroup pg
                             ON (pg.productgroup_id = p.productgroup_id)
                           JOIN businessunit b
                             ON (b.businessunit_id =
                                coalesce((SELECT ca.processbusinessunit_id
                                            FROM customeractivities ca, customer c
                                           WHERE ca.activity_id = pg.activity_id
                                             AND ca.customer_id = c.customer_id
                                             AND ca.processbusinessunit_id = c.defaultbusinessunit_id
                                             AND c.customer_id = m1.customer_id),
                                          (SELECT MIN(ca.processbusinessunit_id)
                                             FROM customeractivities ca
                                            WHERE ca.activity_id = pg.activity_id
                                              AND ca.customer_id =  m1.customer_id)))
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                            AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                            AND m1.customer_id is not null
                            AND m1.uniqueitem_id is not null
                            AND m1.multireadexception_id is null
                       GROUP BY m1.multireadscanbatch_id,
                                b.plant_id,
                                m1.customer_id,
                                m1.deliverypoint_id,
                                m1.typeofmerchandize,
                                m1.plpc_id,
                                m1.distributionpoint_id
                        )
       loop
           pack_deliverybasics.determinedeldateroutesoil(vcursorI.plant_id, vcursorI.customer_id, vcursorI.deliverypoint_id, null, vcursorI.typeofmerchandize,
                                                         /*HVH order 20016281 replaced trunc(sysdate) with pickupdate*/ gv_pickupdate,
                                                         vcursorI.plpc_id, vcursorI.distributionpoint_id, 'N', lv_lastinroute, lv_inroutestop_id,
                                                         lv_inroutecontrol_id, lv_lastinstop, lv_lastindate, lv_plannedoutroute_id, lv_plannedoutroutestop_id,
                                                         lv_outroutecontrol_id, lv_outstop_id, lv_plannedoutdate);
          UPDATE multireadscanbatchcontents m
             SET m.lastindate = lv_lastindate,
                 m.lastinroute_id = lv_lastinroute,
                 m.lastinstop_id = lv_lastinstop,
                 m.lastinroutestop_id = lv_inroutestop_id, -- Fixed issue 3-12-2013 HVH
                 m.plannedoutdate = lv_plannedoutdate,
                 m.plannedoutroute_id = lv_plannedoutroute_id,
                 m.plannedoutstop_id = lv_outstop_id,
                 m.packingnote_id =
                 (case gv_unatendedscantransactypeid when 39
                   then
                      ( select max(pn.packingnote_id)
                        from packingnote pn
                        where pn.distributionpoint_id = m.distributionpoint_id
                        and pn.processbusinessunit_id = gv_businessunit_id
                        and pn.deliverydate = lv_plannedoutdate
                        and pn.status_id in (GC_PN_INPROGRESS_STATUSID,GC_PN_PACKINGNOTE_STATUS_ID)
                        and exists (select 1
                                    from packingnoteline pkl
                                    where pkl.packingnote_id = pn.packingnote_id
                                    and pkl.standardamount + pkl.variationamount > 0 ))
                    else
                      null
                  end)
           WHERE m.multireadscanbatch_id = vcursorI.multireadscanbatch_id
             AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
             AND m.customer_id = vcursorI.customer_id
             AND nvl(m.deliverypoint_id,-1) = nvl(vcursorI.deliverypoint_id,-1)
             AND m.typeofmerchandize = vcursorI.typeofmerchandize
             AND m.plpc_id = vcursorI.plpc_Id  -- added HVH 19-05-2015
             AND m.distributionpoint_id = vcursorI.distributionpoint_Id  -- added HVH 19-05-2015
             AND m.uniqueitem_id is not null
             AND m.multireadexception_id is null;
       end loop;
      exception
          when no_data_found then
            null;
      end;
    end if; -- gs_ss_deliverydetermination = 1
    ---------------
    if gs_ss_deliverydetermination <> 1 then
      begin
       writemultireaddebuglog('Retrieve item info step 4 lastinroute');
       for vcursorI in  (SELECT m1.multireadscanbatch_id,
                                m1.customer_id,
                                m1.deliverypoint_id,
                                m1.typeofmerchandize,
                                m1.plpc_id,
                                m1.distributionpoint_id
                           FROM multireadscanbatchcontents m1
                          WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                           AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                            AND m1.customer_id is not null
                            AND m1.uniqueitem_id is not null
                            AND m1.multireadexception_id is null
                       GROUP BY m1.multireadscanbatch_id,
                                m1.customer_id,
                                m1.deliverypoint_id,
                                m1.typeofmerchandize,
                                m1.plpc_id,
                                m1.distributionpoint_id
                        )
       loop
          lv_lastinstop := null; -- initialize
          pack_sort.getlastinroute(vcursorI.customer_id,
                                   /*HVH order 20016281 replaced trunc(sysdate) with pickupdate*/ gv_pickupdate,
                                   vcursorI.deliverypoint_id, vcursorI.typeofmerchandize,
                                   lv_lastinroute, lv_inroutestop_id, lv_lastindate);
          UPDATE multireadscanbatchcontents m
             SET m.lastindate = lv_lastindate,
                 m.lastinroute_id = lv_lastinroute,
                 m.lastinstop_id = lv_lastinstop,
                 m.lastinroutestop_id = lv_inroutestop_id -- Fixed issue 3-12-2013 HVH
           WHERE m.multireadscanbatch_id = vcursorI.multireadscanbatch_id
             AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
             AND m.customer_id = vcursorI.customer_id
             AND nvl(m.deliverypoint_id,-1) = nvl(vcursorI.deliverypoint_id,-1)
             AND m.typeofmerchandize = vcursorI.typeofmerchandize
             AND m.uniqueitem_id is not null
             AND m.multireadexception_id is null;
       end loop;
      exception
          when no_data_found then
            null;
      end;
      -- find planned out date and route, batchwise, so not id by ID, but for all ID's of the
      -- same customer and plpc together.
      begin
       writemultireaddebuglog('Retrieve item info step 5 plannedoutroute');
       for vcursorO in (SELECT m1.multireadscanbatch_id,
                              b.plant_id,
                              m1.customer_id,
                              m1.deliverypoint_id,
                              m1.typeofmerchandize,
                              m1.delayedevenexchange,
                              m1.deedeliveryscheme_id,
                              m1.plpc_id,
                              m1.lastindate,
                              m1.lastinroute_id,
                              m1.lastinroutestop_id,
                              m1.distributionpoint_id
                           FROM multireadscanbatchcontents m1
                           JOIN customer c
                             ON (c.customer_id = m1.customer_id)
                           JOIN product p
                             ON (p.product_id = m1.product_id)
                           JOIN productgroup pg
                             ON (pg.productgroup_id = p.productgroup_id)
                           JOIN businessunit b
                             ON (b.businessunit_id =
                                coalesce((SELECT ca.processbusinessunit_id
                                            FROM customeractivities ca, customer c
                                           WHERE ca.activity_id = pg.activity_id
                                             AND ca.customer_id = c.customer_id
                                             AND ca.processbusinessunit_id = c.defaultbusinessunit_id
                                             AND c.customer_id = m1.customer_id),
                                          (SELECT MIN(ca.processbusinessunit_id)
                                             FROM customeractivities ca
                                            WHERE ca.activity_id = pg.activity_id
                                              AND ca.customer_id =  m1.customer_id)))
                        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                          AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                          AND m1.delayedevenexchange > 0 -- only for delayed even exchange!
                          AND m1.customer_id is not null
                          AND m1.uniqueitem_id is not null
                          AND m1.multireadexception_id is null
                     GROUP BY m1.multireadscanbatch_id,
                              b.plant_id,
                              m1.customer_id,
                              m1.deliverypoint_id,
                              m1.typeofmerchandize,
                              m1.delayedevenexchange,
                              m1.deedeliveryscheme_id,
                              m1.plpc_id,
                              m1.lastindate,
                              m1.lastinroute_id,
                              m1.lastinroutestop_id,
                              m1.distributionpoint_id
                      )
       loop
          lv_outstop_id := null; -- initialize
          pack_sort.fillplannedoutroute(vcursorO.plant_id,
                                        trunc(sysdate),
                                        vcursorO.typeofmerchandize,
                                        vcursorO.delayedevenexchange,
                                        vcursorO.deedeliveryscheme_id,
                                        vcursorO.plpc_id,
                                        vcursorO.customer_id,
                                        vcursorO.deliverypoint_id,
                                        vcursorO.lastinroute_id,
                                        nvl(vcursorO.lastindate,trunc(sysdate)), -- Fix HVH 2/8/2013
                                        vcursorO.lastinroutestop_id,
                                        lv_plannedoutroutestop_id,
                                        lv_plannedoutroute_id,
                                        lv_plannedoutdate,
                                        gc_ss_scanbyroute);
          UPDATE multireadscanbatchcontents m
             SET m.plannedoutdate = lv_plannedoutdate,
                 m.plannedoutroute_id = lv_plannedoutroute_id,
                 m.plannedoutstop_id = lv_outstop_id,
                 m.packingnote_id =
                 (case gv_unatendedscantransactypeid when 39
                   then
                      ( select max(pn.packingnote_id)
                        from packingnote pn
                        where pn.distributionpoint_id = m.distributionpoint_id
                        and pn.processbusinessunit_id = gv_businessunit_id
                        and pn.deliverydate = lv_plannedoutdate
                        and pn.status_id in (GC_PN_INPROGRESS_STATUSID,GC_PN_PACKINGNOTE_STATUS_ID)
                        and exists (select 1
                                    from packingnoteline pkl
                                    where pkl.packingnote_id = pn.packingnote_id
                                    and pkl.standardamount + pkl.variationamount > 0 ))
                    else
                      null
                  end)
           WHERE m.multireadscanbatch_id = vcursorO.multireadscanbatch_id
             AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
             AND m.customer_id = vcursorO.customer_id
             AND nvl(m.deliverypoint_id,-1) = nvl(vcursorO.deliverypoint_id,-1)
             AND m.typeofmerchandize = vcursorO.typeofmerchandize
             AND nvl(m.plpc_id,-1) = nvl(vcursorO.plpc_id,-1)
             AND m.delayedevenexchange = vcursorO.delayedevenexchange
             AND nvl(m.deedeliveryscheme_id,-1) = nvl(vcursorO.deedeliveryscheme_id,-1)
             AND nvl(m.lastindate,trunc(sysdate)) = nvl(vcursorO.lastindate,trunc(sysdate)) -- Fix HVH 2/8/2013
             AND nvl(m.lastinroute_id,-1) = nvl(vcursorO.lastinroute_id,-1)
             AND m.uniqueitem_id is not null
             AND m.multireadexception_id is null;
       end loop;
      exception
          when no_data_found then
            null;
      end;
    end if; -- gs_ss_deliverydetermination <> 1

    begin
      -- write error log for those items no plannedoutdate could be determined.
      for x in (SELECT c.customernumber,
                      p.code productcode,
                      s.code sizecode,
                      f.code fmcode,
                      count(1) qty
                 FROM multireadscanbatchcontents m1, distributionpoint dp, department d, customer c, product p,
                      sizedefinition s, finishingmethod f
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                  and m1.poolitemyn = 'Y'
                  and m1.delayedevenexchange > 0  -- only those with delayed even exchange
                  and m1.distributionpoint_id is not null
                  and m1.plpc_id is not null
                  and m1.uniqueitem_id is not null
                  and m1.plannedoutdate is null -- no date found
                  and m1.multireadexception_id is null
                  and dp.distributionpoint_id = m1.distributionpoint_id
                  and d.department_id = dp.department_id
                  and c.customer_id = d.customer_id
                  and p.product_id = m1.product_id
                  and s.sizedefinition_id = m1.sizedefinition_id
                  and f.finishingmethod_id = m1.finishingmethod_id
                GROUP BY c.customernumber,
                         p.code,
                         s.code,
                         f.code
               ) loop
        begin
            gv_last_error_number := -1;
            gv_last_error_message := 'No next delivery date could be determined for customer# ' || x.customernumber || ' product/size/fm ' || x.productcode || '/' || x.sizecode || '/' || x.fmcode ||  ' Tomorrow assumed.';
            writemultireadwarninglog;
        end;
      end loop; --x

      -- assume planned out date tomorrow for those where no del.date could be determined.
      -- in this way at least delivery variations for delayed even exchange products are created.
      UPDATE multireadscanbatchcontents m1
         SET m1.plannedoutdate = trunc(sysdate) + 1, -- tomorrow assumed
             m1.packingnote_id =
                 (case gv_unatendedscantransactypeid when 39
                   then
                      ( select max(pn.packingnote_id)
                        from packingnote pn
                        where pn.distributionpoint_id = m1.distributionpoint_id
                        and pn.processbusinessunit_id = gv_businessunit_id
                        and pn.deliverydate = trunc(sysdate) + 1
                        and pn.status_id in (GC_PN_INPROGRESS_STATUSID,GC_PN_PACKINGNOTE_STATUS_ID)
                        and exists (select 1
                                    from packingnoteline pkl
                                    where pkl.packingnote_id = pn.packingnote_id
                                    and pkl.standardamount + pkl.variationamount > 0 ))
                    else
                      null
                  end)
       WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
         and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         and m1.poolitemyn = 'Y'
         and m1.delayedevenexchange > 0  -- only those with delayed even exchange
         and m1.distributionpoint_id is not null
         and m1.plpc_id is not null
         and m1.uniqueitem_id is not null
         and m1.plannedoutdate is null -- no date found
         and m1.multireadexception_id is null;

    exception
      when no_data_found then
        null;
    end;
   end retrieve_item_info_for_delvar; -- retrieve_item_info

  -------------------------------------------
  procedure delete_uhfbundle(fp_subbatchnumber number) is
  begin
    --delete_uhfbundle
    delete from uhfbundle u
    where  u.uhfbundle_id in (select mbc.uhfbundle_id
                              from   multireadscanbatchcontents mbc
                              where  mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                              and   (mbc.subbatchnumber = fp_subbatchnumber or fp_subbatchnumber = 0)
                              and    mbc.uhfbundle_id is not null);
    commit;
  exception
    when no_data_found then
      null;
  end delete_uhfbundle;

   -------------------------------------------
   function add_virtual_scans return number is
   lv_number_of_rows number;
   begin
    begin
    writemultireaddebuglog('Add Virtual Scans');

    merge /*+index(m XIE4MULTIREADSCANCONTENTBATCH)*/ into multireadscanbatchcontents m
    using
     (select gv_multireadscanbatch_id multireadscanbatch_id,
             gv_subbatchnumber subbatch,
             u.primaryid idcode,
             u.uhfbundle_id,
             gv_systemuser_id systemuser_id,
             sysdate timestamp
        from uniqueitem u
       where u.uhfbundle_id in
         (select x.uhfbundle_id from
           (select mbc.uhfbundle_id,
                   ub.bundlesize,
                   count(mbc.uniqueitem_id) qty_scanned
              from multireadscanbatchcontents mbc,
                   uhfbundle ub
             where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
               and ub.uhfbundle_id = mbc.uhfbundle_id
               and ub.bundlesize <> 0
             group by mbc.uhfbundle_id, ub.bundlesize
            having (count(mbc.uniqueitem_id) / ub.bundlesize) *100 >= gc_ss_uhfoutscanbundleperc) x)) merge_subquery
     on (m.multireadscanbatch_id = merge_subquery.multireadscanbatch_id
         and
         m.idcode = merge_subquery.idcode)
    when matched then
    update set
      m.uhfbundle_id = merge_subquery.uhfbundle_id, --HVH ABS-56030
      m.multireadexception_id =  case when m.multireadexception_id = 30 -- Possible stray read
                                   then null                     -- then clear exception
                                   else m.multireadexception_id -- else leave exception
                                 end
    when not matched then
    insert
    (multireadscanbatch_id,
     subbatchnumber,
     idcode,
     idcoderead,
     uhfbundle_id,
     scantimestamp,
     systemuser_id,
     virtualyn
    )
    values
    (merge_subquery.multireadscanbatch_id,
     merge_subquery.subbatch,
     merge_subquery.idcode,
     merge_subquery.idcode,
     merge_subquery.uhfbundle_id,
     merge_subquery.timestamp,
     merge_subquery.systemuser_id,
     'Y'
    );
  --ABS-56030
    lv_number_of_rows := SQL%ROWCOUNT;
    gv_items_in_batch := gv_items_in_batch + lv_number_of_rows;

--  redo the count becaue SQL%ROWCOUNT after merge does not say how many were added.
    select count(*)
      into gv_items_in_batch
      from multireadscanbatchcontents m
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and m.subbatchnumber = gv_subbatchnumber;
    commit;
    return(lv_number_of_rows);
    exception
      when no_data_found then
        return(0);
    end;
   end; -- add_virtual_scans


   ----------------------------------
  function find_distrpnt_notoutscand_itms return number is
  /* This procedure determines the distrutionpoint of the not outscanned pool items
     that are scanned on-site at the customer by receive from or send to laundry
     It does that in the following way:
                 a) check if all other items in BATCH are linked to same distributionpoint
                    if so, then link to that one
                    if not then b)
                 b) check if all other items in BATCH are linked to same customer
                    if so, then go to c)
                    if not then determine the customer with the most items
                       if found goto c)
                       if not found do not remove exception so that it can be tried later with next subbatch
                 c) for the in b) determined customer:
                    check if there is a bulk department,
                     if so, then link to distribution point with highest# of that department
                     if not then link to distribution point with highest# of department with highest #

  */

    lv_mincust number;
    lv_maxcust number;
    lv_cust    number;
    lv_mindip  number;
    lv_maxdip  number;
    lv_dip     number;
  begin
    lv_dip := null;
    lv_cust := null;
    -- a)
    select min(m.distributionpoint_id) mindip,
           max(m.distributionpoint_id) maxdip
      into lv_mindip,
           lv_maxdip
      from multireadscanbatchcontents m
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and m.subbatchnumber <= gv_subbatchnumber  -- all subbatches smaller or equal to current one
       and m.uniqueitem_id is not null
       and m.distributionpoint_id is not null
       and m.multireadexception_id is null
       and m.poolitemyn = 'Y';  -- pool items only

    -- b) try to determine customer
    if lv_mindip is not null and lv_mindip = lv_maxdip
       then lv_dip := lv_mindip;
       else
        -- b1) first see if all items in batch have the same customer
        begin
        select min(d.customer_id) mincust,
               max(d.customer_id) maxcust
          into lv_mincust,
               lv_maxcust
          from multireadscanbatchcontents m,
               distributionpoint dp,
               department d
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber <= gv_subbatchnumber  -- all subbatches smaller or equal to current one
           and m.uniqueitem_id is not null
           and m.distributionpoint_id is not null
           and dp.distributionpoint_id = m.distributionpoint_id
           and d.department_id = dp.department_id
           and m.multireadexception_id is null
           and m.poolitemyn = 'Y';  -- pool items only
        exception
          when no_data_found then null;
        end;

      if lv_mincust is not null and lv_mincust = lv_maxcust then
        lv_cust := lv_mincust;
      end if;

      if lv_cust is null then
        -- b2) determine the customer with the most items
        begin
          select x.customer_id
            into lv_cust
            from
               (select d.customer_id, count(*) cnt
                  from multireadscanbatchcontents m,
                       distributionpoint dp,
                       department d
                 where m.multireadscanbatch_id = gv_multireadscanbatch_id
                   and m.subbatchnumber <= gv_subbatchnumber  -- all subbatches smaller or equal to current one
                   and m.uniqueitem_id is not null
                   and m.distributionpoint_id is not null
                   and dp.distributionpoint_id = m.distributionpoint_id
                   and d.department_id = dp.department_id
                   and m.multireadexception_id is null
                   and m.poolitemyn = 'Y'
                 group by d.customer_id
                 order by count(*) desc
               ) x
           where rownum = 1;
         exception
           when no_data_found then null;
         end;
      end if;

      if lv_cust is not null
         then -- c) customer is found, now try to find distribution point:
            -- c1) take distribpoint with highest # of bulk department
            begin
            select x.distributionpoint_id
              into lv_dip
              from (select dp.distributionpoint_id
                      from department d,
                           distributionpoint dp
                     where dp.department_id = d.department_id
                       and d.bulkdeliveriesdept = 'Y'
                       and d.customer_id = lv_cust
                     order by dp.distributionpointnumber desc) x
             where rownum = 1;
             exception
                when no_data_found then
                  -- c2) take department/distribpoint with highest #
                  begin
                    select x.distributionpoint_id
                      into lv_dip
                      from (
                            select dp.distributionpoint_id
                            from department d,
                                 distributionpoint dp
                           where dp.department_id = d.department_id
                             and d.customer_id = lv_cust
                           order by d.departmentnumber desc, dp.distributionpointnumber desc
                           ) x
                      where rownum = 1;
                  exception
                    when no_data_found then null;
                  end;
             end;
      end if;  -- lv_cust is not null
    end if; -- lv_mindip is not null and lv_mindip = lv_maxdip

    return lv_dip;
  end find_distrpnt_notoutscand_itms;

  ----------------------------------------------------------------------------------------------
  function plantoperatingtimeoverlap(fp_plant_id in number,
                                     fp_scanstarttimestamp in date,
                                     fp_scanendtimestamp in date) return number as
  -- calculates the duration (rounded to minutes) between the passed timestamps, for the time
  -- the passed plant was operating using plantoperatinghours definitions.
  lv_total_timeoverlap number;
  lv_night_timeoverlap number;
  lv_day_timeoverlap number;
  lv_starttime_this_day date;
  lv_endtime_this_day date;
  lv_checkdate date;
  begin
    lv_total_timeoverlap := 0;
    lv_checkdate := trunc(fp_scanstarttimestamp);

    while lv_checkdate <= trunc(fp_scanendtimestamp) loop
      -- initialisation:
      lv_night_timeoverlap := 0;
      lv_day_timeoverlap := 0;
      if lv_checkdate = trunc(fp_scanstarttimestamp)
        then lv_starttime_this_day := fp_scanstarttimestamp;
        else lv_starttime_this_day := lv_checkdate;
      end if;
      if lv_checkdate = trunc(fp_scanendtimestamp)
        then lv_endtime_this_day := fp_scanendtimestamp;
        else lv_endtime_this_day := lv_checkdate + 1;
      end if;
      -- first determine overlap night shift part:
      begin
      select least(lv_endtime_this_day,po.endtime-trunc(po.endtime)+lv_checkdate) -  lv_starttime_this_day
        into lv_night_timeoverlap
        from plantoperatinghours po
       where po.plant_id = fp_plant_id
         and po.day_id = GETABSDAYNUMBER(lv_checkdate-1) -- previous day
         and po.endtime <= po.starttime -- only when that day has a night shift
         and lv_starttime_this_day < po.endtime-trunc(po.endtime)+lv_checkdate;
      exception
       when no_data_found then
          lv_night_timeoverlap := 0;
      end;
      -- second determine day shift part:
      begin
      select case when po.endtime > po.starttime
             then
               least(lv_endtime_this_day,po.endtime-trunc(po.endtime)+lv_checkdate) -
               greatest(lv_starttime_this_day,po.starttime-trunc(po.starttime)+lv_checkdate)
             else
               case when po.starttime-trunc(po.starttime)+lv_checkdate < lv_endtime_this_day
                 then least(lv_endtime_this_day,lv_checkdate+1) -
                      greatest(lv_starttime_this_day,po.starttime-trunc(po.starttime)+lv_checkdate)
                 else 0
               end
             end
        into lv_day_timeoverlap
        from plantoperatinghours po
       where po.plant_id = fp_plant_id
         and po.day_id = GETABSDAYNUMBER(lv_checkdate);
      exception
       when no_data_found then
          lv_day_timeoverlap := 0;
      end;
      lv_total_timeoverlap := lv_total_timeoverlap + lv_night_timeoverlap + lv_day_timeoverlap;
      lv_checkdate := lv_checkdate + 1;
    end loop;
    -- convert to minutes and round:
    lv_total_timeoverlap := round(lv_total_timeoverlap * 24 * 60);
    return(lv_total_timeoverlap);
  end;

  ---------------------------------------------
  procedure load_uniqueitem_buffer_info is
  -- to store previous values that are later needed when creating buffer scans
   begin
      begin
        writemultireaddebuglog('Load buffer Info');
        MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.idcode,
                      m1.subbatchnumber,
                      ubi.productionprocessbuffer_id,
                      ubi.lastscantimestamp
                 FROM multireadscanbatchcontents m1, uniqueitembufferinfo ubi
                WHERE ubi.uniqueitem_id = m1.uniqueitem_id
                  and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                  and m1.multireadexception_id is null
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
        AND m.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m.productionprocessbuffer_id = MERGE_SUBQUERY.productionprocessbuffer_id,
                 m.lastscantimestamp          = MERGE_SUBQUERY.lastscantimestamp;
      exception
        when no_data_found then
          null;
      end;
   end load_uniqueitem_buffer_info;


  ---------------------------------------------
  procedure insertupdate_uniqueitembufinfo(fp_transactiontype in number) is
   begin
     begin
      writemultireaddebuglog('Update Unique Item Buffer Info');
      MERGE INTO uniqueitembufferinfo u
      USING (SELECT mbc.uniqueitem_id,
                    mbc.scantimestamp,
                    mbc.idcode,
                    case when mbc.poolitemyn = 'N'
                      then mbc.customer_id
                      else mbc.relatedcustomer_id
                    end relatedcustomer_id,
                    mbc.product_id,
                    mbc.sizedefinition_id,
                    mbc.productionprocessbuffer_id,
                    mbc.uniqueitembatchnumber
               FROM multireadscanbatchcontents mbc
              WHERE mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and mbc.multireadexception_id is null
                -- do not update if already in this buffer
                and nvl(mbc.productionprocessbuffer_id,-1) <> nvl(gv_prodprocessbuffer_id,-1)
                -- HVH 1/7/2015 added the following condition to prevent that uniqueitem is updated
                -- with wrong values, in case of out-of-sequence processing due to offline scanning.
                and nvl(mbc.lastscantimestamp,to_date('01012000','ddmmyyyy')) <= mbc.scantimestamp
                -- for transactiontype 2 or 42 (outscan or rag) only update when item linked to buffer
                and (mbc.productionprocessbuffer_id is not null or (fp_transactiontype <> 2 and fp_transactiontype <> 42))
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.plant_id = gv_plant_id,
                u.businessunit_id = gv_businessunit_id,
                u.lastscandate = trunc(MERGE_SUBQUERY.scantimestamp),
                u.lastscantimestamp = MERGE_SUBQUERY.scantimestamp,
                u.idcode = MERGE_SUBQUERY.idcode,
                u.relatedcustomer_link_id = MERGE_SUBQUERY.relatedcustomer_id,
                u.product_link_id = MERGE_SUBQUERY.product_id,
                u.sizedefinition_link_id = MERGE_SUBQUERY.sizedefinition_id,
                u.productionprocessbuffer_id = gv_prodprocessbuffer_id,
                u.prevprodprocessbuffer_id = MERGE_SUBQUERY.productionprocessbuffer_id,
                u.batchnumber = MERGE_SUBQUERY.uniqueitembatchnumber,
                u.lastscanstation = gv_workstation_code,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate
      WHEN NOT MATCHED THEN INSERT
               (uniqueitembufferinfo_id,
                uniqueitem_id,
                plant_id,
                businessunit_id,
                lastscandate,
                lastscantimestamp,
                inscantimestamp,
                idcode,
                relatedcustomer_link_id,
                product_link_id,
                sizedefinition_link_id,
                productionprocessbuffer_id,
                prevprodprocessbuffer_id,
                batchnumber,
                lastscanstation,
                systemuser_id,
                timestamp)
               VALUES
               (seq_uniqueitembufferinfo.nextval,
                MERGE_SUBQUERY.uniqueitem_id,
                gv_plant_id,
                gv_businessunit_id,
                trunc(MERGE_SUBQUERY.scantimestamp),
                MERGE_SUBQUERY.scantimestamp,
                MERGE_SUBQUERY.scantimestamp, -- upon create it must be the inscan, so current scantimestamp
                MERGE_SUBQUERY.idcode,
                MERGE_SUBQUERY.relatedcustomer_id,
                MERGE_SUBQUERY.product_id,
                MERGE_SUBQUERY.sizedefinition_id,
                gv_prodprocessbuffer_id,
                MERGE_SUBQUERY.productionprocessbuffer_id,
                MERGE_SUBQUERY.uniqueitembatchnumber,
                gv_workstation_code,
                gv_systemuser_id,
                sysdate
               );
    exception
      when no_data_found then
        null;
    end;
   end insertupdate_uniqueitembufinfo;

   ---------------------------------------------
   procedure create_prodprocessbufscans(fp_transactiontype in number) is
   begin
    begin
    writemultireaddebuglog('Create Production Process Buffer Scans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.productionprocessscan_id = seq_productionprocessscan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and nvl(m.lastscantimestamp,to_date('01012000','ddmmyyyy')) <= m.scantimestamp
       -- do not update if already in this buffer
       and nvl(m.productionprocessbuffer_id,-1) <> nvl(gv_prodprocessbuffer_id,-1)
       -- for transactiontype 2 or 42 (outscan or rag) only create scan when item linked to buffer
       and (m.productionprocessbuffer_id is not null or (fp_transactiontype <> 2 and fp_transactiontype <> 42));
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Production Process Buffer Scans');
    insert into productionprocessscan
            (productionprocessscan_id,
             plant_id,
             businessunit_id,
             scandate,
             scantimestamp,
             uniqueitem_link_id,
             uniqueitembufferinfo_id,
             idcode,
             relatedcustomer_link_id,
             product_link_id,
             sizedefinition_link_id,
             toprodprocessbuffer_id,
             fromprodprocessbuffer_id,
             minutesinpreviousbuffer,
             minutessinceinscan,
             batchnumber,
             scanstation,
             systemuser_id,
             timestamp
            )
    select mbc.productionprocessscan_id,
           gv_plant_id,
           gv_businessunit_id,
           trunc(mbc.scantimestamp),
           mbc.scantimestamp,
           mbc.uniqueitem_id,
           u.uniqueitembufferinfo_id,
           mbc.idcode,
           case when mbc.poolitemyn = 'N'
              then mbc.customer_id
              else mbc.relatedcustomer_id
           end relatedcustomer_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gv_prodprocessbuffer_id,
           mbc.productionprocessbuffer_id,
           case when mbc.productionprocessbuffer_id is not null -- only calc time when prev. buffer not null
           then plantoperatingtimeoverlap(gv_plant_id,nvl(mbc.lastscantimestamp,mbc.scantimestamp),mbc.scantimestamp)
           else 0
           end,
           plantoperatingtimeoverlap(gv_plant_id,u.inscantimestamp,mbc.scantimestamp),
           mbc.uniqueitembatchnumber,
           gv_workstation_code,
           gv_systemuser_id,
           sysdate
      from multireadscanbatchcontents mbc, uniqueitembufferinfo u
     where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null
       and u.uniqueitem_id = mbc.uniqueitem_id
       and nvl(mbc.lastscantimestamp,to_date('01012000','ddmmyyyy')) <= mbc.scantimestamp
       and mbc.productionprocessscan_id is not null;
    exception
      when no_data_found then
        null;
    end;

    begin
      writemultireaddebuglog('Update Production Process Buffer Scan Aggregation');
      MERGE INTO productionprocessscanaggr ppsa
      USING (SELECT ps.businessunit_id,
                    ps.scandate,
                    ps.relatedcustomer_link_id,
                    ps.product_link_id,
                    ps.sizedefinition_link_id,
                    ps.toprodprocessbuffer_id,
                    ps.fromprodprocessbuffer_id,
                    ps.batchnumber,
                    ps.scanstation,
                    count(*) number_of_scans,
                    sum(ps.minutesinpreviousbuffer) totalminutesinprevbuffer,
                    sum(ps.minutessinceinscan) totalminutessinceinscan
               FROM multireadscanbatchcontents mbc, productionprocessscan ps
              WHERE mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and mbc.multireadexception_id is null
                and nvl(mbc.lastscantimestamp,to_date('01012000','ddmmyyyy')) <= mbc.scantimestamp
                and ps.productionprocessscan_id = mbc.productionprocessscan_id
              GROUP BY
                    ps.businessunit_id,
                    ps.scandate,
                    ps.relatedcustomer_link_id,
                    ps.product_link_id,
                    ps.sizedefinition_link_id,
                    ps.toprodprocessbuffer_id,
                    ps.fromprodprocessbuffer_id,
                    ps.batchnumber,
                    ps.scanstation
            ) MERGE_SUBQUERY
          ON (ppsa.businessunit_id = MERGE_SUBQUERY.businessunit_id
          AND ppsa.scandate  = MERGE_SUBQUERY.scandate
          AND nvl(ppsa.relatedcustomer_link_id,-1) = nvl(MERGE_SUBQUERY.relatedcustomer_link_id,-1)
          AND ppsa.product_link_id  = MERGE_SUBQUERY.product_link_id
          AND ppsa.sizedefinition_link_id  = MERGE_SUBQUERY.sizedefinition_link_id
          AND nvl(ppsa.toprodprocessbuffer_id,-1) = nvl(MERGE_SUBQUERY.toprodprocessbuffer_id,-1)
          AND nvl(ppsa.fromprodprocessbuffer_id,-1) = nvl(MERGE_SUBQUERY.fromprodprocessbuffer_id,-1)
          AND nvl(ppsa.batchnumber,-1) = nvl(MERGE_SUBQUERY.batchnumber,-1)
          AND ppsa.scanstation  = MERGE_SUBQUERY.scanstation)
      WHEN MATCHED THEN
        UPDATE
           SET  ppsa.numberofscans = ppsa.numberofscans + MERGE_SUBQUERY.number_of_scans,
                ppsa.totalminutesinprevbuffer = ppsa.totalminutesinprevbuffer + MERGE_SUBQUERY.totalminutesinprevbuffer,
                ppsa.totalminutessinceinscan = ppsa.totalminutessinceinscan + MERGE_SUBQUERY.totalminutessinceinscan,
                ppsa.systemuser_id = gv_systemuser_id,
                ppsa.timestamp = sysdate
      WHEN NOT MATCHED THEN INSERT
               (productionprocessscanaggr_id,
                businessunit_id,
                scandate,
                relatedcustomer_link_id,
                product_link_id,
                sizedefinition_link_id,
                toprodprocessbuffer_id,
                fromprodprocessbuffer_id,
                batchnumber,
                scanstation,
                numberofscans,
                totalminutesinprevbuffer,
                totalminutessinceinscan,
                systemuser_id,
                timestamp)
               VALUES
               (seq_productionprocessscanaggr.nextval,
                MERGE_SUBQUERY.businessunit_id,
                MERGE_SUBQUERY.scandate,
                MERGE_SUBQUERY.relatedcustomer_link_id,
                MERGE_SUBQUERY.product_link_id,
                MERGE_SUBQUERY.sizedefinition_link_id,
                MERGE_SUBQUERY.toprodprocessbuffer_id,
                MERGE_SUBQUERY.fromprodprocessbuffer_id,
                MERGE_SUBQUERY.batchnumber,
                MERGE_SUBQUERY.scanstation,
                MERGE_SUBQUERY.number_of_scans,
                MERGE_SUBQUERY.totalminutesinprevbuffer,
                MERGE_SUBQUERY.totalminutessinceinscan,
                gv_systemuser_id,
                sysdate
               );

     exception
        when no_data_found then
          null;
     end;
   end; -- create_productionprocessbufscans

  ---------------------------------------------
  procedure delete_uniqueitem_buffer_info is
   begin
     begin
      writemultireaddebuglog('Delete Unique Item Buffer Info');
      DELETE
        FROM uniqueitembufferinfo u
       WHERE u.uniqueitem_id in
            (SELECT mbc.uniqueitem_id
               FROM multireadscanbatchcontents mbc
              WHERE mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and mbc.multireadexception_id is null
                and nvl(mbc.lastscantimestamp,to_date('01012000','ddmmyyyy')) <= mbc.scantimestamp);
    exception
      when no_data_found then
        null;
    end;
   end delete_uniqueitem_buffer_info;

   ---------------------------------------------
   procedure create_garmdisp_transactions is
   begin
    begin
    writemultireaddebuglog('Create garmentdispenser transactions for not inscanned general pool items');
    INSERT INTO gdtransaction g
               (gdtransaction_id,
                customer_link_id,
                gdtransctiontype,
                creationdate,
                status_id,
                garmentdispensercode,
                primaryid,
                lastissuedate,
                productcode,
                sizecode,
                numberofwashings,
                systemuser_id,
                timestamp,
                businessunit_id,
                changesperweek,
                personalizeditem,
                credit,
                customerowned)
    (SELECT seq_gdtransaction.nextval,
            m1.customer_id,
            21, -- gdtransactiontype = return to stock -> to take out of dispenser
            sysdate,
            gc_status_id_gd_new,
            gd.code,
            u.primaryid,
            nvl(u.lastoutscandate,trunc(m1.scantimestamp)), -- last issue date
            p.code, -- productcode
            s.code, -- sizecode
            0,   -- nr of washes
            gv_systemuser_id,
            sysdate,
            u.businessunit_id,
            0,   -- changes per week
            'N', -- personalized item
            0,   -- credit
            'N'  -- customer owned
       FROM multireadscanbatchcontents m1,
            garmentdispenser gd,
            customergarmentdispenser cgd,
            uniqueitem u,
            product p,
            sizedefinition s,
            department d,  -- prev dept
            distributionpoint dp  -- prev dip
      WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
        and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
        and dp.distributionpoint_id = m1.prev_distributionpoint_id
        and d.department_id = dp.department_id
        and gd.customer_id = d.customer_id
        and gd.deliverypoint_id = dp.deliverypoint_id
        and gd.usedforpool = 'Y'
        and cgd.customer_id = d.customer_id
        and cgd.generalpool = 'Y'
        and cgd.interface in (5,6) -- general or WnC
        and m1.poolitemyn = 'Y'
        and m1.relatedcustomer_id is null -- general pool
        and m1.stay_id = gc_stay_id_at_customer -- only for items not scanned in
        and u.uniqueitem_id = m1.uniqueitem_id
        and p.product_id = m1.product_id
        and s.sizedefinition_id = m1.sizedefinition_id
        and m1.multireadexception_id is null
    );
    exception
      when no_data_found then
        null;
    end;
   end; -- create_garmentdispenser_transactions

   -------------------------------------------------------------------------------------------------
    function f_calculatecontainerreturndate(fp_customer_id           in customer.customer_id%type,
                                            fp_containerdeliverydate in containerrent.deliverydate%type)
      return date is
      lv_calculatedreturndate date;
    begin
      begin
        select max(rc.drivingdate)
          into lv_calculatedreturndate
          from stop s
          join routecontrol rc
            on rc.routecontrol_id = s.routecontrol_id
         where s.customer_link_id = fp_customer_id
           and s.stoptype in (1, 3, 4)
           and rc.drivingdate > fp_containerdeliverydate
           and rc.drivingdate <= sysdate;
      exception
        when no_data_found then
          null;
      end;
      if lv_calculatedreturndate is null then
        for customerdeldays in (select distinct (d.daynumber)
                                  from customerdeliveryday dd
                                  join day d
                                    on d.day_id = dd.day_id
                                 where dd.customer_id = fp_customer_id
                                 order by 1 desc) loop
          select trunc(sysdate, 'IW') + customerdeldays.daynumber - 1
            into lv_calculatedreturndate
            from dual;
          if lv_calculatedreturndate < sysdate and
             lv_calculatedreturndate >= fp_containerdeliverydate then
            return(lv_calculatedreturndate);
          end if;
        end loop;
        if lv_calculatedreturndate > sysdate then
          select trunc(sysdate, 'IW') +
                 (select max(d.daynumber)
                    from customerdeliveryday dd
                    join day d
                      on d.day_id = dd.day_id
                   where dd.customer_id = fp_customer_id) - 8
            into lv_calculatedreturndate
            from dual;
        end if;
        if lv_calculatedreturndate is null or
           lv_calculatedreturndate < fp_containerdeliverydate then
          lv_calculatedreturndate := fp_containerdeliverydate;
        end if;
      end if;
      return(lv_calculatedreturndate);
    end f_calculatecontainerreturndate;
   ---------------------------------------------------------------------------------------------
    procedure update_containerrent_enddate(fp_container_id      in containerrent.container_id%type,
                                           fp_systemuser_id     in containerrent.systemuser_id%type,
                                           fp_isfromPackingNote in boolean) is

      lv_containerrent_id          number;
      lv_customer_id               number;
      lv_containerrentdeliverydate date;
      lv_calculatedreturndate      date;
      lv_container_id              number;
      lv_isfromPN                  varchar2(1);

    begin
      begin
        lv_container_id := fp_container_id;
        if fp_isfromPackingNote then
          lv_isfromPN := 'Y';
        else
          lv_isfromPN := 'N';
        end if;
        select cr.containerrent_id, cr.deliverydate, cbpc.customer_id
          into lv_containerrent_id,
               lv_containerrentdeliverydate,
               lv_customer_id
          from containerrent cr
          join containerbillpercustomer cbpc
            on cbpc.containerbillpercustomer_id =
               cr.containerbillpercustomer_id
         where cr.container_id = lv_container_id
           and (cr.deliverydate < trunc(sysdate) or
               (cr.deliverydate = trunc(sysdate) and lv_isfromPN = 'N'))
           and cr.returndate = getabsmaxdate
           and rownum = 1;
      exception
        when no_data_found then
          lv_containerrent_id := -1;
      end;
      if lv_containerrent_id > 0 then
        lv_calculatedreturndate := f_calculatecontainerreturndate(lv_customer_id,
                                                                  lv_containerrentdeliverydate);
        update containerrent cr
           set cr.returndate    = lv_calculatedreturndate,
               cr.systemuser_id = fp_systemuser_id,
               cr.timestamp     = sysdate
         where cr.containerrent_id = lv_containerrent_id;
      end if;
    end; ---- update_containerrent_enddate

   -------------------------------------------------------------------------------------------

   procedure update_container_rent is
   begin
     begin
       writemultireaddebuglog('Update Container Rent');
       for c_container in (select mbc.container_id, mbc.systemuser_id
                             from multireadscanbatchcontknt mbc
                            where mbc.multireadscanbatch_id =
                                  gv_multireadscanbatch_id
                              and (mbc.subbatchnumber = gv_subbatchnumber or
                                  gv_subbatchnumber = 0)
                              and mbc.multireadexception_id is null
                              and mbc.container_id is not null) loop

         update_containerrent_enddate(c_container.container_id,
                                      c_container.systemuser_id,
                                      false);
       end loop;
     exception
       when no_data_found then
         null;
       when others then
         writemultireaddebuglog('Error Update Container Rent' || sqlerrm);
     end;
   end;
   --------------------------------------------------------------------------------------------

   procedure create_container_return_for_previous_delivery(fp_container_id      in containercharge.container_id%type,
                                                           fp_systemuser_id     in containercharge.systemuser_id%type,
                                                           fp_isFromPackingNote in boolean) is

     lv_containercharge_id          containercharge.containercharge_id%type;
     lv_customer_id                 containerbillpercustomer.customer_id%type;
     lv_containerchargedeliverydate containercharge.chargecreateddate%type;
     lv_calculatedreturndate        containercharge.chargecreateddate%type;
     lv_distributionpoint_id        containercharge.distributionpoint_link_id%type;
     lv_containerbillpercust_id     containercharge.containerbillpercustomer_id%type;
     lv_isFromPN                    varchar2(1);

   begin
     begin
       if fp_isFromPackingNote then
         lv_isFromPN := 'Y';
       else
         lv_isFromPN := 'N';
       end if;
       select cc_del.containercharge_id,
              cc_del.chargecreateddate,
              cc_del.containerbillpercustomer_id,
              cc_del.distributionpoint_link_id,
              cbpc.customer_id
         into lv_containercharge_id,
              lv_containerchargedeliverydate,
              lv_containerbillpercust_id,
              lv_distributionpoint_id,
              lv_customer_id
         from containercharge cc_del
         join containerbillpercustomer cbpc
           on cbpc.containerbillpercustomer_id =
              cc_del.containerbillpercustomer_id
        where cc_del.type = 1
          and cc_del.container_id = fp_container_id
          and (cc_del.chargecreateddate < trunc(sysdate) or
              (cc_del.chargecreateddate = trunc(sysdate) and
              lv_isFromPN = 'N'))
          and not exists
        (select 1
                 from containercharge cc_ret
                where cc_ret.container_id = fp_container_id
                  and cc_ret.type = 2
                  and cc_ret.containerbillpercustomer_id =
                      cc_del.containerbillpercustomer_id
                  and cc_ret.chargecreateddate >= cc_del.chargecreateddate)
          and rownum = 1;
     exception
       when no_data_found then
         lv_containercharge_id := -1;
     end;
     if lv_containercharge_id > 0 then
       lv_calculatedreturndate := f_calculatecontainerreturndate(lv_customer_id,
                                                                 lv_containerchargedeliverydate);
       insert into containercharge
         (containercharge_id,
          container_id,
          containerbillpercustomer_id,
          distributionpoint_link_id,
          chargecreateddate,
          type,
          invoiceheader_id,
          systemuser_id,
          timestamp)
       values
         (seq_containercharge.nextval,
          fp_container_id,
          lv_containerbillpercust_id,
          lv_distributionpoint_id,
          lv_calculatedreturndate,
          2,
          null,
          fp_systemuser_id,
          sysdate);
     end if;
   end; ---- create_container_return_for_previous_delivery

   ---------------------------------------------------------------------------------------------
   procedure update_container_charges is
   begin
     begin
       writemultireaddebuglog('Update Container Charge');
       for c_container in (select mbc.container_id, mbc.systemuser_id
                             from multireadscanbatchcontknt mbc
                            where mbc.multireadscanbatch_id =
                                  gv_multireadscanbatch_id
                              and (mbc.subbatchnumber = gv_subbatchnumber or
                                  gv_subbatchnumber = 0)
                              and mbc.multireadexception_id is null
                              and mbc.container_id is not null) loop
         create_container_return_for_previous_delivery(c_container.container_id,
                                                       c_container.systemuser_id,
                                                       false);
       end loop;
     exception
       when no_data_found then
         null;
       when others then
         writemultireaddebuglog('Error Update Container Charge' || sqlerrm);
     end;
   end; --- update_container_charges

   ---------------------------------------------------------------------------------------------

   function find_ragged_by_primary_ID return number is
   /*  Try to find ID Codes in table for ragged items search on PRIMARY ID
       No BU filter is needed because chip numbers are supposed to be overall unique. */

    begin
    if (gv_items_in_batch > gv_items_found) then
      begin
      writemultireaddebuglog('Step 2A Find Rag by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT r.primaryid idcode,
                    r.raggeditem_id,
                    r.product_link_id,
                    r.sizedefinition_link_id,
                    r.finishingmethod_id,
                    r.relatedcustomerlink_id,
                    r.customerowned,
                    r.poolitem,
                    r.ragtimestamp,
                    r.secondaryid
               FROM (SELECT ri.primaryid,
                            max(ri.ragtimestamp) ragtimestamp -- most recent ragged item
                       FROM multireadscanbatchcontents m1, raggeditem ri
                      WHERE m1.idcode = ri.primaryid
                        and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                        and nvl(m1.multireadexception_id, 0) <> 15
                        and m1.uniqueitem_id is null -- only for those items that are not yet found in previous steps
                      group by ri.primaryid) X,
                    raggeditem r
              where r.primaryid = x.primaryid
                and r.ragtimestamp = x.ragtimestamp
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.raggeditem_id,
               m.product_id            = MERGE_SUBQUERY.product_link_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_link_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomerlink_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.status_id             = gc_status_id_ragged,
               m.lastscantimestamp     = MERGE_SUBQUERY.ragtimestamp,
               m.multireadexception_id = 4, -- ragged
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.secondaryid           = MERGE_SUBQUERY.secondaryid;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
    return 0;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
      end if;
    return 0;
    end; -- find_ragged_by_primary_ID

  ----------------------------------------------------------------------------------------------

  function find_ragged_by_secondary_ID return number is
  /*  Try to find ID Codes in table for ragged items search on SECONDARY ID
      No BU filter is needed because chip numbers are supposed to be overall unique. */

    begin
    if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      begin
      writemultireaddebuglog('Step 2B Find Rag by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT r.secondaryid idcode,
                    r.raggeditem_id,
                    r.product_link_id,
                    r.sizedefinition_link_id,
                    r.finishingmethod_id,
                    r.relatedcustomerlink_id,
                    r.customerowned,
                    r.poolitem,
                    r.ragtimestamp
               FROM (SELECT ri.secondaryid,
                            max(ri.ragtimestamp) ragtimestamp -- most recent ragged item
                       FROM multireadscanbatchcontents m1, raggeditem ri
                      WHERE m1.idcode = ri.secondaryid
                        and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                        and nvl(m1.multireadexception_id, 0) <> 15
                        and m1.uniqueitem_id is null -- only for those items that are not yet found in previous steps
                      group by ri.secondaryid) X,
                    raggeditem r
              where r.secondaryid = x.secondaryid
                and r.ragtimestamp = x.ragtimestamp
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.raggeditem_id,
               m.product_id            = MERGE_SUBQUERY.product_link_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_link_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomerlink_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.status_id             = gc_status_id_ragged, --ragged
               m.lastscantimestamp     = MERGE_SUBQUERY.ragtimestamp,
               m.multireadexception_id = 4, -- ragged
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N');
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
    return 0;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
      end if;
    return 0;
    end; -- find_ragged_by_secondary_ID

  ----------------------------------------------------------------------------------------------
  function f_validateinscanbatch(fp_called_by_inscan_YNR in varchar2) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      case fp_called_by_inscan_YNR
       when 'Y' then gv_main_code_block := 'Validate Inscan Batch';
       when 'R' then gv_main_code_block := 'Validate Inscan Reject Batch';
       else gv_main_code_block := 'Validate Laundry Buffer Scan Batch';
      end case;
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING ( SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.relatedcustomer_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    u.uhfbundle_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                    nvl(m1.uniqueitembatchnumber, u.batchnumber) uniqueitembatchnumber,
                    u.lastdistributionpoint_link_id,
                    u.customerowned,
                    u.lastdeliverynotenumber
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when fp_called_by_inscan_YNR = 'Y'
                                                  and MERGE_SUBQUERY.stay_id in (gc_stay_id_in_laundry, gc_stay_id_reject)
                                                  and (MERGE_SUBQUERY.scantimestamp - MERGE_SUBQUERY.lastscandate)*24 < gc_ss_inscanhourinterval
                                                  and gc_ss_inscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             when fp_called_by_inscan_YNR = 'R' and
                                                  MERGE_SUBQUERY.stay_id = gc_stay_id_reject
                                             then 31 -- Already scanned Rejected from Customer
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.uniqueitembatchnumber,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastdeliverynotenumber= MERGE_SUBQUERY.lastdeliverynotenumber;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.relatedcustomer_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    u.uhfbundle_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.batchnumber,
                    u.lastdistributionpoint_link_id,
                    u.customerowned,
                    u.lastdeliverynotenumber
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when fp_called_by_inscan_YNR = 'Y'
                                                  and MERGE_SUBQUERY.stay_id in (gc_stay_id_in_laundry, gc_stay_id_reject)
                                                  and (MERGE_SUBQUERY.scantimestamp - MERGE_SUBQUERY.lastscandate)*24 < gc_ss_inscanhourinterval
                                                  and gc_ss_inscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             when fp_called_by_inscan_YNR = 'R' and
                                                  MERGE_SUBQUERY.stay_id = gc_stay_id_reject
                                             then 31 -- Already scanned Rejected from Customer
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastdeliverynotenumber= MERGE_SUBQUERY.lastdeliverynotenumber;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;


      -- step 2A
      -- Try to find ID Codes in table for ragged items search on PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if (gv_items_in_batch > gv_items_found) then
      begin
      writemultireaddebuglog('Step 2A Find Rag by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT r.primaryid idcode,
                    r.raggeditem_id,
                    r.businessunit_id,
                    r.relatedcustomerlink_id relatedcustomer_id,
                    r.product_link_id,
                    r.sizedefinition_link_id,
                    r.finishingmethod_id,
                    r.distributionpoint_link_id,
                    r.poolitem,
                    r.ragtimestamp,
                    r.secondaryid,
                    case
                     when rr.allowreissue ='Y' and r.poolitem = 1 and r.weareremployment_link_id is null then
                      'Y'
                     when rr.allowreissue ='Y' and r.poolitem = 2 and r.weareremployment_link_id is not null then
                     (select 'Y'
                       from weareremployment we,
                            wearer w,
                            customer c,
                            wearerinventory wi
                      where we.weareremployment_id = r.weareremployment_link_id
                        and w.wearer_id = we.wearer_id
                        and c.customer_id = w.customer_id
                        and wi.weareremployment_id = r.weareremployment_link_id
                        and wi.product_id = r.product_link_id
                        and wi.sizedefinition_id = r.sizedefinition_link_id
                        and c.dateinactive >= trunc(sysdate)
                        and c.active = 'Y'
                        and w.dateinactive >= trunc(sysdate)
                        and wi.dateinactive >= trunc(sysdate))
                     else
                      'N'
                     end possible_to_reissue,
                     r.lastdistributionpoint_link_id,
                     r.customerowned
               FROM (SELECT ri.primaryid,
                            max(ri.ragtimestamp) ragtimestamp -- most recent ragged item
                       FROM multireadscanbatchcontents m1, raggeditem ri, ragreason rr
                      WHERE m1.idcode = ri.primaryid
                        and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                        and nvl(m1.multireadexception_id, 0) <> 15
                        and m1.uniqueitem_id is null -- only for those items that are not yet found in previous steps
                      group by ri.primaryid) X,
                    raggeditem r,
                    ragreason rr
              where r.primaryid = x.primaryid
                and r.ragtimestamp = x.ragtimestamp
                and rr.ragreason_id = r.ragreason_id
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.raggeditem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_link_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_link_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_link_id,
               m.status_id             = gc_status_id_ragged,
               m.stay_id               = gc_stay_id_at_customer,
               m.lastscantimestamp     = MERGE_SUBQUERY.ragtimestamp,
               m.multireadexception_id = case when gc_ss_reissueraggeditem='Y'
                                               and MERGE_SUBQUERY.possible_to_reissue='Y'
                                          then null -- no error because will be brought in circ automatically
                                          else 4 -- ragged
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.secondaryid           = MERGE_SUBQUERY.secondaryid,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
      end if;

      -- step 2B
      -- Try to find ID Codes in table for ragged items search on SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      begin
      writemultireaddebuglog('Step 2B Find Rag by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT r.secondaryid idcode,
                    r.raggeditem_id,
                    r.businessunit_id,
                    r.relatedcustomerlink_id relatedcustomer_id,
                    r.product_link_id,
                    r.sizedefinition_link_id,
                    r.finishingmethod_id,
                    r.distributionpoint_link_id,
                    r.poolitem,
                    r.ragtimestamp,
                    case
                     when rr.allowreissue ='Y' and r.poolitem = 1 and r.weareremployment_link_id is null then
                      'Y'
                     when rr.allowreissue ='Y' and r.poolitem = 2 and r.weareremployment_link_id is not null then
                     (select 'Y'
                       from weareremployment we,
                            wearer w,
                            customer c,
                            wearerinventory wi
                      where we.weareremployment_id = r.weareremployment_link_id
                        and w.wearer_id = we.wearer_id
                        and c.customer_id = w.customer_id
                        and wi.weareremployment_id = r.weareremployment_link_id
                        and wi.product_id = r.product_link_id
                        and wi.sizedefinition_id = r.sizedefinition_link_id
                        and c.dateinactive >= trunc(sysdate)
                        and c.active = 'Y'
                        and w.dateinactive >= trunc(sysdate)
                        and wi.dateinactive >= trunc(sysdate))
                     else
                      'N'
                     end possible_to_reissue,
                     r.lastdistributionpoint_link_id,
                     r.customerowned
               FROM (SELECT ri.secondaryid,
                            max(ri.ragtimestamp) ragtimestamp -- most recent ragged item
                       FROM multireadscanbatchcontents m1, raggeditem ri, ragreason rr
                      WHERE m1.idcode = ri.secondaryid
                        and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                        and m1.subbatchnumber = gv_subbatchnumber
                        and nvl(m1.multireadexception_id, 0) <> 15
                        and m1.uniqueitem_id is null -- only for those items that are not yet found in previous steps
                      group by ri.secondaryid) X,
                    raggeditem r,
                    ragreason rr
              where r.secondaryid = x.secondaryid
                and r.ragtimestamp = x.ragtimestamp
                and rr.ragreason_id = r.ragreason_id
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.raggeditem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_link_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_link_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_link_id,
               m.status_id             = gc_status_id_ragged, --ragged
               m.stay_id               = gc_stay_id_at_customer,
               m.lastscantimestamp     = MERGE_SUBQUERY.ragtimestamp,
               m.multireadexception_id = case when gc_ss_reissueraggeditem='Y'
                                               and MERGE_SUBQUERY.possible_to_reissue='Y'
                                          then null -- no error because will be brought in circ automatically
                                          else 4 -- ragged
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.prev_distributionpoint_id = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 4
      -- Mark all items that are scanned meanwhile with rejection reason
      begin
        writemultireaddebuglog('Step 4 Reject items scanned meanwhile');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 15
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.lastscantimestamp > m.scantimestamp;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

     -- optional step 5
     if gv_ss_hrsnoinscanaftrdelnote > 0 then
      begin
        writemultireaddebuglog('Step 5 Reject items scanned too soon after delivery');
        MERGE /*+index(m1 XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m1
        USING (SELECT m.idcode
                 FROM multireadscanbatchcontents m
                 JOIN packingnote pn on pn.notenumber = m.lastdeliverynotenumber
               WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                 and m.subbatchnumber = gv_subbatchnumber
                 and m.multireadexception_id is null
                 and m.stay_id = gc_stay_id_at_customer
                 and pn.processedtimestamp is not null
                 -- additional condition for performance: relying on short circuit boolean evaluation preventing that
                 -- for every old row plantoperationtimeoverlap needs to be called, which is slow for long periods
                 and m.scantimestamp - nvl(pn.processedtimestamp,to_date('01012000','ddmmyyyy')) < 5 -- less then 5 days ago
                 and plantoperatingtimeoverlap(gv_plant_id,nvl(pn.processedtimestamp,sysdate-5),m.scantimestamp) -- minutes
                     < gv_ss_hrsnoinscanaftrdelnote * 60
              ) MERGE_SUBQUERY
        ON (m1.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m1.subbatchnumber = gv_subbatchnumber
        AND m1.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m1.multireadexception_id = 3; -- scanned within time interval
          commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
     end if;

     return 0;
   end f_validateinscanbatch;

  ----------------------------------------------------------------------------------------------
  function f_validatescanbatchKNT(fp_transactiontype in number) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      case fp_transactiontype
       when gc_transtype_inscan then
          gv_main_code_block := 'Validate Inscan Batch Containers';
       when gc_transtype_disinfect then
          gv_main_code_block := 'Validate Disinfection Batch Containers';
       when gc_transtype_receive then
          gv_main_code_block := 'Validate Receive Batch Containers';
       when gc_transtype_send then
          gv_main_code_block := 'Validate Send Batch Containers';
       else
          gv_main_code_block := 'Validate Batch Containers';
      end case;

      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      gv_items_found_knt := 0;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
      USING (SELECT c.primaryid idcode,
                    c.container_id,
                    c.businessunit_id,
                    c.ownerbusinessunit_id,
                    c.ownercustomer_id,
                    c.containertype_id,
                    c.dateinactive,
                    c.stay_id,
                    c.distributionpoint_id,
                    c.lastdistributionpoint_link_id,
                    c.tareweight,
                    c.lastinscandate,
                    sc.secondaryid
               FROM multireadscanbatchcontknt m1, container c
                    left outer join secondarycontainer sc on (sc.container_id = c.container_id)
              WHERE m1.idcode = c.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.container_id          = MERGE_SUBQUERY.container_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.ownerbusinessunit_id  = MERGE_SUBQUERY.ownerbusinessunit_id,
               m.ownercustomer_id      = MERGE_SUBQUERY.ownercustomer_id,
               m.containertype_id      = MERGE_SUBQUERY.containertype_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.lastdistribpoint_id   = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.tareweight            = MERGE_SUBQUERY.tareweight,
               m.secondaryid           = MERGE_SUBQUERY.secondaryid,
               m.multireadexception_id = case when (fp_transactiontype = gc_transtype_inscan
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_in_laundry)
                                                or (fp_transactiontype = gc_transtype_disinfect
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_disinfect)
                                                or (fp_transactiontype = gc_transtype_receive
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_receive)
                                                or (fp_transactiontype = gc_transtype_send
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_send)
                                           then 20 -- container already scanned
                                           else
                                            case when fp_transactiontype = gc_transtype_inscan
                                                  and MERGE_SUBQUERY.dateinactive <= trunc(sysdate)
                                                 then 18 -- inactive container
                                                 else null
                                            end
                                         end;
      gv_items_found_knt := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found_knt := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates_knt(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secon_id_range_exists_knt='Y' and (gv_items_in_batch_knt > gv_items_found_knt) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
      USING (SELECT sc.secondaryid idcode,
                    c.container_id,
                    c.businessunit_id,
                    c.ownerbusinessunit_id,
                    c.ownercustomer_id,
                    c.containertype_id,
                    c.dateinactive,
                    c.stay_id,
                    c.distributionpoint_id,
                    c.lastdistributionpoint_link_id,
                    c.tareweight,
                    c.lastinscandate
               FROM multireadscanbatchcontknt m1, container c, secondarycontainer sc
              WHERE m1.idcode = sc.secondaryid
                and c.container_id = sc.container_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.container_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.container_id          = MERGE_SUBQUERY.container_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.ownerbusinessunit_id  = MERGE_SUBQUERY.ownerbusinessunit_id,
               m.ownercustomer_id      = MERGE_SUBQUERY.ownercustomer_id,
               m.containertype_id      = MERGE_SUBQUERY.containertype_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.lastdistribpoint_id   = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.tareweight            = MERGE_SUBQUERY.tareweight,
               m.secondaryid           = MERGE_SUBQUERY.idcode,
               m.multireadexception_id = case when (fp_transactiontype = gc_transtype_inscan
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_in_laundry)
                                                or (fp_transactiontype = gc_transtype_disinfect
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_disinfect)
                                                or (fp_transactiontype = gc_transtype_receive
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_receive)
                                                or (fp_transactiontype = gc_transtype_send
                                                and MERGE_SUBQUERY.stay_id = gc_stay_id_knt_send)
                                           then 20 -- container already scanned
                                           else
                                            case when fp_transactiontype = gc_transtype_inscan
                                                  and MERGE_SUBQUERY.dateinactive <= trunc(sysdate)
                                                 then 18 -- inactive container
                                                 else null
                                            end
                                         end;
      gv_items_found_knt := gv_items_found_knt + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates_knt(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      begin
      writemultireaddebuglog('Step 1C Populate primary ID');
      UPDATE multireadscanbatchcontknt m
         set m.idcode = (select c.primaryid from container c where c.container_id = m.container_id)
       where m.multireadscanbatch_id = gv_multireadscanbatch_id
         and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         and m.multireadexception_id is null
         and m.container_id is not null
         and m.secondaryid = m.idcode;
      commit;
      exception
        when no_data_found then
          null;
      end;

      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch_knt > gv_items_found_knt) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontknt m
           set m.multireadexception_id = 17 -- container not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.container_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;


     -- optional step 4 for inscan
     if fp_transactiontype = gc_transtype_inscan AND gv_ss_hrsnoinscanaftrdelnote > 0 then
      begin
        writemultireaddebuglog('Step 4 Reject containers scanned too soon after delivery');
        MERGE /*+index(m1 XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontknt m1
        USING (SELECT m.idcode
                 FROM multireadscanbatchcontknt m
                 JOIN container c on c.container_id = m.container_id
                 JOIN packingnote pn on pn.notenumber = c.lastnotenumber
               WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                 and m.subbatchnumber = gv_subbatchnumber
                 and m.multireadexception_id is null
                 and m.stay_id = gc_stay_id_knt_at_customer
                 and pn.processedtimestamp is not null
                 -- additional condition for performance: relying on short circuit boolean evaluation preventing that
                 -- for every old row plantoperationtimeoverlap needs to be called, which is slow for long periods
                 and m.scantimestamp - nvl(pn.processedtimestamp,to_date('01012000','ddmmyyyy')) < 5 -- less then 5 days ago
                 and plantoperatingtimeoverlap(gv_plant_id,nvl(pn.processedtimestamp,sysdate-5),m.scantimestamp) -- minutes
                     < gv_ss_hrsnoinscanaftrdelnote * 60
              ) MERGE_SUBQUERY
        ON (m1.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m1.subbatchnumber = gv_subbatchnumber
        AND m1.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m1.multireadexception_id = 3; -- scanned within time interval
          commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
     end if;

     return 0;
   end f_validatescanbatchKNT;

  ----------------------------------------------------------------------------------------------
  function f_validateoutscanbatch(fp_customer_id in number) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   ---------------------------------------------
   procedure retrieve_item_info is

   lv_lastinroute               number;
   lv_lastinroutestop           number;
   lv_lastindate                date;
   lv_plannedoutroutestop_id    number;
   lv_plannedoutroute_id        number;
   lv_plannedoutstop_id         number;
   lv_plannedoutdate            date;
   lv_outroutecontrol_id        number;
   begin
   -------------
   begin
    writemultireaddebuglog('Retrieve item info step 1 load wearer info');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    w.customer_id,
                    we.weareremployment_id,
                    we.distributionpoint_id,
                    case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select g.deliverypoint_id
                                    from garmentdispenser g
                                   where g.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u,
                    uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                    weareremployment we, wearer w
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.uniqueitem_id = unp.uniqueitem_id
                and we.weareremployment_id = unp.weareremployment_id
                and w.wearer_id = we.wearer_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                --and m1.multireadexception_id is null  --removed so that for rejected scans wearer is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.scan_id               = seq_scan.nextval,
               m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
      commit;
    exception
      when no_data_found then
        null;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
      end;
    end;
    -- find plpc
    begin
    writemultireaddebuglog('Retrieve item info step 2a plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.customer_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id;
      commit;
    exception
      when no_data_found then
        null;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
      end;
    end;
    -- load delayed even exchange and related dee delivery scheme
    begin
    writemultireaddebuglog('Retrieve item info step 2b plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    p.delayedevenexchange,
                    p.deedeliveryscheme_id
               FROM multireadscanbatchcontents m1, productlistpercustomer p
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.productlistpercustomer_id = m1.plpc_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.delayedevenexchange = MERGE_SUBQUERY.delayedevenexchange,
               m.deedeliveryscheme_id = MERGE_SUBQUERY.deedeliveryscheme_id;
      commit;
    exception
      when no_data_found then
        null;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
      end;
    end;
    -- safety net1: when plpc not found put delayed even exchange to 1 for garments.
    begin
    writemultireaddebuglog('Retrieve item info step 2c plpc');
    UPDATE multireadscanbatchcontents m
       SET m.delayedevenexchange = 1
     WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
       AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       AND m.plpc_id is null
       AND m.typeofmerchandize=2;
    commit;
    -- safety net2: when dee not populated put delayed even exchange to 1 for garments.
    UPDATE multireadscanbatchcontents m
       SET m.delayedevenexchange = 1
     WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
       AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       AND m.delayedevenexchange = 7
       AND m.deedeliveryscheme_id is null;
    commit;
    exception
      when no_data_found then
        null;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
      end;
    end;
    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      commit;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
        end;
      end;
    -- find last in date and route, batchwise, so not id by ID, but for all ID's of the
    -- same customer, deliverypoint and type of merchandize together.
    begin
     writemultireaddebuglog('Retrieve item info step 4 lastinroute');
     for vcursorI in  (SELECT m1.multireadscanbatch_id,
                              m1.customer_id,
                              m1.deliverypoint_id,
                              m1.typeofmerchandize
                         FROM multireadscanbatchcontents m1
                        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                         AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                          AND m1.customer_id is not null
                          AND m1.uniqueitem_id is not null
                          AND m1.multireadexception_id is null
                     GROUP BY m1.multireadscanbatch_id,
                              m1.customer_id,
                              m1.deliverypoint_id,
                              m1.typeofmerchandize
                      )
     loop
        pack_sort.getlastinroute(vcursorI.customer_id,trunc(sysdate),
                                 vcursorI.deliverypoint_id, vcursorI.typeofmerchandize,
                                 lv_lastinroute, lv_lastinroutestop, lv_lastindate);
        UPDATE multireadscanbatchcontents m
           SET m.lastindate = lv_lastindate,
               m.lastinroute_id = lv_lastinroute,
               m.lastinroutestop_id = lv_lastinroutestop
         WHERE m.multireadscanbatch_id = vcursorI.multireadscanbatch_id
           AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           AND m.customer_id = vcursorI.customer_id
           AND nvl(m.deliverypoint_id,-1) = nvl(vcursorI.deliverypoint_id,-1)
           AND m.typeofmerchandize = vcursorI.typeofmerchandize
           AND m.uniqueitem_id is not null
           AND m.multireadexception_id is null;
     end loop;
     commit;
    exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
        end;
    end;
    -- find planned out date and route, batchwise, so not id by ID, but for all ID's of the
    -- same customer and plpc together.
    begin
     writemultireaddebuglog('Retrieve item info step 5 plannedoutroute');
     for vcursorO in (SELECT m1.multireadscanbatch_id,
                            m1.customer_id,
                            m1.deliverypoint_id,
                            m1.typeofmerchandize,
                            m1.delayedevenexchange,
                            m1.deedeliveryscheme_id,
                            m1.plpc_id,
                            m1.lastindate,
                            m1.lastinroute_id,
                            m1.lastinroutestop_id,
                            m1.distributionpoint_id,
                            m1.uniqueitem_id
                       FROM multireadscanbatchcontents m1
                      WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                        AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                        AND m1.delayedevenexchange > 0 -- only for delayed even exchange!
                        AND m1.customer_id is not null
                        AND m1.uniqueitem_id is not null
                        AND m1.multireadexception_id is null
                   GROUP BY m1.multireadscanbatch_id,
                            m1.customer_id,
                            m1.deliverypoint_id,
                            m1.typeofmerchandize,
                            m1.delayedevenexchange,
                            m1.deedeliveryscheme_id,
                            m1.plpc_id,
                            m1.lastindate,
                            m1.lastinroute_id,
                            m1.lastinroutestop_id,
                            m1.distributionpoint_id,
                            m1.uniqueitem_id
                    )
     loop
         -- order 20014102
        if gs_ss_outconfirmedplannedroute in (1,3) then
           if gs_ss_deliverydetermination = 1 then
              pack_deliverybasics.determinedeldaterouteclean(gv_plant_id, vcursorO.customer_id, vcursorO.deliverypoint_id, null, vcursorO.typeofmerchandize,
                                                             nvl(vcursorO.lastindate,trunc(sysdate)), vcursorO.plpc_id, vcursorO.distributionpoint_id, 'N',
                                                            lv_plannedoutroutestop_id ,lv_plannedoutroute_id, lv_plannedoutstop_id , lv_outroutecontrol_id, lv_plannedoutdate);

           else
              pack_sort.fillplannedoutroute(gv_plant_id,
                                            trunc(sysdate),
                                            vcursorO.typeofmerchandize,
                                            vcursorO.delayedevenexchange,
                                            vcursorO.deedeliveryscheme_id,
                                            vcursorO.plpc_id,
                                            vcursorO.customer_id,
                                            vcursorO.deliverypoint_id,
                                            vcursorO.lastinroute_id,
                                            nvl(vcursorO.lastindate,trunc(sysdate)), -- Fix HVH 2/8/2013
                                            vcursorO.lastinroutestop_id,
                                            lv_plannedoutroutestop_id,
                                            lv_plannedoutroute_id,
                                            lv_plannedoutdate,
                                            gc_ss_scanbyroute);
           end if;
        else
           begin
             select uir.plannedoutroute_id,
                    uir.plannedoutdate,
                    uir.plannedoutstop_id
               into lv_plannedoutroute_id,
                    lv_plannedoutdate,
                    lv_plannedoutstop_id
               from uniqueitemroute uir
              where uir.uniqueitem_id = vcursorO.uniqueitem_id;
           exception
               when no_data_found then
                    lv_plannedoutroute_id := null;
                    lv_plannedoutdate     := null;
                    lv_plannedoutstop_id  := null;
           end;
        end if;
      UPDATE multireadscanbatchcontents m
         SET m.plannedoutdate = lv_plannedoutdate,
             m.plannedoutroute_id = lv_plannedoutroute_id,
             m.plannedoutstop_id = lv_plannedoutstop_id
       WHERE m.multireadscanbatch_id = vcursorO.multireadscanbatch_id
         AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         AND m.customer_id = vcursorO.customer_id
         AND nvl(m.deliverypoint_id,-1) = nvl(vcursorO.deliverypoint_id,-1)
         AND m.typeofmerchandize = vcursorO.typeofmerchandize
         AND nvl(m.plpc_id,-1) = nvl(vcursorO.plpc_id,-1)
         AND m.delayedevenexchange = vcursorO.delayedevenexchange
         AND nvl(m.deedeliveryscheme_id,-1) = nvl(vcursorO.deedeliveryscheme_id,-1)
         AND nvl(m.lastindate,trunc(sysdate)) = nvl(vcursorO.lastindate,trunc(sysdate)) -- Fix HVH 2/8/2013
         AND nvl(m.lastinroute_id,-1) = nvl(vcursorO.lastinroute_id,-1)
         AND m.uniqueitem_id is not null
         AND m.multireadexception_id is null;
       commit;
     end loop;
    commit;
    exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
        end;
    end;
   end; -- retrieve_item_info

   ---------------------------------------------------------------
   begin
      gv_main_code_block := 'Validate Outscan Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- step 2A
      if find_ragged_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 2B
      if find_ragged_by_secondary_ID <> 0 then
        return gc_result_ora_error;
      end if;


      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 4
      -- Mark pool items
      begin
        writemultireaddebuglog('Step 4');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 5 -- Pool item to be scanned on delivery note
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.poolitemyn = 'Y'
           and m.multireadexception_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 5
      -- Mark all with flags that prohibit delivery with exception reason
      begin
        writemultireaddebuglog('Step 5');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and exists (select 1
                                from uniqueitemflag uif, flag f
                               where uif.uniqueitem_id = m1.uniqueitem_id
                and uif.startdate <= trunc(sysdate)
                                and f.flag_id = uif.flag_id
                                and f.prohibitdelivery = 'Y')
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 10; -- Item has a flag that prohibits delivery
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if fp_customer_id is not null then
        begin
          writemultireaddebuglog('Step 6b2 Reject garments for other customer than selected customer');
          MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.uniqueitem_id
                   FROM multireadscanbatchcontents m1
                   join uniqueitemnonpool unp on unp.uniqueitem_id = m1.uniqueitem_id
                   join weareremployment we on we.weareremployment_id = unp.weareremployment_id
                   join wearer w on w.wearer_id = we.wearer_id
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.multireadexception_id is null
                    and w.customer_id <> fp_customer_id
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
          AND m.subbatchnumber = gv_subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
          WHEN MATCHED THEN
            UPDATE
               SET m.multireadexception_id = 9; -- Item is for a different customer
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      retrieve_item_info;

      return(gv_result);
   end f_validateoutscanbatch;

  ----------------------------------------------------------------------------------------------
  function f_validateoutscanpoolbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   function Find_by_primary_ID return number is
   -- Try to find ID Codes in database by PRIMARY ID
   -- No BU filter is needed because chip numbers are supposed to be overall unique.
   begin
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT /*+index(mb XPKMULTIREADBATCH) index(di XPKDISTRIBUTIONPOINT) index(uif XPKUNIQUEITEMFIXEDINFO)*/
                    u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    p.distributionpoint_id,
                    dp.customer_id,
                    u.relatedcustomer_id,
                    u.customerowned,
                    nvl(u.distributionpoint_id,u.lastdistributionpoint_link_id) prev_distributionpoint_id,
                    u.finishingmethod_id prev_finishingmethod_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    p.route_id,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    u.uhfbundle_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                   (select upc.client_id
                    from uniqueitemclientpool upc
                    where upc.uniqueitem_id = u.uniqueitem_id ) client_id
               FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                    packingnote p, distributionpoint di, department dp, uniqueitem u,
                    uniqueitemfixedinfo uif
              WHERE m1.idcode = u.primaryid
                and m1.uniqueitem_id is null
                and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and p.packingnote_id = mb.packingnote_id
                and di.distributionpoint_id = p.distributionpoint_id
                and dp.department_id = di.department_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.prev_finishingmethod_id   = MERGE_SUBQUERY.prev_finishingmethod_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.plannedoutroute_id    = MERGE_SUBQUERY.route_id,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id = gc_status_id_in_circ
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             when MERGE_SUBQUERY.Client_Id is not null
                                             then 35 -- Client Pool, item has been scanned out to a client
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.processedyn           = 'N',
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      return 0;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
   end;

   --------------------------
   begin
      gv_main_code_block := 'Validate Outscan Pool Batch';
      gv_items_found := 0;
      -- step 1A
      writemultireaddebuglog('Step 1A Find by Primary ID');
      if Find_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    p.distributionpoint_id,
                    dp.customer_id,
                    u.relatedcustomer_id,
                    u.customerowned,
                    nvl(u.distributionpoint_id,u.lastdistributionpoint_link_id) prev_distributionpoint_id,
                    u.finishingmethod_id prev_finishingmethod_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    p.route_id,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    u.uhfbundle_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                   (select upc.client_id
                    from uniqueitemclientpool upc
                    where upc.uniqueitem_id = u.uniqueitem_id ) client_id
               FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                    packingnote p,  distributionpoint di, department dp, uniqueitem u,
                    secondaryuniqueitem su,
                    uniqueitemfixedinfo uif
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and p.packingnote_id = mb.packingnote_id
                and di.distributionpoint_id = p.distributionpoint_id
                and dp.department_id = di.department_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.prev_finishingmethod_id   = MERGE_SUBQUERY.prev_finishingmethod_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.plannedoutroute_id    = MERGE_SUBQUERY.route_id,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id = gc_status_id_in_circ
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             when MERGE_SUBQUERY.Client_Id is not null
                                             then 35 -- Client Pool, item has been scanned out to a client
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.processedyn           = 'N',
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

    -- step 2A
      if find_ragged_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 2B
      if find_ragged_by_secondary_ID <> 0 then
        return gc_result_ora_error;
      end if;

     if (gv_databasecode = 'FIS') then
       update multireadscanbatchcontents m
         set m.product_id = (select min(p.product_id)
                               from product                p,
                                    product                pin,
                                    productlistpercustomer plpc
                              where pin.product_id = m.product_id
                                and plpc.customer_id = m.customer_id
                                and p.product_id = plpc.product_id
                                and substr(p.code, 1, 8) =
                                    substr(pin.code, 1, 8))
        where m.multireadscanbatch_id = gv_multireadscanbatch_id
         AND m.subbatchnumber = gv_subbatchnumber
         and m.product_id in
             (select p.product_id
                from product p
               where p.code in
                     ('ZH24BM01*', 'ZH23BS06*', 'ZH60DU02*', 'ZH02DS01*',
                      'ZH21HT04*', 'ZH60DU03*', 'ZH04KS01*', 'ZH10PS25*',
                      'ZH10PS01*', 'ZH60DU01*', 'ZH01SS01*', 'ZH60DU04*',
                      'ZH05SK01*'));
        commit;
      end if;

      -- 21481 --
      if gc_ss_uhfoutscanbundleperc > 0 and gv_outscantrackonly <> 'Y' then  -- add virtual scans only when % > 0
        if add_virtual_scans <> 0 then  -- if virtual scans added by function add_virtual_scans
          if Find_by_primary_ID <> 0 then  -- then redo Find_by_primary_ID for the added virtual scans
            return gc_result_ora_error;
          end if;
        end if;
       end if;
      -- End 21481 --

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark Items not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 4
      if gv_outscangarmentsaswell
       then
        begin
        writemultireaddebuglog('Step 4 Load wearer info');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.multireadscanbatch_id,
                        m1.subbatchnumber,
                        u.uniqueitem_id,
                        u.primaryid,
                        u.finishingmethod_id,
                        w.customer_id,
                        we.weareremployment_id,
                        we.distributionpoint_id,
                        case when we.deliverypoint_id is not null
                          then we.deliverypoint_id
                          else
                              case when we.locker_id is not null
                                then (select l.deliverypoint_id
                                        from locker l
                                       where l.locker_id = we.locker_id)
                                else (select g.deliverypoint_id
                                        from garmentdispenser g
                                       where g.garmentdispenser_id = we.garmentdispenser_id)
                              end
                        end deliverypoint_id,
                        u.customerowned,
                        uif.lastissuedate,
                        uif.qualitygrade_id,
                        p.typeofmerchandise,
                        m1.multireadexception_id,
                        (select max(ds.scantimestamp)
                               from deliveryscan ds
                              where ds.uniqueitem_link_id = u.uniqueitem_id
                                and nvl(ds.packingnote_id,0) = 0) delscan_timestamp -- outscan not put on a delnote
                   FROM multireadscanbatchcontents m1, uniqueitem u,
                        uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                        weareremployment we, wearer w
                  WHERE m1.uniqueitem_id = u.uniqueitem_id
                    and m1.uniqueitem_id = uif.uniqueitem_id
                    and m1.uniqueitem_id = unp.uniqueitem_id
                    and we.weareremployment_id = unp.weareremployment_id
                    and w.wearer_id = we.wearer_id
                    and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and m1.poolitemyn = 'N'
                    and m1.uniqueitem_id is not null
                    --and m1.multireadexception_id is null  --removed so that for rejected scans wearer is known
                                                            --and because of outscans within time interval
                    and p.product_id = u.product_id
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
          AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
          WHEN MATCHED THEN
            UPDATE
               SET m.idcode                = MERGE_SUBQUERY.primaryid,
                   m.customer_id           = MERGE_SUBQUERY.customer_id,
                   m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
                   m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                   m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
                   m.customerowned         = MERGE_SUBQUERY.customerowned,
                   m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
                   m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
                   m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
                   m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise,
                   m.deliveryscantimestamp = MERGE_SUBQUERY.delscan_timestamp,
                   m.multireadexception_id = case when MERGE_SUBQUERY.delscan_timestamp is not null
                                                   and MERGE_SUBQUERY.multireadexception_id = 3 -- time interval
                                               then null  -- remove exception
                                               else MERGE_SUBQUERY.multireadexception_id
                                             end;
          commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_result := gc_result_ora_error;
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            writemultireaderrorlog;
          end;
        end;
       else -- if not gv_outscangarmentsaswell
        begin
          -- Mark all personalized garments with rejection reason
          writemultireaddebuglog('Step 3 Reject personalized garments');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 6 -- Personalized garments not be to be scanned at delivery note
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.multireadexception_id is null
             and m.poolitemyn = 'N';
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if gv_outscangarmentsaswell

      -- step 5
      -- Mark all OR packs with exception reason
      begin
        writemultireaddebuglog('Step 5 Reject OR packs');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 7 -- OR packs not to be scanned in this screen
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.poolitemyn = 'Y'
           and m.orpackitemyn = 'Y';
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 6
      -- Mark all bundle contents with exception reason
      begin
        writemultireaddebuglog('Step 6 Reject Bundle contents');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT u.uniqueitem_id
                 FROM multireadscanbatchcontents m1, uniqueitem u
                WHERE m1.uniqueitem_id = u.uniqueitem_id
                  and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and u.currentuniquebundle_id is not null
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 8; -- Item is in a bundle, scan the bundle
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 7
      -- Mark all for different customer with exception reason
      begin
        writemultireaddebuglog('Step 7a Reject customer related pool items for other customer');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1, customer c
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and m1.poolitemyn = 'Y'
                  and m1.relatedcustomer_id is not null
                  and c.customer_id = m1.customer_id
/* ABS-11318 strict customerrelated check replaced by less strict check */
                  and m1.relatedcustomer_id <> c.customer_id
                  and m1.relatedcustomer_id <> c.debtor_id
                  and m1.relatedcustomer_id <> c.masteraccount_id
          and m1.relatedcustomer_id <> c.othercustomer_id
/*
                  and ((m1.relatedcustomer_id <> c.customer_id and c.customerrelated in (0,1))
                   or  (m1.relatedcustomer_id <> c.debtor_id and c.customerrelated = 2)
                   or  (m1.relatedcustomer_id <> c.masteraccount_id and c.customerrelated = 3))
*/
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 9; -- Item is for a different customer
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if gv_outscangarmentsaswell
       then
        begin
          writemultireaddebuglog('Step 7b Reject garments for other customer');
          MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.uniqueitem_id
                   FROM multireadscanbatchcontents m1,multireadscanbatch mb,
                        packingnote p, distributionpoint di,department dp
                  WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.multireadexception_id is null
                    and p.packingnote_id = mb.packingnote_id
                    and di.distributionpoint_id = p.distributionpoint_id
                    and dp.department_id = di.department_id
                    and m1.poolitemyn = 'N'
                    and m1.customer_id <> dp.customer_id -- different customer
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
          AND m.subbatchnumber = gv_subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
          WHEN MATCHED THEN
            UPDATE
               SET m.multireadexception_id = 9; -- Item is for a different customer
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if gv_outscangarmentsaswell

      -- step 8
      -- Mark all with flags that prohibit delivery with exception reason
      begin
        writemultireaddebuglog('Step 8 Reject items with flag that prohibits delivery');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and exists (select 1
                                from uniqueitemflag uif, flag f
                               where uif.uniqueitem_id = m1.uniqueitem_id
                                and uif.startdate <= trunc(sysdate)
                                and f.flag_id = uif.flag_id
                                and f.prohibitdelivery = 'Y')
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 10; -- Item has a flag that prohibits delivery
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 9
      -- check if not already scanned at this delivery note.
      begin
        writemultireaddebuglog('Step 9a Reject if pool item already scanned on this delivery note');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1, multireadscanbatch mb, packingnote p, uniqueitem u
                WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and p.packingnote_id = mb.packingnote_id
                  and u.lastdeliverynotenumber = p.notenumber
                  and m1.poolitemyn = 'Y'
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 12; -- Already scanned at this delivery note.
      commit;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      begin
        writemultireaddebuglog('Step 9b Reject if pool item already scanned on this bulk delivery note');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1, multireadscanbatch mb, packingnote p, uniqueitem u
                WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and p.bulkpackingnote_id = mb.packingnote_id
                  and u.lastdeliverynotenumber = p.notenumber
                  and m1.poolitemyn = 'Y'
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 12; -- Already scanned at this delivery note.
      commit;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if gv_outscangarmentsaswell then
        begin
          writemultireaddebuglog('Step 9c Reject if garment already scanned on this delivery note');
          MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.uniqueitem_id
                   FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                        deliveryscan ds
                  WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.multireadexception_id is null
                    and ds.uniqueitem_link_id = m1.uniqueitem_id
                    and ds.packingnote_id = mb.packingnote_id
                    and m1.poolitemyn = 'N'
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
          AND m.subbatchnumber = gv_subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
          WHEN MATCHED THEN
            UPDATE
               SET m.multireadexception_id = 12; -- Already scanned at this delivery note.
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;  --  if gv_outscangarmentsaswell

      -- 21481 --
      if gc_ss_uhfoutscanbundleperc > 0 and gv_outscantrackonly <> 'Y' then  -- add virtual non uniques only when % > 0
       begin
        writemultireaddebuglog('Step 10 add virtual non uniques');
          -- insert a dummy row for each not unique item
          insert into multireadscanbatchcontents
                      (multireadscanbatch_id,
                      subbatchnumber,
                      idcode,
                      customer_id,
                      product_id,
                      sizedefinition_id,
                      finishingmethod_id,
                      scantimestamp,
                      systemuser_id,
                      poolitemyn,
                      orpackitemyn,
                      uhfbundle_id,
                      processedyn,
                      virtualyn,
                      bundleaddedyn,
                      idcoderead)
         (select gv_multireadscanbatch_id,
                 gv_subbatchnumber,
                 '#'|| to_char(u.uhfbundle_id)||'-'|| to_char(z.itemseqnumber) as idcode,
                 u.customer_id,
                 u.product_link_id,
                 u.sizedefinition_link_id,
                 u.finishingmethod_id,
                 sysdate,
                 gv_systemuser_id,
                 'Y' as poolitemyn,
                 'N' as orpackitemyn,
                 u.uhfbundle_id,
                 'N' as processedyn,
                 'Y' as virtualyn,
                 'N' as bundleaddedyn,
                 '#'|| to_char(u.uhfbundle_id)||'-'|| to_char(z.itemseqnumber) as idcoderead
            from (SELECT b.uhfbundle_id,
                         x.customer_id,
                         b.product_link_id,
                         b.sizedefinition_link_id,
                         x.finishingmethod_id,
                         b.bundlesize - x.qty_unique qty_non_unique
                    FROM uhfbundle b,
                         (SELECT m.uhfbundle_id,
                                 max(m.customer_id) as customer_id,
                                 max(m.finishingmethod_id) as finishingmethod_id,
                                 count(*) qty_unique
                            FROM multireadscanbatchcontents m
                           WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                             AND m.uhfbundle_id in
                                 (select y.uhfbundle_id
                                    from (select mbc.uhfbundle_id,
                                                 ub.bundlesize,
                                                 count(mbc.uniqueitem_id) qty_scanned
                                            from multireadscanbatchcontents mbc,
                                                 uhfbundle                  ub
                                           where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                                             and mbc.subbatchnumber <= gv_subbatchnumber -- added by HVH for ABS-56030
                                             and ub.uhfbundle_id = mbc.uhfbundle_id
                                             and nvl(mbc.bundleaddedyn, 'N') <> 'Y'
                                           group by mbc.uhfbundle_id, ub.bundlesize
                                          having(count(mbc.uniqueitem_id) / ub.bundlesize) * 100 >= gc_ss_uhfoutscanbundleperc
                                             and count(mbc.uniqueitem_id) < ub.bundlesize) y)  -- added for ABS-55411
                           GROUP BY m.uhfbundle_id) x
                   WHERE b.uhfbundle_id = x.uhfbundle_id
                     AND b.deliverystatus < 2 -- not yet delivered
                     AND b.bundlesize > x.qty_unique) u,
                 (select rownum itemseqnumber  -- link to dual with connect level to explode the number of rows to qty_non_unique
                    from dual
                  connect by level <=
                             (select max(q.qty_non_unique)
                                from (SELECT b.uhfbundle_id,
                                             b.product_link_id,
                                             b.sizedefinition_link_id,
                                             b.bundlesize - x.qty_unique qty_non_unique
                                        FROM uhfbundle b,
                                             (SELECT m.uhfbundle_id, count(*) qty_unique
                                                FROM multireadscanbatchcontents m
                                               WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                                                 AND m.uhfbundle_id in
                                                     (select y.uhfbundle_id
                                                        from (select mbc.uhfbundle_id,
                                                                     ub.bundlesize,
                                                                     count(mbc.uniqueitem_id) qty_scanned
                                                                from multireadscanbatchcontents mbc,
                                                                     uhfbundle                  ub
                                                               where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                                                                 and ub.uhfbundle_id = mbc.uhfbundle_id
                                                                 and nvl(mbc.bundleaddedyn, 'N') <> 'Y'
                                                               group by mbc.uhfbundle_id,
                                                                        ub.bundlesize
                                                              having(count(mbc.uniqueitem_id) / ub.bundlesize) * 100 >= gc_ss_uhfoutscanbundleperc
                                                                 and count(mbc.uniqueitem_id) < ub.bundlesize) y)  -- added for ABS-55411
                                               GROUP BY m.uhfbundle_id) x
                                       WHERE b.uhfbundle_id = x.uhfbundle_id
                                         AND b.bundlesize > x.qty_unique) q)) z
           where z.itemseqnumber <= u.qty_non_unique);
           commit;

          update multireadscanbatchcontents mbc
             set mbc.bundleaddedyn = 'Y',
                 mbc.multireadexception_id =
                 case when mbc.multireadexception_id = 30 -- Possible stray read
                    then null                     -- then clear exception
                    else mbc.multireadexception_id -- else leave exception
                 end
           where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
             and mbc.uhfbundle_id in
                 (select distinct mbc.uhfbundle_id
                    from multireadscanbatchcontents mbc,
                         uhfbundle ub
                   where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                     and ub.uhfbundle_id = mbc.uhfbundle_id
                     and nvl(mbc.bundleaddedyn,'N') <> 'Y'
                   group by mbc.uhfbundle_id, ub.bundlesize
                  having (count(mbc.uniqueitem_id) / ub.bundlesize) *100 >= gc_ss_uhfoutscanbundleperc
                     and count(mbc.uniqueitem_id) < ub.bundlesize);  -- added for ABS-55411
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;  -- gc_ss_uhfoutscanbundleperc > 0 and gv_outscantrackonly <> 'Y'
      -- End 21481 --


      -- step 11A -- assign tags first to pack content products.
      if gv_outscantrackonly <> 'Y' then
      begin
        writemultireaddebuglog('Step 11a Find packingnote line for pack contents');
        for x in (select pl.packingsequence,
                         pl.packingnoteline_id,
                         plc.product_id,
                         plc.sizedefinition_id,
                         plc.finishingmethod_id,
                         sum(pl.tobedeliveredamount*plc.quantity) orderedqty,
                         sum(nvl(plc.scannedqty,0)) scannedqty_processed,
                         (select count(1)
                            from multireadscanbatchcontents mbc
                           where mbc.multireadscanbatch_id = m.multireadscanbatch_id
                             and mbc.subbatchnumber < gv_subbatchnumber
                             and mbc.product_id = plc.product_id
                             and mbc.sizedefinition_id = plc.sizedefinition_id
                             and mbc.packingnoteline_id = pl.packingnoteline_id
                             and mbc.multireadexception_id is null
                             and mbc.processedyn = 'N'
                         ) scannedqty_not_processed
                    from packingnoteline pl, packingnotelinecontent plc,
                         multireadscanbatch m, product pr, product pp
                   where m.multireadscanbatch_id = gv_multireadscanbatch_id
                     and pl.packingnote_id = m.packingnote_id
                     and plc.packingnoteline_id = pl.packingnoteline_id
                     and pr.product_id = plc.product_id
                     and pr.uniquepoolitem = 'Y'
                     and pp.product_id = pl.product_id -- pack product
                group by m.multireadscanbatch_id,
                         pl.packingsequence,
                         pl.packingnoteline_id,
                         pp.code,
                         plc.product_id,
                         plc.sizedefinition_id,
                         plc.finishingmethod_id
                  having sum(pl.tobedeliveredamount*plc.quantity) >
                         (sum(nvl(plc.scannedqty,0)) +
                          (select count(1)
                            from multireadscanbatchcontents mbc
                           where mbc.multireadscanbatch_id = m.multireadscanbatch_id
                             and mbc.subbatchnumber < gv_subbatchnumber
                             and mbc.product_id = plc.product_id
                             and mbc.packingnoteline_id = pl.packingnoteline_id
                             and mbc.sizedefinition_id = plc.sizedefinition_id
                             and mbc.multireadexception_id is null
                             and mbc.processedyn = 'N')
                         )
                order by pl.packingsequence, pp.code
                 ) loop
            MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
            USING (SELECT m1.idcode
                     FROM multireadscanbatchcontents m1, multireadscanbatch mb
                    WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                      and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                      and m1.subbatchnumber = gv_subbatchnumber
                      and m1.product_id = x.product_id
                      and m1.sizedefinition_id = x.sizedefinition_id
                      -- No filter on finishingmethod because it is not yet known here
                      and m1.multireadexception_id is null
                      and m1.packingnoteline_id is null
                      -- only the quantity that is still required.
                      and rownum <= x.orderedqty - x.scannedqty_processed - x.scannedqty_not_processed
                  ) MERGE_SUBQUERY
            ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
            AND m.subbatchnumber = gv_subbatchnumber
            AND m.idcode = MERGE_SUBQUERY.idcode)
            WHEN MATCHED THEN
              UPDATE
                 SET m.packingnoteline_id = x.packingnoteline_id,
                     m.packingsequence = x.packingsequence,
                     m.finishingmethod_id = x.finishingmethod_id,
                     m.partofpackyn = 'Y';
            commit;
        end loop;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 10B
      -- find packingnoteline
      begin
        writemultireaddebuglog('Step 11b Find packingnote line');
        MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.idcode,
                      (select min(l.packingnoteline_id)
                         from packingnoteline l
                        where l.packingnote_id = mb.packingnote_id
                          and l.product_id = m1.product_id
                          and l.sizedefinition_id = m1.sizedefinition_id) packingnoteline_id
                 FROM multireadscanbatchcontents m1, multireadscanbatch mb
                WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.packingnoteline_id is null
                  and m1.multireadexception_id is null
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m.packingnoteline_id = MERGE_SUBQUERY.packingnoteline_id,
                 m.partofpackyn = 'N';
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
         end;
       end;
      end if; -- if gv_outscantrackonly <> 'Y'

      -- step 12
      -- find plpc
      begin
        writemultireaddebuglog('Step 12a Find Plpc pool items');
        update multireadscanbatchcontents m
           set m.plpc_id= nvl(
                              (select min(p.productlistpercustomer_id)
                                 from productlistpercustomer p
                                where p.customer_id = m.customer_id
                                  and p.product_id = m.product_id
                                  and p.sizedefinition_id = m.sizedefinition_id
                                  and p.dateactive <= trunc(sysdate)
                                  and p.dateinactive >= trunc(sysdate)),
                              (select min(p.productlistpercustomer_id)
                                 from productlistpercustomer p
                                where p.customer_id = m.customer_id
                                  and p.product_id = m.product_id
                                  and p.sizedefinition_id = gv_size_star_id
                                  and p.dateactive <= trunc(sysdate)
                                  and p.dateinactive >= trunc(sysdate))
                              )
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.poolitemyn='Y'
           and m.multireadexception_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if gv_outscangarmentsaswell then
        begin
        writemultireaddebuglog('Step 12b Find Plpc garments');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.multireadscanbatch_id,
                        m1.subbatchnumber,
                        m1.uniqueitem_id,
                        nvl( -- first try active plpc
                        nvl( -- first try exact match size
                        (select p.productlistpercustomer_id
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = m1.sizedefinition_id
                            and p.finishingmethod_id = m1.finishingmethod_id
                            and p.dateactive <= trunc(sysdate)
                            and p.dateinactive >= trunc(sysdate))
                         , -- then try size *
                         (select p.productlistpercustomer_id
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = gv_size_star_id
                            and p.finishingmethod_id = m1.finishingmethod_id
                            and p.dateactive <= trunc(sysdate)
                            and p.dateinactive >= trunc(sysdate))
                         ), -- then try all plpc
                        nvl( -- first try exact match size
                        (select max(p.productlistpercustomer_id)
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = m1.sizedefinition_id
                            and p.finishingmethod_id = m1.finishingmethod_id)
                         , -- then try size *
                         (select max(p.productlistpercustomer_id)
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = gv_size_star_id
                            and p.finishingmethod_id = m1.finishingmethod_id)
                         )
                         ) productlistpercustomer_id
                   FROM multireadscanbatchcontents m1
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and m1.uniqueitem_id is not null
                    and m1.customer_id is not null
                    and m1.poolitemyn='N'
                    and m1.multireadexception_id is null
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
          AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
          WHEN MATCHED THEN
            UPDATE
               SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id;
          commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_result := gc_result_ora_error;
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            writemultireaderrorlog;
          end;
        end;
      end if; -- if gv_outscangarmentsaswell

      -- step 13
      -- mark those for which no contract could be found.
      begin
        writemultireaddebuglog('Step 13 Reject those without contract');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 11 -- No active contract found.
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.packingnoteline_id is null
           and m.plpc_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 14
      -- populate finishingmethod and packingsequence
      begin
        writemultireaddebuglog('Step 14 Populate finishingmethod and packing sequence');
       if gv_outscantrackonly <> 'Y'
       then
        update multireadscanbatchcontents m
           set m.finishingmethod_id =
               case when m.packingnoteline_id is not null
               then (select l.finishingmethod_id
                       from packingnoteline l
                      where l.packingnoteline_id = m.packingnoteline_id)
               else (select p.finishingmethod_id
                       from productlistpercustomer p
                      where p.productlistpercustomer_id = m.plpc_id)
               end,
               m.packingsequence =
               case when m.packingnoteline_id is not null
               then (select l.packingsequence
                       from packingnoteline l
                      where l.packingnoteline_id = m.packingnoteline_id)
               else nvl((select pps.packingsequence
                           from plantproductsettings pps,
                                multireadscanbatch mb,
                                businessunit b
                          where pps.plant_id = b.plant_id
                            and b.businessunit_id = mb.businessunit_id
                            and mb.multireadscanbatch_id = m.multireadscanbatch_id
                            and pps.product_id = m.product_id),
                         (select pr.packingsequence
                            from product pr
                           where pr.product_id = m.product_id)
                       )
               end
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.partofpackyn <> 'Y' -- exclude rows linked to pack product
           and m.multireadexception_id is null;
       else  -- if gv_outscantrackonly = 'Y' then only update fin.method
        update multireadscanbatchcontents m
           set m.finishingmethod_id = nvl((select p.finishingmethod_id
                                         from productlistpercustomer p
                                        where p.productlistpercustomer_id = m.plpc_id),m.prev_finishingmethod_id)
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.partofpackyn <> 'Y' -- exclude rows linked to pack product
           and m.multireadexception_id is null;
       end if; -- gv_outscantrackonly <> 'Y'
       commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 15
      -- mark those that are part of a virtual bundle that did not yet reach virtual bundle threshold
      if gv_ss_uhfstrayreadreduction = 1 and gc_ss_uhfoutscanbundleperc > 0 and gv_outscantrackonly <> 'Y' then
        begin
          writemultireaddebuglog('Step 15 Reject those that are part of a virtual bundle but are too few');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 30 -- Possible stray read
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.multireadexception_id is null
             and m.uhfbundle_id in
                 (select y.uhfbundle_id
                    from (select mbc.uhfbundle_id,
                                 ub.bundlesize,
                                 count(mbc.uniqueitem_id) qty_scanned
                            from multireadscanbatchcontents mbc,
                                 uhfbundle                  ub
                           where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                             and mbc.subbatchnumber <= gv_subbatchnumber -- added by HVH for ABS-56030
                             and ub.uhfbundle_id = mbc.uhfbundle_id
                           group by mbc.uhfbundle_id, ub.bundlesize
                          having(count(mbc.uniqueitem_id) / ub.bundlesize) * 100 < gc_ss_uhfoutscanbundleperc
                             and count(mbc.uniqueitem_id) < ub.bundlesize) y);
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      return 0;
   end f_validateoutscanpoolbatch;

----------------------------------------------------------------------------------------------
  function f_validateoutscanbatchKNT return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      gv_main_code_block := 'Validate Outscan Batch Containers';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      gv_items_found_knt := 0;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
      USING (SELECT c.primaryid idcode,
                    c.container_id,
                    c.businessunit_id,
                    c.ownerbusinessunit_id,
                    c.ownercustomer_id,
                    c.containertype_id,
                    c.dateinactive,
                    c.stay_id,
                    c.distributionpoint_id,
                    c.lastdistributionpoint_link_id,
                    c.tareweight,
                    c.lastoutscandate,
                    sc.secondaryid,
                    m1.scantimestamp
               FROM multireadscanbatchcontknt m1, container c
                    left outer join secondarycontainer sc on (sc.container_id = c.container_id)
              WHERE m1.idcode = c.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.container_id          = MERGE_SUBQUERY.container_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.ownerbusinessunit_id  = MERGE_SUBQUERY.ownerbusinessunit_id,
               m.ownercustomer_id      = MERGE_SUBQUERY.ownercustomer_id,
               m.containertype_id      = MERGE_SUBQUERY.containertype_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.lastdistribpoint_id   = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.tareweight            = MERGE_SUBQUERY.tareweight,
               m.secondaryid           = MERGE_SUBQUERY.secondaryid,
               m.multireadexception_id = case when MERGE_SUBQUERY.dateinactive <= trunc(sysdate)
                                          then 18 -- inactive container
                                          else case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                     and gv_ss_uhfkntoutscaninterval <> 0
                                                     and (MERGE_SUBQUERY.scantimestamp -
                                                          MERGE_SUBQUERY.lastoutscandate)*24 < gv_ss_uhfkntoutscaninterval
                                                  then 20 -- container already scanned
                                                  else null
                                               end
                                         end;
      gv_items_found_knt := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found_knt := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates_knt(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secon_id_range_exists_knt='Y' and (gv_items_in_batch_knt > gv_items_found_knt) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
      USING (SELECT sc.secondaryid idcode,
                    c.container_id,
                    c.businessunit_id,
                    c.ownerbusinessunit_id,
                    c.ownercustomer_id,
                    c.containertype_id,
                    c.dateinactive,
                    c.stay_id,
                    c.distributionpoint_id,
                    c.lastdistributionpoint_link_id,
                    c.tareweight,
                    c.lastoutscandate,
                    m1.scantimestamp
               FROM multireadscanbatchcontknt m1, container c, secondarycontainer sc
              WHERE m1.idcode = sc.secondaryid
                and c.container_id = sc.container_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.container_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.container_id          = MERGE_SUBQUERY.container_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.ownerbusinessunit_id  = MERGE_SUBQUERY.ownerbusinessunit_id,
               m.ownercustomer_id      = MERGE_SUBQUERY.ownercustomer_id,
               m.containertype_id      = MERGE_SUBQUERY.containertype_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.lastdistribpoint_id   = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.tareweight            = MERGE_SUBQUERY.tareweight,
               m.secondaryid           = MERGE_SUBQUERY.idcode,
               m.multireadexception_id = case when MERGE_SUBQUERY.dateinactive <= trunc(sysdate)
                                          then 18 -- inactive container
                                          else case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                     and gv_ss_uhfkntoutscaninterval <> 0
                                                     and (MERGE_SUBQUERY.scantimestamp -
                                                          MERGE_SUBQUERY.lastoutscandate)*24 < gv_ss_uhfkntoutscaninterval
                                                  then 20 -- container already scanned
                                                  else null
                                               end
                                         end;
      gv_items_found_knt := gv_items_found_knt + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates_knt(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
    end if;

      begin
      writemultireaddebuglog('Step 1C Check if not already added');
      UPDATE multireadscanbatchcontknt m
         set m.multireadexception_id = 20 -- Container already scanned at this note
       where m.multireadscanbatch_id = gv_multireadscanbatch_id
         and m.subbatchnumber = gv_subbatchnumber
         and m.multireadexception_id is null
         and m.container_id in
            (select pnc.container_id
               from multireadscanbatch mb,
                    packingnotecontainer pnc
              where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and pnc.packingnote_id = mb.packingnote_id
                and pnc.container_id = m.container_id);
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- Mark all for different customer with exception reason
      begin
        writemultireaddebuglog('Step 1D Check customer');
        MERGE /*+index(m XIE2MULTIREADSCANBATCHCONTKNT)*/ INTO multireadscanbatchcontknt m
        USING (SELECT m1.container_id
                 FROM multireadscanbatchcontknt m1,
                      multireadscanbatch mb,
                      packingnote p,
                      distributionpoint dp,
                      department d,
                      customer c
                WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and m1.ownercustomer_id is not null
                  and p.packingnote_id = mb.packingnote_id
                  and dp.distributionpoint_id = p.distributionpoint_id
                  and d.department_id = dp.department_id
                  and c.customer_id = d.customer_id
                  and m1.ownercustomer_id <> c.customer_id
                  and m1.ownercustomer_id <> c.debtor_id
                  and m1.ownercustomer_id <> c.masteraccount_id
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.container_id = MERGE_SUBQUERY.container_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 19; -- Container is for a different customer
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      begin
      writemultireaddebuglog('Step 2 Populate primary ID');
      UPDATE multireadscanbatchcontknt m
         set m.idcode = (select c.primaryid from container c where c.container_id = m.container_id)
       where m.multireadscanbatch_id = gv_multireadscanbatch_id
         and m.subbatchnumber = gv_subbatchnumber
         and m.multireadexception_id is null
         and m.container_id is not null
         and m.secondaryid = m.idcode;
         commit;
      exception
        when no_data_found then
          null;
      end;


      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch_knt > gv_items_found_knt) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontknt m
           set m.multireadexception_id = 17 -- container not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.container_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      return 0;
   end f_validateoutscanbatchKNT;

  ----------------------------------------------------------------------------------------------
  function f_validatescanandcountbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   function Find_by_primary_ID return number is
   -- Try to find ID Codes in database by PRIMARY ID
   -- No BU filter is needed because chip numbers are supposed to be overall unique.
   begin
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT /*+index(mb XPKMULTIREADBATCH) index(di XPKDISTRIBUTIONPOINT) index(uif XPKUNIQUEITEMFIXEDINFO)*/
                    u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    gv_consumptionpoint_id distributionpoint_id,
                    dp.customer_id,
                    di.deliverypoint_id,
                    u.relatedcustomer_id,
                    u.customerowned,
                    nvl(u.distributionpoint_id,u.lastdistributionpoint_link_id) prev_distributionpoint_id,
                    u.finishingmethod_id prev_finishingmethod_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    gv_route_id route_id,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    u.uhfbundle_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                    distributionpoint di, department dp, uniqueitem u,
                    uniqueitemfixedinfo uif
              WHERE m1.idcode = u.primaryid
                and m1.uniqueitem_id is null
                and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and di.distributionpoint_id = gv_consumptionpoint_id
                and dp.department_id = di.department_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.prev_finishingmethod_id   = MERGE_SUBQUERY.prev_finishingmethod_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.plannedoutroute_id    = MERGE_SUBQUERY.route_id,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id = gc_status_id_in_circ
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.processedyn           = 'N',
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      return 0;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
   end;

   --------------------------
   begin
      gv_main_code_block := 'Validate Scan and Count Batch';
      -- step 1A
      writemultireaddebuglog('Step 1A Find by Primary ID');
      if Find_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    gv_consumptionpoint_id distributionpoint_id,
                    dp.customer_id,
                    di.deliverypoint_id,
                    u.relatedcustomer_id,
                    u.customerowned,
                    nvl(u.distributionpoint_id,u.lastdistributionpoint_link_id) prev_distributionpoint_id,
                    u.finishingmethod_id prev_finishingmethod_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    gv_route_id route_id,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    u.uhfbundle_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, multireadscanbatch mb,
                    distributionpoint di, department dp, uniqueitem u,
                    secondaryuniqueitem su,
                    uniqueitemfixedinfo uif
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and di.distributionpoint_id = gv_consumptionpoint_id
                and dp.department_id = di.department_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.prev_finishingmethod_id   = MERGE_SUBQUERY.prev_finishingmethod_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.plannedoutroute_id    = MERGE_SUBQUERY.route_id,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id = gc_status_id_in_circ
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                             then 3 -- scanned within time interval
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.processedyn           = 'N',
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

     if (gv_databasecode = 'FIS') then
       update multireadscanbatchcontents m
         set m.product_id = (select min(p.product_id)
                               from product                p,
                                    product                pin,
                                    productlistpercustomer plpc
                              where pin.product_id = m.product_id
                                and plpc.customer_id = m.customer_id
                                and p.product_id = plpc.product_id
                                and substr(p.code, 1, 8) =
                                    substr(pin.code, 1, 8))
        where m.multireadscanbatch_id = gv_multireadscanbatch_id
         AND m.subbatchnumber = gv_subbatchnumber
         and m.product_id in
             (select p.product_id
                from product p
               where p.code in
                     ('ZH24BM01*', 'ZH23BS06*', 'ZH60DU02*', 'ZH02DS01*',
                      'ZH21HT04*', 'ZH60DU03*', 'ZH04KS01*', 'ZH10PS25*',
                      'ZH10PS01*', 'ZH60DU01*', 'ZH01SS01*', 'ZH60DU04*',
                      'ZH05SK01*'));
        commit;
      end if;

      -- 21481 --
      if gc_ss_uhfoutscanbundleperc > 0 and gv_outscantrackonly <> 'Y' then  -- add virtual scans only when % > 0
        if add_virtual_scans <> 0 then  -- if virtual scans added by function add_virtual_scans
          if Find_by_primary_ID <> 0 then  -- then redo Find_by_primary_ID for the added virtual scans
            return gc_result_ora_error;
          end if;
        end if;
       end if;
      -- End 21481 --

      -- step 2
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2 Mark Items not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 3
      if gv_outscangarmentsaswell
       then
        begin
        writemultireaddebuglog('Step 3 Load wearer info');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.multireadscanbatch_id,
                        m1.subbatchnumber,
                        u.uniqueitem_id,
                        u.primaryid,
                        u.finishingmethod_id,
                        w.customer_id,
                        we.weareremployment_id,
                        we.distributionpoint_id,
                        case when we.deliverypoint_id is not null
                          then we.deliverypoint_id
                          else
                              case when we.locker_id is not null
                                then (select l.deliverypoint_id
                                        from locker l
                                       where l.locker_id = we.locker_id)
                                else (select g.deliverypoint_id
                                        from garmentdispenser g
                                       where g.garmentdispenser_id = we.garmentdispenser_id)
                              end
                        end deliverypoint_id,
                        u.customerowned,
                        uif.lastissuedate,
                        uif.qualitygrade_id,
                        p.typeofmerchandise,
                        m1.multireadexception_id,
                        (select max(ds.scantimestamp)
                               from deliveryscan ds
                              where ds.uniqueitem_link_id = u.uniqueitem_id
                                and nvl(ds.packingnote_id,0) = 0) delscan_timestamp -- outscan not put on a delnote
                   FROM multireadscanbatchcontents m1, uniqueitem u,
                        uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                        weareremployment we, wearer w
                  WHERE m1.uniqueitem_id = u.uniqueitem_id
                    and m1.uniqueitem_id = uif.uniqueitem_id
                    and m1.uniqueitem_id = unp.uniqueitem_id
                    and we.weareremployment_id = unp.weareremployment_id
                    and w.wearer_id = we.wearer_id
                    and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.poolitemyn = 'N'
                    and m1.uniqueitem_id is not null
                    --and m1.multireadexception_id is null  --removed so that for rejected scans wearer is known
                                                            --and because of outscans within time interval
                    and p.product_id = u.product_id
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
          AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
          WHEN MATCHED THEN
            UPDATE
               SET m.idcode                = MERGE_SUBQUERY.primaryid,
                   m.customer_id           = MERGE_SUBQUERY.customer_id,
                   m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
                   m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                   m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
                   m.customerowned         = MERGE_SUBQUERY.customerowned,
                   m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
                   m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
                   m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
                   m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise,
                   m.deliveryscantimestamp = MERGE_SUBQUERY.delscan_timestamp /*,
                   m.multireadexception_id = case when MERGE_SUBQUERY.delscan_timestamp is not null
                                                   and MERGE_SUBQUERY.multireadexception_id = 3 -- time interval
                                               then null  -- remove exception
                                               else MERGE_SUBQUERY.multireadexception_id
                                             end */;
          commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_result := gc_result_ora_error;
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            writemultireaderrorlog;
          end;
        end;
       else -- if not gv_outscangarmentsaswell
        begin
          -- Mark all personalized garments with rejection reason
          writemultireaddebuglog('Step 3 Reject personalized garments');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 6 -- Personalized garments not be to be scanned at delivery note
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.multireadexception_id is null
             and m.poolitemyn = 'N';
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if gv_outscangarmentsaswell

      -- step 4
      -- Mark all OR packs with exception reason
      begin
        writemultireaddebuglog('Step 4 Reject OR packs');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 7 -- OR packs not to be scanned in this screen
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.poolitemyn = 'Y'
           and m.orpackitemyn = 'Y';
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 5
      -- Mark all bundle contents with exception reason
      begin
        writemultireaddebuglog('Step 5 Reject Bundle contents');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT u.uniqueitem_id
                 FROM multireadscanbatchcontents m1, uniqueitem u
                WHERE m1.uniqueitem_id = u.uniqueitem_id
                  and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and u.currentuniquebundle_id is not null
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 8; -- Item is in a bundle, scan the bundle
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 6
      -- Mark all for different customer with exception reason
      begin
        writemultireaddebuglog('Step 6a Reject customer related pool items for other customer');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1, customer c
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and m1.poolitemyn = 'Y'
                  and m1.relatedcustomer_id is not null
                  and c.customer_id = m1.customer_id
                  and m1.relatedcustomer_id <> c.customer_id
                  and m1.relatedcustomer_id <> c.debtor_id
                  and m1.relatedcustomer_id <> c.masteraccount_id
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 9; -- Item is for a different customer
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if gv_outscangarmentsaswell
       then
        begin
          writemultireaddebuglog('Step 6b Reject garments for other customer');
          MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.uniqueitem_id
                   FROM multireadscanbatchcontents m1,multireadscanbatch mb,
                        distributionpoint di,department dp
                  WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.multireadexception_id is null
                    and di.distributionpoint_id = m1.distributionpoint_id -- dip_id already populated during record creation
                    and dp.department_id = di.department_id
                    and m1.poolitemyn = 'N'
                    and m1.customer_id <> dp.customer_id -- different customer
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
          AND m.subbatchnumber = gv_subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
          WHEN MATCHED THEN
            UPDATE
               SET m.multireadexception_id = 9; -- Item is for a different customer
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
        begin
          writemultireaddebuglog('Step 6c Reject garments for other department/cp');
          MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.uniqueitem_id
                   FROM multireadscanbatchcontents m1
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.multireadexception_id is null
                    and m1.distributionpoint_id <> gv_consumptionpoint_id
                    and m1.poolitemyn = 'N'
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
          AND m.subbatchnumber = gv_subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
          WHEN MATCHED THEN
            UPDATE
               SET m.multireadexception_id = 21; -- Item is for a different department / cp
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if gv_outscangarmentsaswell

      -- step 7
      -- Mark all with flags that prohibit delivery with exception reason
      begin
        writemultireaddebuglog('Step 7 Reject items with flag that prohibits delivery');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and exists (select 1
                                from uniqueitemflag uif, flag f
                               where uif.uniqueitem_id = m1.uniqueitem_id
                                and uif.startdate <= trunc(sysdate)
                                and f.flag_id = uif.flag_id
                                and f.prohibitdelivery = 'Y')
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 10; -- Item has a flag that prohibits delivery
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 8
      -- find plpc
      begin
        writemultireaddebuglog('Step 8a Find Plpc pool items');
        update multireadscanbatchcontents m
           set m.plpc_id= nvl(
                              (select min(p.productlistpercustomer_id)
                                 from productlistpercustomer p
                                where p.customer_id = m.customer_id
                                  and p.product_id = m.product_id
                                  and p.sizedefinition_id = m.sizedefinition_id
                                  and p.dateactive <= trunc(sysdate)
                                  and p.dateinactive >= trunc(sysdate)),
                              (select min(p.productlistpercustomer_id)
                                 from productlistpercustomer p
                                where p.customer_id = m.customer_id
                                  and p.product_id = m.product_id
                                  and p.sizedefinition_id = gv_size_star_id
                                  and p.dateactive <= trunc(sysdate)
                                  and p.dateinactive >= trunc(sysdate))
                              )
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.poolitemyn='Y'
           and m.multireadexception_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if gv_outscangarmentsaswell then
        begin
        writemultireaddebuglog('Step 8b Find Plpc garments');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.multireadscanbatch_id,
                        m1.subbatchnumber,
                        m1.uniqueitem_id,
                        nvl( -- first try active plpc
                        nvl( -- first try exact match size
                        (select p.productlistpercustomer_id
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = m1.sizedefinition_id
                            and p.finishingmethod_id = m1.finishingmethod_id
                            and p.dateactive <= trunc(sysdate)
                            and p.dateinactive >= trunc(sysdate))
                         , -- then try size *
                         (select p.productlistpercustomer_id
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = gv_size_star_id
                            and p.finishingmethod_id = m1.finishingmethod_id
                            and p.dateactive <= trunc(sysdate)
                            and p.dateinactive >= trunc(sysdate))
                         ), -- then try all plpc
                        nvl( -- first try exact match size
                        (select max(p.productlistpercustomer_id)
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = m1.sizedefinition_id
                            and p.finishingmethod_id = m1.finishingmethod_id)
                         , -- then try size *
                         (select max(p.productlistpercustomer_id)
                           from productlistpercustomer p
                          where p.customer_id = m1.customer_id
                            and p.product_id = m1.product_id
                            and p.sizedefinition_id = gv_size_star_id
                            and p.finishingmethod_id = m1.finishingmethod_id)
                         )
                         ) productlistpercustomer_id
                   FROM multireadscanbatchcontents m1
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and m1.uniqueitem_id is not null
                    and m1.customer_id is not null
                    and m1.poolitemyn='N'
                    and m1.multireadexception_id is null
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
          AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
          WHEN MATCHED THEN
            UPDATE
               SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id;
          commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_result := gc_result_ora_error;
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            writemultireaderrorlog;
          end;
        end;
      end if; -- if gv_outscangarmentsaswell

      -- step 9
      -- mark those for which no contract could be found.
      begin
        writemultireaddebuglog('Step 9 Reject those without contract');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 11 -- No active contract found.
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.plpc_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      begin
        writemultireaddebuglog('Step 10 Update Finishing method for poolitems');
        update multireadscanbatchcontents m
           set m.finishingmethod_id = (select p.finishingmethod_id
                                         from productlistpercustomer p
                                        where p.productlistpercustomer_id = m.plpc_id)
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.poolitemyn='Y'
           and m.plpc_id is not null
           and m.multireadexception_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      begin
        writemultireaddebuglog('Step 11 deliveryscantimestamp for poolitems');
        -- this is done so that it is known that this is a rescan, only when for same cons.point
        update multireadscanbatchcontents m
           set m.deliveryscantimestamp =
               (select max(ds.scantimestamp)
                  from deliveryscan ds
                 where ds.uniqueitem_link_id = m.uniqueitem_id
                   and nvl(ds.packingnote_id,0) = 0   -- outscan not put on a delnote
                   and ds.distributionpoint_link_id = gv_consumptionpoint_id)
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.poolitemyn='Y'
           and m.multireadexception_id is null;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;


      return 0;
   end f_validatescanandcountbatch;


  ----------------------------------------------------------------------------------------------
  function f_validatestack return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

--------- HVH ABS-13664
  lv_number_pool_items            number;
  lv_number_nonpool_items         number;
  lv_number_unknown_items         number;
  lv_number_other_rejections      number;
  lv_number_distinct_products     number;
  lv_number_distinct_sizes        number;
  lv_stackcheck_stackproduct_id   number;
  lv_stackcheck_stacksize_id      number;
  lv_substituted_product_id       number;
  lv_substituted_size_id          number;
--  lv_valid_options                number;
  lv_nrofitems_product1           number;
  lv_nrofitems_product2           number;
  lv_stackcheck_packproduct_id    number;
  lv_disimilarityfactor_pack1     number;  -- used for pack_product determination
  lv_disimilarityfactor_pack2     number;  -- used for pack_product determination
  lv_nr_of_rows                   number;  -- used for pack_product determination
  lv_stackcheck_product_id        number;
  lv_stackcheck_size_id           number;
  lv_stackcheckpack               varchar2(1);
  lv_stackcheckproductidentified  varchar2(1);
  lv_mixedproductsallowed         varchar2(1);
  lv_itemspartlytagged            varchar2(1);
  lv_customers_allow_mixed_prod   number;
  lv_products_partly_tagged       number;

  lv_min_relatedcustomer_id       number;
  lv_max_relatedcustomer_id       number;
  lv_relatedcustomer_id_stack     number;
  lv_customer_id_packingnote      number;
  lv_nr_of_general_pool_items     number;
  lv_ordered_qty                  number;
  lv_pn_found                     number;
  lv_produced_stack_qty           number;

  ------------------------------------------
  procedure assing_unknown_items is

  lv_product_id                    number;
  lv_size_id                       number;
  lv_finmethod_id                  number;
  lv_customer_owned                varchar2(1);
  lv_relatedcustomer_id            number;
  lv_qualitygrade_id               number;
  lv_supplier_id                   number;
  lv_currency_id                   number;
  lv_purchase_price                number(15,6);
  lv_reasoncode_id                 number;

  begin
     begin
     writemultireaddebuglog('Select item properties');
     ---Step 1 check defaults for unknown items
     SELECT m1.product_id,
            m1.sizedefinition_id,
            u.finishingmethod_id,
            u.customerowned,
            m1.relatedcustomer_id,
            uif.qualitygrade_id,
            uif.supplier_id,
            uif.currency_id,
            uif.purchaseprice,
            uif.reasoncode_id
       INTO lv_product_id,
            lv_size_id,
            lv_finmethod_id,
            lv_customer_owned,
            lv_relatedcustomer_id,
            lv_qualitygrade_id,
            lv_supplier_id,
            lv_currency_id,
            lv_purchase_price,
            lv_reasoncode_id
       FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif
      WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
        AND uif.uniqueitem_id = m1.uniqueitem_id
        AND u.uniqueitem_id = m1.uniqueitem_id
        AND m1.multireadexception_id is null
        AND rownum = 1;

     --step 2 take new uniqueitem_id for new items
     writemultireaddebuglog('Create UniqueItem IDs');
     UPDATE multireadscanbatchcontents m1
        SET m1.uniqueitem_id = seq_uniqueitem.nextval
      WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
        and m1.multireadexception_id = 1;

      --step 3 insert unique item
      writemultireaddebuglog('Insert_unique_item');
      INSERT INTO uniqueitem u
       (uniqueitem_id,
        primaryid,
        idcodesequencenumber,
        statuschangedate,
        staychangedate,
        lastinscandate,
        lastoutscandate,
        lastscandate,
        iteminfoupdatedate,
        washestotal,
        repairstotal,
        rewashtotal,
        customerowned,
        businessunit_id,
        status_id,
        prevstatus_id,
        prevstay_id,
        stay_id,
        product_id,
        sizedefinition_id,
        finishingmethod_id,
        relatedcustomer_id,
        distributionpoint_id,
        lastdistributionpoint_link_id,
        systemuser_id,
        timestamp,
        planneddeliverydate,
        poolitem,
        deliveryfromstock,
        startrentfrom,
        unrelatedloan_id,
        residualvalue)
      (SELECT m1.uniqueitem_id uniqueitem_id,
              m1.idcode primaryid,
              1 idcodesequencenumber,
              trunc(m1.scantimestamp) statuschangedate,
              trunc(m1.scantimestamp) staychangedate,
              null lastinscandate,
              null lastoutscandate,
              m1.scantimestamp lastscandate,
              trunc(m1.scantimestamp) iteminfoupdatedate,
              0 washestotal,
              0 repairstotal,
              0 rewashtotal,
              lv_customer_owned customerowned,
              gv_businessunit_id businessunit_id,
              gc_status_id_in_circ status_id,
              null prevstatus_id,
              null prevstay_id,
              gc_stay_id_in_laundry stay_id,
              lv_product_id product_id,
              lv_size_id sizedefinition_id,
              lv_finmethod_id finishingmethod_id,
              lv_relatedcustomer_id relatedcustomer_id,
              null distributionpoint_id,
              null lastdistributionpoint_link_id,
              gv_systemuser_id systemuser_id,
              sysdate timestamp,
              null planneddeliverydate,
              1 poolitem,
              'N' deliveryfromstock,
              1 startrentfrom, -- in circ immediiately
              null unrelatedloan_id,
              0 residualvalue
         FROM multireadscanbatchcontents m1
        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and m1.multireadexception_id = 1); -- unknown

      --Step 4 create uniqueitemfixedinfo, insert into unique item fixed info
      writemultireaddebuglog('Insert_unique_item_fixed_info');
      INSERT INTO uniqueitemfixedinfo u
       (uniqueitem_id,
        purchasedate,
        lastonstockdate,
        firstissuedate,
        lastissuedate,
        numberofissues,
        enddatefullrent,
        daysincircprevissue,
        daysinstockprevious,
        purchaseprice,
        remark,
        qualitygrade_id,
        supplier_id,
        currency_id,
        issuedbyworkorder_id,
        reasoncode_id,
        systemuser_id,
        timestamp,
        stockroomlocation_id,
        temporaryid)
      (SELECT m1.uniqueitem_id,
              trunc(m1.scantimestamp) purchasedate,
              null lastonstockdate,
              trunc(m1.scantimestamp) firstissuedate,
              trunc(m1.scantimestamp) lastissuedate,
              1 numberofissues,
              to_date('20991231','YYYYMMDD') enddatefullrent,
              0 daysincircprevissue,
              0 daysinstockprevious,
              lv_purchase_price purchaseprice,
              null remark,
              lv_qualitygrade_id qualitygrade_id,
              lv_supplier_id supplier_id,
              lv_currency_id currency_id,
              null issuedbyworkorder_id,
              lv_reasoncode_id reasoncode_id,
              gv_systemuser_id systemuser_id,
              sysdate timestamp,
              null stockroomlocation_id,
              'N' temporaryid
         FROM multireadscanbatchcontents m1
        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and m1.multireadexception_id = 1); -- unknown

      --Step 5 create uniqueitem link
      writemultireaddebuglog('Insert_unique_item_link');
      INSERT INTO uniqueitem_link u
       (uniqueitem_link_id,
        uniqueitem_id,
        raggeditem_id,
        systemuser_id,
        timestamp)
      (SELECT m1.uniqueitem_id,
              m1.uniqueitem_id,
              null raggeditem_id,
              gv_systemuser_id systemuser_id,
              sysdate timestamp
         FROM multireadscanbatchcontents m1
        WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and m1.multireadexception_id = 1); -- unknown

      --Step 6 create issuehistory transaction
      writemultireaddebuglog('Insert_issue_history');
      INSERT INTO issuehistory u
             (issuehistory_id,
              processbusinessunit_id,
              forbusinessunit_id,
              uniqueitem_link_id,
              reasoncode_id,
              customer_link_id,
              weareremployment_link_id,
              distributionpoint_link_id,
              product_link_id,
              assigndate,
              incircdate,
              quantity,
              assignyear,
              assignweek,
              assignday,
              incircyear,
              incircweek,
              incircday,
              issuestatus,
              workstationcode,
              customerowned,
              customerrelated,
              issuegrade_id,
              requestedgrade_id,
              prepcharge,
              currency_id,
              systemuser_id,
              timestamp,
              invoicebusinessunit_id,
              invoiceheader_id,
              primaryid,
              amount,
              sizedefinition_link_id)
      (SELECT seq_issuehistory.nextval issuehistory_id,
              gv_businessunit_id processbusinessunit_id,
              gv_businessunit_id forbusinessunit_id,
              m1.uniqueitem_id uniqueitem_link_id,
              lv_reasoncode_id reasoncode_id,
              lv_relatedcustomer_id customer_link_id,
              null weareremployment_link_id,
              null distributionpoint_link_id,
              lv_product_id product_link_id,
              trunc(m1.scantimestamp) assigndate,
              trunc(m1.scantimestamp) incircdate,
              1 quantity,
              getyearofweek(trunc(m1.scantimestamp)) assignyear,
              getisoweek(trunc(m1.scantimestamp)) assignweek,
              getabsdaynumber(trunc(m1.scantimestamp)) assignday,
              getyearofweek(trunc(m1.scantimestamp)) incircyear,
              getisoweek(trunc(m1.scantimestamp)) incircweek,
              getabsdaynumber(trunc(m1.scantimestamp)) incircday,
              1 issuestatus, -- free of charge
              w.code workstationcode,
              lv_customer_owned customerowned,
              case when lv_relatedcustomer_id is not null
               then 'Y'
               else 'N'
              end customerrelated,
              lv_qualitygrade_id issuegrade_id,
              lv_qualitygrade_id requestedgrade_id,
              0 prepcharge,
              lv_currency_id currency_id,
              gv_systemuser_id systemuser_id,
              sysdate timestamp,
              gv_businessunit_id invoicebusinessunit_id,
              null invoiceheader_id,
              m1.idcode primaryid,
              0 amount,
              lv_size_id sizedefinition_link_id
         FROM multireadscanbatchcontents m1, multireadscanbatch m, workstation w
        WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
          and m1.multireadscanbatch_id = m.multireadscanbatch_id
          and w.workstation_id = m.workstation_id
          and m1.multireadexception_id = 1); -- unknown

      --Step 7 create assign scan
      writemultireaddebuglog('Insert_scan');
      INSERT INTO scan s
             (scan_id,
              businessunit_id,
              scantimestamp,
              primaryid,
              customer_link_id,
              weareremployment_link_id,
              distributionpoint_link_id,
              product_link_id,
              sizedefinition_link_id,
              stay_id,
              status_id,
              scanstation,
              issuedate,
              route_id,
              reasoncode_id,
              customerowned,
              year,
              week,
              dayno,
              qualitygrade_id,
              systemuser_id,
              timestamp,
              prevstay_id,
              transactiontype_id,
              dayslate,
              uniqueitem_link_id)
      (SELECT seq_scan.nextval scan_id,
              gv_businessunit_id businessunit_id,
              m1.scantimestamp scantimestamp,
              m1.idcode primaryid,
              lv_relatedcustomer_id customer_link_id,
              null weareremployment_link_id,
              null distributionpoint_link_id,
              lv_product_id product_link_id,
              lv_size_id sizedefinition_link_id,
              gc_stay_id_in_laundry stay_id,
              gc_status_id_in_circ status_id,
              w.code scanstation,
              trunc(m1.scantimestamp) issuedate,
              null route_id,
              lv_reasoncode_id reasoncode_id,
              lv_customer_owned customerowned,
              getyearofweek(trunc(m1.scantimestamp))year,
              getisoweek(trunc(m1.scantimestamp)) week,
              getabsdaynumber(trunc(m1.scantimestamp)) dayno,
              lv_qualitygrade_id qualitygrade_id,
              gv_systemuser_id systemuser_id,
              sysdate timestamp,
              null prevstay_id,
              36 transactiontype_id, ---36 = Assign and In Circ Via Stack Check
              0 dayslate,
              m1.uniqueitem_id uniqueitem_link_id
         FROM multireadscanbatchcontents m1, multireadscanbatch m, workstation w
        WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
          and m1.multireadscanbatch_id = m.multireadscanbatch_id
          and w.workstation_id = m.workstation_id
          and m1.multireadexception_id = 1); -- unknown

      -- Step 8 update multiread scan batch contents
      writemultireaddebuglog('Update multiread scanbatch contents');
      UPDATE multireadscanbatchcontents m1
         set m1.multireadexception_id = null, -- no longer an exeption
             m1.product_id = lv_product_id,
             m1.sizedefinition_id = lv_size_id,
             m1.poolitemyn = 'Y',
             m1.orpackitemyn = 'N',
             m1.stay_id = gc_stay_id_in_laundry,
             m1.status_id = gc_status_id_in_circ,
             m1.relatedcustomer_id = lv_relatedcustomer_id
      WHERE  m1.multireadscanbatch_id = gv_multireadscanbatch_id
      and    m1.multireadexception_id = 1;
    commit;

    exception
      when no_data_found then
        null;
    end;
  end; -- assing_unknown_items
--------- HVH ABS-13664  END

   --------------------------
   begin
      gv_code_block := 'Validate Stack';

      -- step 0 determine customer of packingnote
      if gv_packingnote_id > 0 then
          select d.customer_id
            into lv_customer_id_packingnote
            from packingnote p
            join distributionpoint dp on dp.distributionpoint_id = p.distributionpoint_id
            join department d on d.department_id = dp.department_id
           where p.packingnote_id = gv_packingnote_id;
      end if;

      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.relatedcustomer_id,
                    u.poolitem,
                    u.customerowned,
                    u.status_id,
                    u.stay_id,
                    u.uhfbundle_id,
                    u.lastscandate,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.batchnumber,
                    m1.scantimestamp
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id = gc_status_id_in_circ
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                                  and gv_ss_createdelnotestackcheck = 1
                                             then 3 -- scanned within time interval
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.relatedcustomer_id,
                    u.customerowned,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.lastscandate,
                    u.batchnumber,
                    m1.scantimestamp
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id = gc_status_id_in_circ
                                          then
                                            case when MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer
                                                  and (MERGE_SUBQUERY.scantimestamp -
                                                       MERGE_SUBQUERY.lastscandate)*24 < gc_ss_outscanhourinterval
                                                  and gc_ss_outscanhourinterval <> 0
                                                  and gv_ss_createdelnotestackcheck = 1
                                             then 3 -- scanned within time interval
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
       end;
      END LOOP;
      end if;

      if gv_dbSetting <> 'PED' then
      -- step 2A
      if find_ragged_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 2B
      if find_ragged_by_secondary_ID <> 0 then
        return gc_result_ora_error;
      end if;
      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 4
      -- Mark all bundle contents with exception reason
      begin
        writemultireaddebuglog('Step 4 Part of a bundle');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT u.uniqueitem_id
                 FROM multireadscanbatchcontents m1, uniqueitem u
                WHERE m1.uniqueitem_id = u.uniqueitem_id
                  and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and u.currentuniquebundle_id is not null
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 8; -- Item is in a bundle, scan the bundle
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      -- step 5
      -- Mark all with flags that prohibit delivery with exception reason
      begin
        writemultireaddebuglog('Step 5 Has flags');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id
                 FROM multireadscanbatchcontents m1
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and exists (select 1
                                from uniqueitemflag uif, flag f
                               where uif.uniqueitem_id = m1.uniqueitem_id
                                and uif.startdate <= trunc(sysdate)
                                and f.flag_id = uif.flag_id
                                and f.prohibitdelivery = 'Y')
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.multireadexception_id = 10; -- Item has a flag that prohibits delivery
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

     -- step 5.1
      -- Mark all with total rewashes > ss value with exception reason
     if gv_dbSetting = 'PED' and gv_ss_rewashmax > 0 then
        begin
          writemultireaddebuglog('Step 5.1 Max rewashes reached');
          MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
          USING (SELECT m1.uniqueitem_id
                   FROM multireadscanbatchcontents m1 join uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.subbatchnumber = gv_subbatchnumber
                    and m1.multireadexception_id is null
                    and (u.rewashtotal > gv_ss_rewashmax)
                ) MERGE_SUBQUERY
          ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
          AND m.subbatchnumber = gv_subbatchnumber
          AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
          WHEN MATCHED THEN
            UPDATE
               SET m.multireadexception_id = 33; -- Item has reached max rewashes
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      begin
        writemultireaddebuglog('Step 6 Find Customer');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id,
                      w.customer_id
                 FROM multireadscanbatchcontents m1,
                      wearer w,
                      weareremployment we,
                      uniqueitemnonpool u
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and we.weareremployment_id = u.weareremployment_id
                  and w.wearer_id = we.wearer_id
                  and m1.poolitemyn='N'
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.UNIQUEITEM_ID)
        WHEN MATCHED THEN
          UPDATE
             SET m.relatedcustomer_id = MERGE_SUBQUERY.customer_id;
      commit;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      begin
        gv_main_code_block := 'Step 7 Select Contents';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        lv_mixedproductsallowed := 'N';
        lv_itemspartlytagged := 'N';

        select sum(case when m.poolitemyn='Y' and m.multireadexception_id is null then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' and m.multireadexception_id is null then 1 else 0 end) number_nonpool_items,
               sum(case when m.multireadexception_id = 1 then 1 else 0 end) number_unknown_items,
               sum(case when m.multireadexception_id > 1 then 1 else 0 end) number_other_rejections,
               count(distinct m.product_id) number_distinct_products,
               count(distinct m.sizedefinition_id) number_distinct_sizes
          into lv_number_pool_items,
               lv_number_nonpool_items,
               lv_number_unknown_items,
               lv_number_other_rejections,
               lv_number_distinct_products,
               lv_number_distinct_sizes
          from multireadscanbatchcontents m
         where m.multireadscanbatch_id = gv_multireadscanbatch_id;

        -- determine if mixed products are allowed:
        if gv_ss_stackchkpersonalmixed = 'Y' and lv_number_nonpool_items > 0 then
          lv_mixedproductsallowed := 'Y';
        end if;

        if lv_mixedproductsallowed = 'N' then
          select count(1)
            into lv_customers_allow_mixed_prod
            from multireadscanbatchcontents m, customer c
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and c.customer_id = m.relatedcustomer_id
             and c.stackcheckmixedproducts = 1
             and m.poolitemyn = 'Y';

          if lv_customers_allow_mixed_prod > 0 then
            lv_mixedproductsallowed := 'Y';
          end if;
        end if;

--- ABS-156248
        if lv_mixedproductsallowed = 'N' and
           (lv_number_distinct_products > 1 or lv_number_distinct_sizes > 1) and
           gv_dbSetting = 'PED' then
          /* if PED and multiple distinct products/sizes then check if the
             stack be accepted as mixed products stack because of substitutes
             algoritm: create list of all product_size combinations of substitions together with orginally
             scanned products and select from this the ones for which the total number of products
             matches with the scanned number of products and for which there is at least 1 originally
             scanned product. If total number of products is lower than the scanned qty it means that
             not all products had a matching substitute, so those are not valid.
             example:
             stack of 5 pieces is scanned and has mixed products:
             3 pcs product X
             2 pcs product Y

             situation A)
             product X and Y are not a subsitute for any product
             then result set (all_options) is
             X 3
             Y 2
             Non of the options reach the scanned total of 5 so not a valid combination

             situation B)
             product X is not a subsitute for any product
             product Y is a subsitute for product X
             then result set (all_options) is
             5 pcs product X
             2 pcs product Y
             The first option reaches the scanned total of 5 so is a valid combination

             situation C)
             product X is not a subsitute for any product
             product Y is a subsitute for product Z
             then result set (all_options) is
             3 pcs product X
             2 pcs product Y
             Non of the options reach the scanned total of 5 so not a valid combination

             situation D)
             product X is not a subsitute for any product
             product Y is a subsitute for product X and also for product Z
             then result set (all_options) is
             5 pcs product X
             2 pcs product Y
             The first option reaches the scanned total of 5 so is a valid combination

             situation E)
             product X is a subsitute for product Z
             product Y is a subsitute for product Z
             then result set (all_options) is
             3 pcs product X
             2 pcs product Y
             There would be total of 5 for Z, but because Z is not a originally scanned product
             in the stack it is not counted as valid
          */
          lv_substituted_product_id := null;
          lv_substituted_size_id := null;

          with possibleproductsizecombinations as
           (select m1.product_id        product_id,
                   m1.sizedefinition_id size_id,
                   count(1)             totalqty
              from multireadscanbatchcontents m1
             where m1.multireadscanbatch_id = gv_multireadscanbatch_id
               and m1.multireadexception_id is null
             group by m1.product_id,
                      m1.sizedefinition_id) -- end possibleproductsizecombinations
          select x.product_id,
                 x.size_id
            into lv_substituted_product_id,
                 lv_substituted_size_id
--          select count(1)
--            into lv_valid_options
            from (select all_options.product_id,
                         all_options.size_id,
                         sum(all_options.totalqty) totalqty
                    from (select pc.destinationproduct_id         product_id,
                                 pcs.destinationsizedefinition_id size_id,
                                 1                                totalqty
                            from multireadscanbatchcontents m1
                            join productconversion pc
                              on pc.sourceproduct_id = m1.product_id
                             and pc.customer_link_id = lv_customer_id_packingnote
                            join productconversionsize pcs
                              on pcs.productconversion_id = pc.productconversion_id
                             and pcs.sourcesizedefinition_id = m1.sizedefinition_id
                            join possibleproductsizecombinations p
                              on p.product_id = pc.destinationproduct_id
                             and p.size_id = pcs.destinationsizedefinition_id
                           where m1.multireadscanbatch_id = gv_multireadscanbatch_id
                             and m1.multireadexception_id is null
                          union all
                          select p.product_id,
                                 p.size_id,
                                 p.totalqty
                            from possibleproductsizecombinations p
                           ) all_options
                   group by all_options.product_id,
                            all_options.size_id
                  having sum(all_options.totalqty) = lv_number_pool_items + lv_number_nonpool_items) x
           where rownum =1;
          if lv_substituted_product_id is not null then
            lv_mixedproductsallowed := 'Y';
          end if;
        end if;
--- end ABS-156248

        select count(1)
          into lv_products_partly_tagged
          from multireadscanbatchcontents m, product p
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and p.product_id = m.product_id
           and p.uhftagged = 1;

        if lv_products_partly_tagged > 0 then
          lv_itemspartlytagged := 'Y';
        end if;

      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

     if gv_ss_auto_assign_unkown_tags = 'Y' then -- HVH ABS-13664
        gv_main_code_block := 'Step 8 Assign Unknown tags';
        --ID code range check and UHFTAGFILTER is done in the (java) program so id codes are correct
        If lv_number_nonpool_items = 0 and -- only for poolitems
           lv_number_unknown_items > 0 and -- only if needed
           lv_number_distinct_products = 1 and -- only if the known ones are all the same product
           lv_number_distinct_sizes = 1 and    -- only if the known ones are all the same size
           lv_number_other_rejections = 0 and  -- no other problems found in stack
           lv_number_unknown_items <= (lv_number_pool_items + lv_number_unknown_items) * (100 - gv_ss_auto_assign_min_percent) / 100 then
          assing_unknown_items;
        end if;
     end if; -- gv_auto_assign_unkown_tags then


     -- pack_check
      begin
        gv_main_code_block := 'Step 9 Determine # distinct products';
        -- count number of items
        writemultireaddebuglog('Determine # distinct products');
        select sum(case
                     when y.myrownr = 1 then
                      nvl(lv_substituted_product_id, y.product_id)
                     else
                      0
                   end) product_id,
               sum(case
                     when y.myrownr = 1 then
                      nvl(lv_substituted_size_id, y.sizedefinition_id)
                     else
                      0
                   end) sizedefinition_id,
               sum(case
                     when y.myrownr = 1 then
                      y.nrofitems
                     else
                      0
                   end) nrofitems_product1,
               sum(case
                     when y.myrownr = 2 then
                      y.nrofitems
                     else
                      0
                   end) nrofitems_product2,
               count(*) nrofdistinctitems
        into lv_stackcheck_stackproduct_id,
             lv_stackcheck_stacksize_id,
             lv_nrofitems_product1,
             lv_nrofitems_product2,
             lv_number_distinct_products
        from
        (select rownum myrownr, x.product_id, x.sizedefinition_id, x.nrofitems
          from (select m.product_id, m.sizedefinition_id, count(*) nrofitems
                  from multireadscanbatchcontents m
                 where m.multireadscanbatch_id = gv_multireadscanbatch_id
--                 and m.multireadexception_id is null  ABS-54172
                   and m.product_id is not null
                 group by m.product_id, m.sizedefinition_id
                 order by count(*) desc) x
         where rownum <= 2) y;
      exception
        when no_data_found then
             lv_stackcheck_stackproduct_id := null;
             lv_stackcheck_stacksize_id    := null;
             lv_nrofitems_product1    := 0;
             lv_nrofitems_product2    := 0;
             lv_number_distinct_products := 0;
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if gv_findpack_YN = 'N' or (gv_findpack_YN = 'Y' and lv_number_distinct_products < 2)
      then  -- it is a stack not a pack
          -- populate variables, will be stored at the end in multireadscanbatch table.
          lv_stackcheck_product_id       := lv_stackcheck_stackproduct_id;
          lv_stackcheck_size_id          := lv_stackcheck_stacksize_id;
          lv_stackcheckpack              := 'N';
          if (lv_nrofitems_product1 = lv_nrofitems_product2 and lv_nrofitems_product1 > 0)
             or lv_stackcheck_stackproduct_id is null
      then lv_stackcheckproductidentified := 'N';
            else lv_stackcheckproductidentified := 'Y';
          end if;
      else
        begin
          gv_main_code_block := 'Step 10 Determine Pack Product';

          writemultireaddebuglog('Determine Pack Product');
          select sum(case
                       when x.myrownr = 1 then
                        x.pack_id
                       else
                        0
                     end) pack_id,
                 sum(case
                       when x.myrownr = 1 then
                        x.dissimilarityfactor
                       else
                        0
                     end) disimilarityfactor_pack1,
                 sum(case
                       when x.myrownr = 2 then
                        x.dissimilarityfactor
                       else
                        0
                     end) disimilarityfactor_pack2,
                 count(*) nr_of_rows
          into lv_stackcheck_packproduct_id,
               lv_disimilarityfactor_pack1,
               lv_disimilarityfactor_pack2,
               lv_nr_of_rows
            from (select rownum myrownr, t.pack_id, t.dissimilarityfactor
                    from v_matching_packs t
                   where t.multireadscanbatch_id = gv_multireadscanbatch_id
                     and rownum <= 2) x;
        exception
          when no_data_found then
               lv_stackcheck_packproduct_id := null;
               lv_disimilarityfactor_pack1 := 0;
               lv_disimilarityfactor_pack2 := 0;
               lv_nr_of_rows               := 0;
            null;
          when others then
           begin
            gv_result := gc_result_ora_error;
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;

        -- situation 1
        if lv_nr_of_rows = 0
         then -- no pack exists with any of the products scanned -> revert to stackproduct
          lv_stackcheck_product_id       := lv_stackcheck_stackproduct_id;
          lv_stackcheck_size_id          := lv_stackcheck_stacksize_id;
          lv_stackcheckpack              := 'N';
          if lv_nrofitems_product1 = lv_nrofitems_product2 and lv_nrofitems_product1 > 0
            then lv_stackcheckproductidentified := 'N';
            else lv_stackcheckproductidentified := 'Y';
          end if;
        end if;

        -- situation 2
        if lv_nr_of_rows = 1 and lv_disimilarityfactor_pack1 = 0
         then -- one single exact matching pack found
          lv_stackcheck_product_id       := lv_stackcheck_packproduct_id;
          lv_stackcheck_size_id          := null;
          lv_stackcheckpack              := 'Y';
          lv_stackcheckproductidentified := 'Y';
        end if;

        -- situation 3
        if lv_nr_of_rows = 1 and lv_disimilarityfactor_pack1 > 0 and lv_disimilarityfactor_pack1 <= 5
         then -- one single almost matching pack found
          lv_stackcheck_product_id       := lv_stackcheck_packproduct_id;
          lv_stackcheck_size_id          := null;
          lv_stackcheckpack              := 'Y';
          lv_stackcheckproductidentified := 'Y';
        end if;

        -- situation 4
        if lv_nr_of_rows = 1 and lv_disimilarityfactor_pack1 > 5
         then -- one single pack found but too different to be likely -> revert to stackproduct
          lv_stackcheck_product_id       := lv_stackcheck_stackproduct_id;
          lv_stackcheck_size_id          := lv_stackcheck_stacksize_id;
          lv_stackcheckpack              := 'N';
          if lv_nrofitems_product1 = lv_nrofitems_product2 and lv_nrofitems_product1 > 0
            then lv_stackcheckproductidentified := 'N';
            else lv_stackcheckproductidentified := 'Y';
          end if;
        end if;

        -- situation 5
        if lv_nr_of_rows = 2 and lv_disimilarityfactor_pack1 = 0  and lv_disimilarityfactor_pack2 = 0
         then -- more than one exact matching pack found
          lv_stackcheck_product_id       := lv_stackcheck_packproduct_id;
          lv_stackcheck_size_id          := null;
          lv_stackcheckpack              := 'Y';
          lv_stackcheckproductidentified := 'N';
        end if;

        -- situation 6
        if lv_nr_of_rows = 2 and lv_disimilarityfactor_pack1 = 0  and lv_disimilarityfactor_pack2 > 0
         then -- one single exact matching pack found, other packs found are different
          lv_stackcheck_product_id       := lv_stackcheck_packproduct_id;
          lv_stackcheck_size_id          := null;
          lv_stackcheckpack              := 'Y';
          lv_stackcheckproductidentified := 'Y';
        end if;

        -- situation 7
        if lv_nr_of_rows = 2 and lv_disimilarityfactor_pack1 = lv_disimilarityfactor_pack2 and
           lv_disimilarityfactor_pack1 > 0 and lv_disimilarityfactor_pack1 <= 5
         then -- multiple almost matching packs found but are equally likely
          lv_stackcheck_product_id       := lv_stackcheck_packproduct_id;
          lv_stackcheck_size_id          := null;
          lv_stackcheckpack              := 'Y';
          lv_stackcheckproductidentified := 'N';
        end if;

        -- situation 8
        if lv_nr_of_rows = 2 and lv_disimilarityfactor_pack1 < lv_disimilarityfactor_pack2 and
           lv_disimilarityfactor_pack1 > 0 and lv_disimilarityfactor_pack1 <= 5
         then -- multiple almost matching packs found but one is more likely
          lv_stackcheck_product_id       := lv_stackcheck_packproduct_id;
          lv_stackcheck_size_id          := null;
          lv_stackcheckpack              := 'Y';
          lv_stackcheckproductidentified := 'Y';
        end if;

        -- situation 9
        if lv_nr_of_rows = 2 and lv_disimilarityfactor_pack1 > 5
         then -- multiple packs found but too different to be likely -> revert to stackproduct
          lv_stackcheck_product_id       := lv_stackcheck_stackproduct_id;
          lv_stackcheck_size_id          := lv_stackcheck_stacksize_id;
          lv_stackcheckpack              := 'N';
          if lv_nrofitems_product1 = lv_nrofitems_product2 and lv_nrofitems_product1 > 0
            then lv_stackcheckproductidentified := 'N';
            else lv_stackcheckproductidentified := 'Y';
          end if;
        end if;

      end if; -- gv_findpack_YN = 'N'

      -- determine related customer of stack part 1
       select min(mb.relatedcustomer_id),
              max(mb.relatedcustomer_id)
         into lv_min_relatedcustomer_id,
              lv_max_relatedcustomer_id
         from multireadscanbatchcontents mb
        where mb.multireadscanbatch_id = gv_multireadscanbatch_id
          and mb.relatedcustomer_id is not null;

       if lv_min_relatedcustomer_id is not null and
           lv_min_relatedcustomer_id = lv_max_relatedcustomer_id
          then lv_relatedcustomer_id_stack := lv_min_relatedcustomer_id;
          else lv_relatedcustomer_id_stack := null;
       end if;

      begin
        if lv_stackcheckpack = 'N' and gv_stacksize = 0 /*auto*/  and lv_stackcheck_product_id is not null
          then
            --ABS-134310 Improvement of stack check multiread regarding bundle quantities
            if lv_relatedcustomer_id_stack is not null then
              select max(plpc.custombundlesize)
                into gv_stacksize
                from productlistpercustomer plpc
               where plpc.customer_id = lv_relatedcustomer_id_stack
                 and plpc.product_id = lv_stackcheck_stackproduct_id
                 and plpc.sizedefinition_id = lv_stackcheck_stacksize_id;
            end if;

            if nvl(gv_stacksize,0) = 0 then
              select max(pps.packingamount)
                into gv_stacksize
                from plantproductsizesettings pps
               where pps.plant_id = gv_plant_id
                 and pps.product_id = lv_stackcheck_stackproduct_id
                 and pps.sizedefinition_id = lv_stackcheck_stacksize_id;
            end if;

            if nvl(gv_stacksize,0) = 0 then
              select max(ps.packingamount)
                into gv_stacksize
                from productsize ps
               where ps.product_id = lv_stackcheck_stackproduct_id
                 and ps.sizedefinition_id = lv_stackcheck_stacksize_id;
            end if;

            if nvl(gv_stacksize,0) = 0 then
              begin
                select p.packingamount
                  into gv_stacksize
                  from product p
                 where p.product_id = lv_stackcheck_stackproduct_id;
              exception
                when no_data_found then
                  gv_stacksize := -1;
              end;
            end if;
        end if;
        if lv_stackcheckpack = 'N' and gv_stacksize = -1 /*no check*/  and lv_stackcheck_product_id is not null
          then
             gv_stacksize := lv_number_pool_items + lv_number_nonpool_items;
        end if;
        if lv_stackcheckpack = 'Y' then
             select trunc(sum(p.amount))
               into gv_stacksize
               from packcontents p
              where p.pack_id = lv_stackcheck_product_id
                and p.uniquelycoded = 'Y';
        end if;

   -- ABS-71968 pool stack flow
   if  lv_number_unknown_items = 0
            and lv_number_other_rejections = 0
--            and  lv_number_distinct_products = 1  HVH/ABS-156248 removed condition
--             and  lv_number_distinct_sizes = 1  HVH/ABS-156248 removed condition
              then

        -- situation 1 : other customer than the one from packingnote
        if gv_packingnote_id > 0 and gv_result = 0 and
           lv_relatedcustomer_id_stack is not null then
            -- it is a stack for 1 related customer that needs to be checked against the selected packingote
             if lv_relatedcustomer_id_stack <> lv_customer_id_packingnote then
               gv_result := 4;
             end if;
        end if;

        -- situation 2 : product/size not ordered on selected packingnote
        if gv_packingnote_id > 0 and gv_result = 0 then
          begin
            select l.tobedeliveredamount
              into lv_ordered_qty
              from packingnoteline l
             where l.packingnote_id = gv_packingnote_id
               and l.product_id = lv_stackcheck_product_id
               and l.sizedefinition_id = lv_stackcheck_size_id;
          exception
             when no_data_found then
              gv_result := 5;
          end;
        end if;

        -- situation 3 : qty packed exceeds ordered qty on selected packingnote, in case of general pool items
        if gv_packingnote_id > 0 and gv_result = 0 then

          -- HVH 08/07/2024 ABS-156248 delete old bundles in case stack was recreated with same items
          gv_code_block := 'Delete Old Bundles';
          delete
            from uhfbundle ub
            where ub.uhfbundle_id in
                (select distinct mbc.uhfbundle_id
                   from multireadscanbatchcontents mbc
                  where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                    and mbc.uhfbundle_id is not null);
          commit;
          -- End HVH 08/07/2024 ABS-156248


          select count(*)
            into lv_nr_of_general_pool_items
            from multireadscanbatchcontents m
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.relatedcustomer_id is null
             and m.multireadexception_id is null;
          if lv_nr_of_general_pool_items > 0 then
            select sum(u.bundlesize)
              into lv_produced_stack_qty
              from uhfbundle u
             where u.packingnote_id = gv_packingnote_id
               and u.product_link_id = lv_stackcheck_product_id
               and u.sizedefinition_link_id = lv_stackcheck_size_id;

            -- if produced_qty previous stacks >= ordered qty
            if lv_produced_stack_qty >= lv_ordered_qty then
              gv_result := 6;
            end if;
          end if;
        end if;

        -- situation 4 : no packingote selected while customer related stack
        if gv_packingnote_id = -1 and gv_result = 0
           and lv_relatedcustomer_id_stack is not null then
           -- check if outstanding packingnote exists for the customer to which the stack is related to
          begin
            select 1
              into lv_pn_found
              from packingnote p
              join distributionpoint dp on dp.distributionpoint_id = p.distributionpoint_id
              join department d on d.department_id = dp.distributionpoint_id
             where d.customer_id = lv_relatedcustomer_id_stack
              and p.deliverydate >= trunc(sysdate) - 3
               and p.status_id in (select s.status_id
                                     from status s
                                    where s.statustype = 'PN'
                                      and s.code in ('10','20')) -- new or in progress
                and exists (select 1 from packingnoteline pnl where pnl.packingnote_id = p.packingnote_id
                                    and pnl.product_id = lv_stackcheck_product_id
                                    and pnl.sizedefinition_id = lv_stackcheck_size_id)
                and rownum < 2;
            gv_result := 7; -- return error code 7 when packingnote found
          exception
             when no_data_found then gv_result := 8;  -- return 8 when not found
          end;
        end if;
    end if;
    -- End ABS-71968 pool stack flow

    -- determine related customer of stack part 2 for cases when multiple customers find the customer with the most items in stack
    if lv_relatedcustomer_id_stack is null and lv_min_relatedcustomer_id is not null then
      begin
        select mbc.relatedcustomer_id
          into lv_relatedcustomer_id_stack
          from multireadscanbatchcontents mbc
         where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
         group by mbc.relatedcustomer_id
         order by count(1) desc FETCH FIRST 1 ROWS ONLY;
      exception
         when no_data_found then null;
      end;
    end if;

   update multireadscanbatch m
       set m.stackcheckproduct_id        = lv_stackcheck_product_id,
           m.stackchecksize_id           = lv_stackcheck_size_id,
           m.stackcheckstacksize         = gv_stacksize,
           m.stackcheckpack              = lv_stackcheckpack,
           m.stackcheckproductidentified = lv_stackcheckproductidentified,
           m.mixedproductsallowed        = lv_mixedproductsallowed,
           m.itemspartlytagged           = lv_itemspartlytagged,
           m.relatedcustomer_id          = lv_relatedcustomer_id_stack
    where m.multireadscanbatch_id = gv_multireadscanbatch_id;
    commit;
  exception
    when others then
     begin
      gv_result := gc_result_ora_error;
      gv_last_error_number  := SQLCODE;
      gv_last_error_message := SQLERRM;
      writemultireaderrorlog;
      return gc_result_ora_error;
    end;
  end;
  return gv_result;
end f_validatestack;


  ----------------------------------------------------------------------------------------------
  function f_validaterewashscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      gv_main_code_block := 'Validate Rewashscan Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.relatedcustomer_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.batchnumber
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                              case when MERGE_SUBQUERY.stay_id = gc_stay_id_in_rewash
                                                    and (MERGE_SUBQUERY.scantimestamp - MERGE_SUBQUERY.lastscandate)*24*60 < gc_ss_rewashscantimeinterval
                                               then 3 -- scanned within time interval
                                               else null
                                              end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.relatedcustomer_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.batchnumber
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                              case when MERGE_SUBQUERY.stay_id = gc_stay_id_in_rewash
                                                    and (MERGE_SUBQUERY.scantimestamp - MERGE_SUBQUERY.lastscandate)*24*60 < gc_ss_rewashscantimeinterval
                                               then 3 -- scanned within time interval
                                               else null
                                              end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

    -- step 2A
      if find_ragged_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 2B
      if find_ragged_by_secondary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 4
      -- Mark all items that are scanned meanwhile with rejection reason
      begin
        writemultireaddebuglog('Step 4 Reject items scanned meanwhile');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 15
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.lastscantimestamp > m.scantimestamp;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      return 0;
   end f_validaterewashscanbatch;


  ----------------------------------------------------------------------------------------------
  function f_validateragscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      gv_main_code_block := 'Validate Ragscan Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.prevstay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    u.relatedcustomer_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.plannedoutstop_id     = MERGE_SUBQUERY.prevstay_id, -- misuse field
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.RELATEDCUSTOMER_ID,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else null
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    u.relatedcustomer_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.RELATEDCUSTOMER_ID,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else null
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

    -- step 2A
      if find_ragged_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 2B
      if find_ragged_by_secondary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 4
      -- Mark all type of merchandize 2 garments with rejection reason
      begin
        writemultireaddebuglog('Step 4 Reject personalized garments');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 6 -- Personalized garments not be to be scanned in rag in batch
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.poolitemyn = 'N';
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      return 0;
   end f_validateragscanbatch;

  ----------------------------------------------------------------------------------------------
  function f_validateonsiteinventbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      gv_main_code_block := 'Validate On-site Inventory Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    (select de.customer_id
                          from distributionpoint di,
                               department de
                         where di.distributionpoint_id = m1.distributionpoint_id
                           and de.department_id = di.department_id) customer_id,
                    u.distributionpoint_id prev_distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif
              WHERE m1.idcode = u.primaryid
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else case when MERGE_SUBQUERY.lastscandate = m.scantimestamp  -- ABS-39293 HVH
                                                then 3 -- scanned within time interval
                                                else null
                                               end
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    (select de.customer_id
                          from distributionpoint di,
                               department de
                         where di.distributionpoint_id = m1.distributionpoint_id
                           and de.department_id = di.department_id) customer_id,
                    u.distributionpoint_id prev_distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else case when MERGE_SUBQUERY.lastscandate = m.scantimestamp  -- ABS-39293 HVH
                                                then 3 -- scanned within time interval
                                                else null
                                               end
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- step 2
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 3
      if gv_garmentassistantbatch
      then
        -- 3a find customer and weareremployment for personalized garments
        writemultireaddebuglog('Step 3a Load weareremployement for personalized garments');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id,
                      w.customer_id,
                      we.distributionpoint_id,
                      unp.weareremployment_id
                 FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemnonpool unp,
                      wearer w, weareremployment we
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and unp.uniqueitem_id = m1.uniqueitem_id
                  and we.weareremployment_id = unp.weareremployment_id
                  and w.wearer_id = we.wearer_id
                  and m1.poolitemyn = 'N'
                  and m1.multireadexception_id is null
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.customer_id = MERGE_SUBQUERY.customer_id,
                 m.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id,
                 m.weareremployment_id = MERGE_SUBQUERY.weareremployment_id;

        -- 3b find customer and cons.point for pool items
        writemultireaddebuglog('Step 3a Load consumptionpoint for pool item');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id,
                      d.customer_id,
                      u.distributionpoint_id
                 FROM multireadscanbatchcontents m1, uniqueitem u, distributionpoint dp, department d
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and dp.distributionpoint_id = u.distributionpoint_id
                  and d.department_id = dp.department_id
                  and m1.poolitemyn = 'Y'
                  and m1.multireadexception_id is null
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.customer_id = MERGE_SUBQUERY.Customer_id,
                 m.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id;
      else -- not gv_garmentassistantbatch
        begin
          -- Mark all type of merchandize 2 garments with rejection reason if not scanned with garment assistant
          writemultireaddebuglog('Step 3 Reject personalized garments');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 6
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.multireadexception_id is null
             and m.poolitemyn = 'N';
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if gv_garmentassistantbatch

      -- step 4
      -- Mark all items that are scanned meanwhile with rejection reason
      begin
        writemultireaddebuglog('Step 4 Reject items scanned meanwhile');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 15
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.lastscantimestamp > m.scantimestamp;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if not gv_garmentassistantbatch
      then -- determine plpc in order to know during processing if onsiteinventorycheck is done
        begin
          writemultireaddebuglog('Step 5 Find Plpc pool items');
          update multireadscanbatchcontents m
             set m.plpc_id= (select min(p.productlistpercustomer_id)
                               from productlistpercustomer p
                              where p.customer_id = m.customer_id
                                and p.product_id = m.product_id
                                and p.sizedefinition_id = m.sizedefinition_id
                                and p.dateactive <= trunc(sysdate)
                                and p.dateinactive >= trunc(sysdate))
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.poolitemyn='Y'
             and m.multireadexception_id is null;
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if not gv_garmentassistantbatch

      return 0;
   end f_validateonsiteinventbatch;

 ----------------------------------------------------------------------------------------------
  function f_validateonsitelockerscan return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   --------------------------
   begin
      gv_main_code_block := 'Validate On-site Locker Scan Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    (select de.customer_id
                          from distributionpoint di,
                               department de
                         where di.distributionpoint_id = m1.distributionpoint_id
                           and de.department_id = di.department_id) customer_id,
                    u.distributionpoint_id prev_distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif
              WHERE m1.idcode = u.primaryid
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else case when MERGE_SUBQUERY.lastscandate = m.scantimestamp  -- ABS-39293 HVH
                                                then 3 -- scanned within time interval
                                                else null
                                               end
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    (select de.customer_id
                          from distributionpoint di,
                               department de
                         where di.distributionpoint_id = m1.distributionpoint_id
                           and de.department_id = di.department_id) customer_id,
                    u.distributionpoint_id prev_distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else case when MERGE_SUBQUERY.lastscandate = m.scantimestamp  -- ABS-39293 HVH
                                                then 3 -- scanned within time interval
                                                else null
                                               end
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- Step 1 c Remove duplicate multireadscanbatch_id, subbatchnumber, uniqueitem_id values!
      delete from multireadscanbatchcontents x
      where  exists (select 1
              from   (select t.multireadscanbatch_id, t.subbatchnumber, t.uniqueitem_id,
                              min(t.idcode) min_idcode
                       from   multireadscanbatchcontents t
                       where  t.uniqueitem_id is not null
                       and    t.multireadscanbatch_id = gv_multireadscanbatch_id
                       and    t.subbatchnumber = gv_subbatchnumber
                       group  by t.multireadscanbatch_id, t.subbatchnumber, t.uniqueitem_id
                       having count(1) > 1) y
              where  y.multireadscanbatch_id = x.multireadscanbatch_id
              and    y.subbatchnumber = x.subbatchnumber
              and    y.uniqueitem_id = x.uniqueitem_id
              and    y.min_idcode = x.idcode
              and    y.multireadscanbatch_id = gv_multireadscanbatch_id
              and    y.subbatchnumber = gv_subbatchnumber);


      -- step 2
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- 3a find customer and weareremployment for personalized garments
      writemultireaddebuglog('Step 3a Load weareremployement for personalized garments');
      MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.uniqueitem_id,
                    w.customer_id,
                    we.distributionpoint_id,
                    unp.weareremployment_id
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemnonpool unp,
                    wearer w, weareremployment we
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and u.uniqueitem_id = m1.uniqueitem_id
                and unp.uniqueitem_id = m1.uniqueitem_id
                and we.weareremployment_id = unp.weareremployment_id
                and w.wearer_id = we.wearer_id
                and m1.poolitemyn = 'N'
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.customer_id = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id,
               m.weareremployment_id = MERGE_SUBQUERY.weareremployment_id;

      -- step 4
      -- Mark all items that are scanned meanwhile with rejection reason
      begin
        writemultireaddebuglog('Step 4 Reject items scanned meanwhile');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 15
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.lastscantimestamp > m.scantimestamp;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      return 0;
   end f_validateonsitelockerscan;

  ----------------------------------------------------------------------------------------------
  function f_validatereceivescanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_nr_not_outscanned_items    number;
   lv_dip                        number;

   function Find_by_primary_ID return number is
   -- Try to find ID Codes in database by PRIMARY ID
   -- No BU filter is needed because chip numbers are supposed to be overall unique.
   begin
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.lastdeliverynotenumber,
                    m1.scantimestamp,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
                and m1.uniqueitem_id is null -- Added for ABS-46769
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.Stay_Id=gc_stay_id_onsite_inv
                                             then 12 -- already scanned
                                             else
                                                case when (gc_ss_shipmentcheckperdelnote = 1 AND
                                                          MERGE_SUBQUERY.Stay_Id <> gc_stay_id_at_customer) OR
                                                          (gc_ss_shipmentcheckperdelnote = 0 AND
                                                             (MERGE_SUBQUERY.poolitem <> 1 AND
                                                              MERGE_SUBQUERY.Stay_Id <> gc_stay_id_at_customer) OR
                                                             (MERGE_SUBQUERY.poolitem = 1 AND
                                                              MERGE_SUBQUERY.distributionpoint_id is null))
                                                 then 16 -- not scanned out
                                                 else null
                                                end
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastdeliverynotenumber= MERGE_SUBQUERY.Lastdeliverynotenumber,
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      return 0;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
   end; -- Find_by_primary_ID

   --------------------------
   begin
      gv_main_code_block := 'Validate Receive at Customer Batch';
      gv_items_found := 0;
      -- step 1A
      if Find_by_primary_ID <> 0 then
        return gc_result_ora_error;
      end if;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.lastdeliverynotenumber,
                    m1.scantimestamp,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.Stay_Id=gc_stay_id_onsite_inv
                                             then 12 -- already scanned
                                             else
                                                case when MERGE_SUBQUERY.distributionpoint_id is null OR
                                                          (MERGE_SUBQUERY.lastdeliverynotenumber is null AND
                                                           gc_ss_shipmentcheckperdelnote = 1)
                                                 then 16 -- not scanned out
                                                 else null
                                                end
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastdeliverynotenumber= MERGE_SUBQUERY.Lastdeliverynotenumber,
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- 21481 --
      if gc_ss_uhfoutscanbundleperc > 0 and gs_ss_receivescanusvirtbundle = 1 then  -- add virtual scans only when % > 0
        if add_virtual_scans <> 0 then  -- if virtual scans added by function add_virtual_scans
          if Find_by_primary_ID <> 0 then  -- then redo Find_by_primary_ID for the added virtual scans
            return gc_result_ora_error;
          end if;
       end if;  -- add_virtual_scans <> 0
      end if;  -- gc_ss_uhfoutscanbundleperc > 0
      -- End 21481 --

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

-- START CHANGE ABS-27596
      if gc_ss_shipmentcheckperdelnote=0 -- do not check and try to link to dip
       then
        -- handle rows with exception reason_id 16 -- not scanned out, differently
        -- so that they are no longer exceptions
        -- For garments: just clear the exception
        begin
          writemultireaddebuglog('Step 4a Clear exception for not outscanned garments');
          update multireadscanbatchcontents m
             set m.multireadexception_id = null -- clear exception
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.uniqueitem_id is not null
             and m.multireadexception_id = 16  -- not scanned out
             and m.poolitemyn = 'N';  -- garments only
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;

        -- For pool items: only clear the exception when a distribution point could be
        -- dermined. Also include previous subbatches
        select count(*)
          into lv_nr_not_outscanned_items
          from multireadscanbatchcontents m
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber <= gv_subbatchnumber  -- also include previous subbatches
           and m.uniqueitem_id is not null
           and m.distributionpoint_id is null
           and m.multireadexception_id = 16  -- not scanned out
           and m.poolitemyn = 'Y';  -- pool items only

        if lv_nr_not_outscanned_items > 0 then
          lv_dip := find_distrpnt_notoutscand_itms;
          if lv_dip is not null
           then
            begin
            writemultireaddebuglog('Step 4b Clear exception for not outscanned pool items');
            update multireadscanbatchcontents m
               set m.multireadexception_id = null, -- clear exception
                   m.distributionpoint_id = nvl(m.distributionpoint_id,lv_dip), -- populate distribution point with found value when null
                   m.lastoutscandate = m.scantimestamp
             where m.multireadscanbatch_id = gv_multireadscanbatch_id
               and m.subbatchnumber <= gv_subbatchnumber  -- also include previous subbatches
               and m.uniqueitem_id is not null
               and m.multireadexception_id = 16  -- not scanned out
               and m.poolitemyn = 'Y';  -- pool items only
            commit;
            exception
              when no_data_found then
                null;
              when others then
               begin
                gv_last_error_number  := SQLCODE;
                gv_last_error_message := SQLERRM;
                ROLLBACK;
                writemultireaderrorlog;
               return null;
              end;
            end;
           else -- Write warning in abslog that dip could not be determined.
             gv_last_error_number := -2;
             gv_last_error_message := 'Consumption point could not be determined';
             writemultireadwarninglog;
          end if; -- lv_dip is not null

        end if; -- lv_nr_not_outscanned_items > 0 then

      end if; -- if gc_ss_shipmentcheckperdelnote=0
-- END CHANGE ABS-27596
      return 0;
   end f_validatereceivescanbatch;


  ----------------------------------------------------------------------------------------------
  function f_validatesendscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_nr_not_outscanned_items    number;
   lv_dip                        number;
   --------------------------
   begin
      gv_main_code_block := 'Validate Send to Laundry Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.lastdeliverynotenumber,
                    m1.scantimestamp,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.Stay_Id=gc_stay_id_sent_to_laundry
                                             then 12 -- already scanned
                                             else
                                                case when (gc_ss_shipmentcheckperdelnote = 1 AND
                                                          MERGE_SUBQUERY.Stay_Id <> gc_stay_id_onsite_inv) OR
                                                          (gc_ss_shipmentcheckperdelnote = 0 AND
                                                             (MERGE_SUBQUERY.poolitem <> 1 AND
                                                              MERGE_SUBQUERY.Stay_Id <> gc_stay_id_onsite_inv) OR
                                                             (MERGE_SUBQUERY.poolitem = 1 AND
                                                              MERGE_SUBQUERY.distributionpoint_id is null))
                                                 then 16 -- not scanned out
                                                 else null
                                                end
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastdeliverynotenumber= MERGE_SUBQUERY.Lastdeliverynotenumber,
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.lastdeliverynotenumber,
                    m1.scantimestamp,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.Stay_Id=gc_stay_id_sent_to_laundry
                                             then 12 -- already scanned
                                             else
                                                case when MERGE_SUBQUERY.distributionpoint_id is null OR
                                                          (MERGE_SUBQUERY.lastdeliverynotenumber is null AND
                                                           gc_ss_shipmentcheckperdelnote = 1)
                                                 then 16 -- not scanned out
                                                 else null
                                                end
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastdeliverynotenumber= MERGE_SUBQUERY.Lastdeliverynotenumber,
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

-- START CHANGE ABS-27596
      if gc_ss_shipmentcheckperdelnote=0 -- do not check and try to link to dip
       then
        -- handle rows with exception reason_id 16 -- not scanned out, differently
        -- so that they are no longer exceptions
        -- For garments: just clear the exception
        begin
          writemultireaddebuglog('Step 4a Clear exception for not outscanned garments');
          update multireadscanbatchcontents m
             set m.multireadexception_id = null -- clear exception
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.uniqueitem_id is not null
             and m.multireadexception_id = 16  -- not scanned out
             and m.poolitemyn = 'N';  -- garments only
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;

        -- For pool items: only clear the exception when a distribution point could be
        -- dermined. Also include previous subbatches
        select count(*)
          into lv_nr_not_outscanned_items
          from multireadscanbatchcontents m
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber <= gv_subbatchnumber  -- also include previous subbatches
           and m.uniqueitem_id is not null
           and m.distributionpoint_id is null
           and m.multireadexception_id = 16  -- not scanned out
           and m.poolitemyn = 'Y';  -- pool items only

        if lv_nr_not_outscanned_items > 0 then
          lv_dip := find_distrpnt_notoutscand_itms;
          if lv_dip is not null
           then
            begin
            writemultireaddebuglog('Step 4b Clear exception for not outscanned pool items');
            update multireadscanbatchcontents m
               set m.multireadexception_id = null, -- clear exception
                   m.distributionpoint_id = nvl(m.distributionpoint_id,lv_dip), -- populate distribution point with found value when null
                   m.lastoutscandate = m.scantimestamp
             where m.multireadscanbatch_id = gv_multireadscanbatch_id
               and m.subbatchnumber <= gv_subbatchnumber  -- also include previous subbatches
               and m.uniqueitem_id is not null
               and m.multireadexception_id = 16  -- not scanned out
               and m.poolitemyn = 'Y';  -- pool items only
            commit;
            exception
              when no_data_found then
                null;
              when others then
               begin
                gv_last_error_number  := SQLCODE;
                gv_last_error_message := SQLERRM;
                ROLLBACK;
                writemultireaderrorlog;
               return null;
              end;
            end;
           else -- Write warning in abslog that dip could not be determined.
             gv_last_error_number := -2;
             gv_last_error_message := 'Consumption point could not be determined';
             writemultireadwarninglog;
          end if; -- lv_dip is not null

        end if; -- lv_nr_not_outscanned_items > 0 then

      end if; -- if gc_ss_shipmentcheckperdelnote=0
-- END CHANGE ABS-27596

      return 0;
   end f_validatesendscanbatch;

  ----------------------------------------------------------------------------------------------
  function f_validatesoilingdscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   --------------------------
   begin
      gv_main_code_block := 'Validate Soil in GD Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.lastdeliverynotenumber,
                    m1.scantimestamp,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.Stay_Id=gc_stay_id_soil_in_gd
                                             then 12 -- already scanned
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastdeliverynotenumber= MERGE_SUBQUERY.Lastdeliverynotenumber,
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.lastdeliverynotenumber,
                    m1.scantimestamp,
                    u.uhfbundle_id,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
               m.multireadexception_id = case when  MERGE_SUBQUERY.status_id in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then
                                            case when MERGE_SUBQUERY.Stay_Id=gc_stay_id_soil_in_gd
                                             then 12 -- already scanned
                                             else null
                                            end
                                          else 2 -- not in circ
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastdeliverynotenumber= MERGE_SUBQUERY.Lastdeliverynotenumber,
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- step 3
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 3 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      return 0;
   end f_validatesoilingdscanbatch;

  ----------------------------------------------------------------------------------------------
  function f_validatecleanreturnbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      gv_main_code_block := 'Validate Clean Return Batch';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.relatedcustomer_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.batchnumber
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.idcode = u.primaryid
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
               m.multireadexception_id = case
                                          when (MERGE_SUBQUERY.status_id = gc_status_id_ragged)
                                            then 4
                                          when (MERGE_SUBQUERY.poolitem <> 1)
                                            then 6
                                          when (MERGE_SUBQUERY.stay_id = gc_stay_id_inscan_cleanreturn)
                                            then 32
                                          when (MERGE_SUBQUERY.distributionpoint_id is null)
                                            then 13
                                          else null
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.relatedcustomer_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    u.distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.unrelatedloan_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate,
                    u.batchnumber
               FROM multireadscanbatchcontents m1, uniqueitem u, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
               m.multireadexception_id = case
                                          when (MERGE_SUBQUERY.status_id = gc_status_id_ragged)
                                            then 4
                                          when (MERGE_SUBQUERY.poolitem <> 1)
                                            then 6
                                          when (MERGE_SUBQUERY.stay_id = gc_stay_id_inscan_cleanreturn)
                                            then 32
                                          when (MERGE_SUBQUERY.distributionpoint_id is null)
                                            then 13
                                          else null
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate,
               m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- step 2
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 3
      -- Mark all items that are scanned meanwhile with rejection reason
      begin
        writemultireaddebuglog('Step 3 Reject items scanned meanwhile');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 15
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.lastscantimestamp > m.scantimestamp;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      return 0;
   end f_validatecleanreturnbatch;

  -----------------------------------------------------------------------------------------
  function f_processinscanbatch(fp_called_by_inscan_YN in varchar2,
                                fp_transactiontypeid   in number,
                                fp_exchangecart_id     in number) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;
   lv_number_orpack_items   number := 0;
   lv_number_assigned_items number := 0;
   lv_number_assigned_items_deliv     number := 0;
   lv_number_ragged_items   number := 0;
   lv_number_loan_items     number := 0;
   lv_year number(4);
   lv_week number(2);

   ---------------------------------------------
   procedure retrieve_main_item_info is
   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    -- ABS-90735 for poolitems with stay in laundry outside hour interval prevent
                    -- that delivery variations are created by making customer,dip,prev_dip and delpnt null
                    case
                      when m1.stay_id in (gc_stay_id_in_laundry, gc_stay_id_reject) and
                           m1.poolitemyn = 'Y' then
                       null
                      else
                    nvl(--nvl(u.relatedcustomer_id,  -- HVH 24/02/2015 removed related customer
                       (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = u.distributionpoint_id
                           and de1.department_id = di1.department_id), --),
                        (select de2.customer_id
                           from distributionpoint di2,
                                department de2
                          where di2.distributionpoint_id = u.lastdistributionpoint_link_id
                            and de2.department_id = di2.department_id))
                    end customer_id,
                    case
                      when m1.stay_id in (gc_stay_id_in_laundry, gc_stay_id_reject) and
                           m1.poolitemyn = 'Y' then
                       null
                      else
                       u.distributionpoint_id
                    end distributionpoint_id,
                    u.lastdistributionpoint_link_id,
                    case
                      when m1.stay_id in (gc_stay_id_in_laundry, gc_stay_id_reject) and
                           m1.poolitemyn = 'Y' then
                       null
                      else
                       (select dp.deliverypoint_id
                          from distributionpoint dp
                         where dp.distributionpoint_id = u.distributionpoint_id)
                    end deliverypoint_id,-- end change for ABS-90735
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;

    begin
    -- added step 1b for ABS-55410
    -- When customer related pool items are not outscanned then still you can know the
    -- department/conspoint in case the customer only has 1 active cons.point in order to create delivery variations
    -- of course can only be done when the items cannot be send to any other customer
    writemultireaddebuglog('Retrieve main item info step 1b cust related pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    m1.relatedcustomer_id customer_id,
                    dp.distributionpoint_id,
                    dp.deliverypoint_id
               FROM multireadscanbatchcontents m1, customer c,
                    department d, distributionpoint dp
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and c.customer_id = m1.relatedcustomer_id
                and d.customer_id = m1.relatedcustomer_id
                and dp.department_id = d.department_id
                and d.active = 'Y'
                and dp.active = 'Y'
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                and m1.distributionpoint_id is null -- not processed by query above
                and m1.relatedcustomer_id is not null -- only for customer related items
                and c.customer_id = m1.relatedcustomer_id  -- only if related customer is not billto/master/common/other cust
                and c.customerrelated = 1
                and not exists (select c2.customer_id from customer c2
                                where c2.debtor_id = m1.relatedcustomer_id
                                  and c2.customer_id <> m1.relatedcustomer_id)
                and not exists (select c3.customer_id from customer c3
                                where c3.masteraccount_id = m1.relatedcustomer_id
                                  and c3.customer_id <> m1.relatedcustomer_id)
                and not exists (select c4.customer_id from customer c4
                                where c4.commoncustomer_id = m1.relatedcustomer_id
                                  and c4.customer_id <> m1.relatedcustomer_id)
                and not exists (select c5.customer_id from customer c5
                                where c5.othercustomer_id = m1.relatedcustomer_id
                                  and c5.customer_id <> m1.relatedcustomer_id)
                and (select count(1)
                       from distributionpoint dp,
                            department de
                      where dp.department_id = de.department_id
                        and de.customer_id = m1.relatedcustomer_id
                        and dp.active = 'Y'
                        and de.active = 'Y') = 1  -- exactly 1 active cons.point
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id;
    exception
      when no_data_found then
        null;
    end;

   end if; -- step 1 pool items
   -------------
   if lv_number_nonpool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1c nonpool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    w.customer_id,
                    we.weareremployment_id,
                    we.distributionpoint_id,
                    case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select g.deliverypoint_id
                                    from garmentdispenser g
                                   where g.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u,
                    uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                    weareremployment we, wearer w
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.uniqueitem_id = unp.uniqueitem_id
                and we.weareremployment_id = unp.weareremployment_id
                and w.wearer_id = we.wearer_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                --and m1.multireadexception_id is null   --removed so that for rejected scans wearer is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;

    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 personalized garments (non pool)
   if fp_exchangecart_id is null then
     begin
       lv_year := null;
       lv_week := null;
     end;
   else
   begin
     --Determine the last ChippingRate.Year, ChippingRate.Week
     --selecting the Max(ChippingRate_ID) for the current BusinessUnit
     select max(cr.year), max(cr.week)
     into   lv_year, lv_week
     from   chippingrate cr
     where  cr.businessunit_id = gv_businessunit_id
     and    cr.chippingrate_id =
            (select max(crx.chippingrate_id)
              from   chippingrate crx
              where  crx.businessunit_id = cr.businessunit_id);
   exception
     when no_data_found then
       lv_year := null;
       lv_week := null;
   end;
   end if;
   end retrieve_main_item_info; -- retrieve_main_item_info

   ---------------------------------------------
   procedure undo_rags is
   begin
    begin
    writemultireaddebuglog('Undo Rags - Insert UniqueItem');
    insert into uniqueitem
             (uniqueitem_id,
              primaryid,
              idcodesequencenumber,
              statuschangedate,
              staychangedate,
              lastinscandate,
              lastoutscandate,
              lastscandate,
              iteminfoupdatedate,
              washestotal,
              repairstotal,
              rewashtotal,
              customerowned,
              businessunit_id,
              status_id,
              prevstatus_id,
              prevstay_id,
              stay_id,
              product_id,
              sizedefinition_id,
              finishingmethod_id,
              relatedcustomer_id,
              distributionpoint_id,
              lastdistributionpoint_link_id,
              systemuser_id,
              timestamp,
              planneddeliverydate,
              poolitem,
              deliveryfromstock,
              startrentfrom,
              unrelatedloan_id,
              residualvalue,
              replacementprice,
              residualvalueamount,
              activestocklocation_id,
              leaseweeks,
              lastweareremployment_link_id,
              lastsqleasedate
            )
    select r.raggeditem_id,
           r.primaryid,
           1, -- idcode sequence#
           mbc.scantimestamp, -- status change date
           mbc.scantimestamp, -- stay change date
           mbc.scantimestamp, --lastinscandate
           null, --lastoutscandate
           mbc.scantimestamp, --lastscandate
           trunc(mbc.scantimestamp), --iteminfoupdatedate
           r.washestotal,
           r.repairstotal,
           r.rewashtotal,
           r.customerowned,  --customerowned,
           r.businessunit_id,
           gc_status_id_in_circ,   -- status_id
           gc_status_id_ragged,    -- prevstatus_id
           gc_stay_id_at_customer, -- prevstay_id
           gc_stay_id_in_laundry,  -- stay_id
           r.product_link_id,
           r.sizedefinition_link_id,
           coalesce(r.finishingmethod_id,
             (select wi.finishingmethod_id
              from wearerinventory wi
              where wi.weareremployment_id = r.weareremployment_link_id
              and wi.product_id = r.product_link_id
              and wi.sizedefinition_id = r.sizedefinition_link_id ),
             (select min(plpd.finishingmethod_id)
              from productlistperdistribpoint plpd
              where plpd.distributionpoint_id = nvl(r.distributionpoint_link_id, r.lastdistributionpoint_link_id)
              and plpd.product_id = r.product_link_id
              and plpd.sizedefinition_id = r.sizedefinition_link_id),
             (select min(pf.finishingmethod_id)
              from productfinishingmethod pf
              where pf.product_id = r.product_link_id)),
           r.relatedcustomerlink_id, --   w.customer_id,           --r.relatedcustomerlink_id
           r.distributionpoint_link_id,
           r.lastdistributionpoint_link_id,
           gv_systemuser_id,
           sysdate,
           null, -- planneddeliverydate will be determined later
           r.poolitem,
           'N',  -- deliveryfromstock
           0,    -- startrentfrom,
           null, -- unrelatedloan_id
           0,    -- residualvalue
           0, -- replacementprice
           0, --residualvalueamount,
           null, --activestocklocation_id,
           null, --leaseweeks,
           r.lastweareremployment_link_id, --lastweareremployment_link_id,
           null --lastsqleasedate
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           raggeditem                 r
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and r.raggeditem_id = mbc.uniqueitem_id
       and mbc.status_id = gc_status_id_ragged -- only ragged items
       and mbc.multireadexception_id is null; -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Insert UniqueItemFixedInfo');
    insert into uniqueitemfixedinfo
             (uniqueitem_id,
              purchasedate,
              lastonstockdate,
              firstissuedate,
              lastissuedate,
              numberofissues,
              enddatefullrent,
              daysincircprevissue,
              daysinstockprevious,
              purchaseprice,
              remark,
              qualitygrade_id,
              supplier_id,
              currency_id,
              issuedbyworkorder_id,
              reasoncode_id,
              systemuser_id,
              timestamp,
              stockroomlocation_id,
              temporaryid,
              losschargedate,
              losschargeinvoiceline_id,
              wearerinventorycredit_id,
              rewashemployee_id,
              purchaseorderline_id,
              supplierdelnotenumber
            )
    select r.raggeditem_id,
           r.purchasedate,
           r.lastonstockdate,
           r.firstissuedate,
           r.lastissuedate,
           r.numberofissues,
           trunc(sysdate), -- enddatefullrent
           case when (r.daysincirculation - (r.lastissuedate - trunc(r.timestamp))) > 0
            then r.daysincirculation - (r.lastissuedate - trunc(r.timestamp))
            else 0
           end, -- daysincircprevissue,
           r.daysinstock,
           r.purchaseprice,
           null, -- remark
           r.qualitygrade_id,
           r.supplier_id,
           s.currency_id,
           null, -- issuedbyworkorder_id
           r.reasoncode_id,
           gv_systemuser_id,
           sysdate,
           null, -- stockroomlocation_id
           'N' temporaryid,
           null, -- losschargedate
           0, -- r.losschargeinvoiceline_id
           r.wearerinventorycredit_id,
           null, --- rewashemployee_id,
           r.purchaseorderline_id,
           r.supplierdelnotenumber
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           raggeditem                 r,
           supplier                   s
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and r.raggeditem_id = mbc.uniqueitem_id
       and s.supplier_id = r.supplier_id
       and mbc.status_id = gc_status_id_ragged -- only ragged items
       and mbc.multireadexception_id is null;   -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Insert UniqueItemNonPool');
    insert into uniqueitemnonpool
             (uniqueitem_id,
              garmentsequencenumber,
              weareremployment_id,
              washesthisissue,
              repairsthisissue,
              rewashthisissue,
              freeextragarment,
              enddatefreeextra,
              systemuser_id,
              timestamp,
              wearerinventory_id,
              replacementworkorderline_id,
              depositstocklocation,
              originalweareremployment_id,
              originalwearerinventory_id,
              moveddate,
              chargedforloss
            )
    select r.raggeditem_id,
           nvl((select max(unp.garmentsequencenumber)
                  from uniqueitemnonpool unp
                 where unp.wearerinventory_id=wi.wearerinventory_id),0)
           +
           nvl((select max(nu.sequencenumber)
                  from nonuniqueitem nu
                 where nu.wearerinventory_id=wi.wearerinventory_id),0)
           +1, -- garmentsequencenumber,
           r.weareremployment_link_id,
           0, -- washesthisissue
           0, -- repairsthisissue
           0, -- rewashthisissue
           'N', -- freeextragarment
           null, -- enddatefreeextra
           gv_systemuser_id,
           sysdate,
           wi.wearerinventory_id,
           null, -- replacementworkorderline_id,
           null, -- depositstocklocation,
           null, -- originalweareremployment_id,
           null, -- originalwearerinventory_id,
           null, -- moveddate,
           'N' -- chargedforloss
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           raggeditem                 r,
           wearerinventory            wi
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and r.raggeditem_id = mbc.uniqueitem_id
       and wi.weareremployment_id = r.weareremployment_link_id
       and wi.product_id = r.product_link_id
       and wi.sizedefinition_id = r.sizedefinition_link_id
       and mbc.status_id = gc_status_id_ragged -- only ragged items
       and mbc.multireadexception_id is null;   -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Insert SecondaryID');
    insert into secondaryuniqueitem
             (uniqueitem_id,
              businessunit_id,
              secondaryid,
              systemuser_id,
              timestamp)
    select r.raggeditem_id,
           r.businessunit_id,
           r.secondaryid,
           gv_systemuser_id,
           sysdate
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           raggeditem                 r
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and r.raggeditem_id = mbc.uniqueitem_id
       and r.secondaryid is not null            -- only those ragged items that have a secondary ID
       and mbc.status_id = gc_status_id_ragged  -- only ragged items
       and mbc.multireadexception_id is null;   -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Insert UniqueItemModification');
    insert into uniqueitemmodification
             (uniqueitem_id,
              modification_id,
              sequencenumber,
              systemuser_id,
              timestamp)
    select r.raggeditem_id,
           wim.modification_id,
           wim.sequencenumber,
           gv_systemuser_id,
           sysdate
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           raggeditem                 r,
           wearerinventory            wi,
           wearerinventorymodification wim
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and r.raggeditem_id = mbc.uniqueitem_id
       and wi.weareremployment_id = r.weareremployment_link_id
       and wi.product_id = r.product_link_id
       and wi.sizedefinition_id = r.sizedefinition_link_id
       and wim.wearerinventory_id = wi.wearerinventory_id
       and mbc.status_id = gc_status_id_ragged  -- only ragged items
       and mbc.multireadexception_id is null;   -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Update UniqueItemLink');
    update uniqueitem_link uil
           set uil.uniqueitem_id = uil.raggeditem_id,
               uil.raggeditem_id = null,
               uil.systemuser_id = gv_systemuser_id,
               uil.timestamp = sysdate
         where uil.raggeditem_id in (
              select r.raggeditem_id
                from multireadscanbatch         mb,
                     multireadscanbatchcontents mbc,
                     raggeditem                 r
               where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                 and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
                 and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                 and r.raggeditem_id = mbc.uniqueitem_id
                 and mbc.status_id = gc_status_id_ragged  -- only ragged items
                 and mbc.multireadexception_id is null);   -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Update CircInv');
    MERGE INTO wearerinventory winv
      USING (SELECT wi.wearerinventory_id,
                    count(1) qty
               from multireadscanbatch         mb,
                    multireadscanbatchcontents mbc,
                    raggeditem                 r,
                    wearerinventory            wi
              where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
                and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and r.raggeditem_id = mbc.uniqueitem_id
                and wi.weareremployment_id = r.weareremployment_link_id
                and wi.product_id = r.product_link_id
                and wi.sizedefinition_id = r.sizedefinition_link_id
                and mbc.status_id = gc_status_id_ragged -- only ragged items
                and mbc.multireadexception_id is null   -- only when no exception, so that unrag is allowed
           group by wi.wearerinventory_id
            ) MERGE_SUBQUERY
      ON (winv.wearerinventory_id = MERGE_SUBQUERY.wearerinventory_id)
      WHEN MATCHED THEN
        UPDATE
           SET winv.circinventory = winv.circinventory + MERGE_SUBQUERY.qty,
               winv.systemuser_id = gv_systemuser_id,
               winv.timestamp = sysdate;
    --
    writemultireaddebuglog('Undo Rags - Create GD transaction');
    insert into gdtransaction
             (gdtransaction_id,
              customer_link_id,
              gdtransctiontype,
              creationdate,
              exportdate,
              acceptdate,
              status_id,
              garmentdispensercode,
              wearernumber,
              wearername,
              wearerdateactive,
              departmentnumber,
              cardnumber,
              sex,
              functioncode,
              wearerdateinactive,
              primaryid,
              lastissuedate,
              productcode,
              sizecode,
              gradecode,
              numberofwashings,
              systemuser_id,
              timestamp,
              businessunit_id,
              changesperweek,
              personalizeditem,
              credit,
              wearerfirstname,
              dummyforpool,
              secondaryid,
              old_adminnumber,
              old_gdcode,
              adminnr
            )
    select seq_gdtransaction.nextval, --  gdtransaction_id
           w.customer_id,
           20,     -- gdtransctiontype
           sysdate, -- creationdate
           null,   -- exportdate
           null,   -- acceptdate
           (select s.status_id from status s where s.statustype='GD' and s.code='10'), -- status_id
           gd.code, -- garmentdispensercode
           w.wearernumber,
           w.fullname, -- wearername
           null, -- wearerdateactive
           0, --departmentnumber
           0, --cardnumber
           null, --sex
           null, -- functioncode
           null, -- wearerdateinactive
           r.primaryid,
           r.lastissuedate,
           p.code, -- productcode
           sd.code, -- sizecode
           q.code, -- gradecode
           r.washestotal,
           gv_systemuser_id,
           sysdate,
           r.businessunit_id,
           0, -- changesperweek,
           wi.personalizedgarment, -- personalizeditem
           0, -- credit
           null, -- wearerfirstname
           w.dummyforpool,
           r.secondaryid,
           null, -- old_adminnumber
           null, -- old_gdcode
           null  -- adminnr
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           raggeditem                 r,
           weareremployment           we,
           wearer                     w,
           wearerinventory            wi,
           garmentdispenser           gd,
           product                    p,
           sizedefinition             sd,
           qualitygrade               q
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and r.raggeditem_id = mbc.uniqueitem_id
       and we.weareremployment_id = r.weareremployment_link_id
       and we.garmentdispenser_id is not null   -- only for wearer employments linked to a dispenser
       and w.wearer_id = we.wearer_id
       and gd.garmentdispenser_id = we.garmentdispenser_id
       and wi.weareremployment_id = r.weareremployment_link_id
       and wi.product_id = r.product_link_id
       and wi.sizedefinition_id = r.sizedefinition_link_id
       and p.product_id = r.product_link_id
       and sd.sizedefinition_id = r.sizedefinition_link_id
       and q.qualitygrade_id = r.qualitygrade_id
       and mbc.status_id = gc_status_id_ragged  -- only ragged items
       and mbc.multireadexception_id is null;   -- only when no exception, so that unrag is allowed
    --
    writemultireaddebuglog('Undo Rags - Remove from RaggedItem');
    delete from raggeditem ri
         where ri.raggeditem_id in (
                select r.raggeditem_id
                  from multireadscanbatch         mb,
                       multireadscanbatchcontents mbc,
                       raggeditem                 r
                 where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                   and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
                   and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                   and r.raggeditem_id = mbc.uniqueitem_id
                   and mbc.status_id = gc_status_id_ragged  -- only ragged items
                   and mbc.multireadexception_id is null);   -- only when no exception, so that unrag is allowed
    --
    commit;
    exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
        end;
    end;
   end; -- undo_rags

   ---------------------------------------------
   procedure decrease_onsite_inventory is
   begin
    begin
    writemultireaddebuglog('Decrease onsite inventory');
    MERGE INTO onsiteinventoryadjustment o
      USING ( SELECT /*+ index(m1 XIE1MULTIREADSCANCONTENTBATCH) index(p XAK2PRODUCTLISTPERDISTRIBPOINT) index(plpc XPKPRODUCTLISTPERCUSTOMER) */
                    p.productlistperdistribpoint_id,
                    5 origin, trunc(sysdate) inventorydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1, productlistperdistribpoint p,
                    productlistpercustomer plpc, customer c
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.distributionpoint_id = m1.distributionpoint_id
                and p.product_id = m1.product_id
                and p.sizedefinition_id = m1.sizedefinition_id
                and p.finishingmethod_id = m1.finishingmethod_id
                and plpc.productlistpercustomer_id = m1.plpc_id
                and plpc.soilcountmethod <> 0
                and c.customer_id = plpc.customer_id
                and c.allocationmethod = 0 -- Only decrease onsite inventory upon inscan when customer is NOT setup for allocation
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
              GROUP BY p.productlistperdistribpoint_id
            ) MERGE_SUBQUERY
      ON (o.productlistperdistribpoint_id = MERGE_SUBQUERY.productlistperdistribpoint_id
      AND o.origin                        = MERGE_SUBQUERY.origin
      AND o.inventorydate                 = MERGE_SUBQUERY.inventorydate
      AND o.reference is null)
      WHEN MATCHED THEN
        UPDATE
           SET o.quantity = o.quantity - MERGE_SUBQUERY.qty,
               o.systemuser_id = gv_systemuser_id,
               o.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
          (onsiteinventoryadjustment_id,
           productlistperdistribpoint_id,
           origin,
           inventorydate,
           quantity,
           reference,
           systemuser_id,
           timestamp,
           invoiceheader_id)
        VALUES
          (seq_onsiteinventoryadjustment.nextval,
           MERGE_SUBQUERY.productlistperdistribpoint_id,
           MERGE_SUBQUERY.origin,
           MERGE_SUBQUERY.inventorydate,
           MERGE_SUBQUERY.qty * -1,
           null, -- reference
           gv_systemuser_id,
           sysdate,
           null);
    exception
      when no_data_found then
        null;
    end;
   end; --decrease_onsite_inventory

   ---------------------------------------------
   procedure create_delivery_variations is

   begin
    begin
    gv_code_block := 'Create delivery variations pool';
    writemultireaddebuglog(gv_code_block);
    MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
      USING (SELECT nvl(p.distributionpoint_id, m1.distributionpoint_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.finishingmethod_id,
                    m1.plannedoutdate deliverydate,
                    max(m1.packingnote_id) packingnote_id,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.delayedevenexchange > 0  -- only those with delayed even exchange
                and nvl(p.distributionpoint_id, m1.distributionpoint_id) is not null
                and m1.plpc_id is not null
                and m1.uniqueitem_id is not null
                and m1.plannedoutdate is not null -- delivery date found
                and m1.multireadexception_id is null
                -- HVH-20016093 do not create DV's if last stay is sent to laundry because that scan already made the DV
                and m1.stay_id <> gc_stay_id_sent_to_laundry
              GROUP BY nvl(p.distributionpoint_id, m1.distributionpoint_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.finishingmethod_id,
                       m1.plannedoutdate
            ) MERGE_SUBQUERY
      ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
      AND d.product_id = MERGE_SUBQUERY.product_id
      AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
      AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
      AND d.deliverydate = MERGE_SUBQUERY.deliverydate
      AND (d.packingnote_id = MERGE_SUBQUERY.packingnote_id OR
          (d.packingnote_id is null and MERGE_SUBQUERY.packingnote_id is null))
      AND d.processed = case when MERGE_SUBQUERY.packingnote_id is null then 'N' else 'Y' end
      AND d.causenote_id is null
      AND d.updaterentqty = 'N'
      AND d.origin = 1
      AND d.soilcountsubtype = 7 -- inscan
      AND d.weborderline_id is null
      AND d.reference is null
      AND d.adjustmentreason_id is null
      AND d.reasoncode_id is null
      )
      WHEN MATCHED THEN
        UPDATE
           SET d.amount = d.amount + MERGE_SUBQUERY.qty,
               d.systemuser_id = gv_systemuser_id,
               d.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (deliveryvariations_id,
            product_id,
            packingnote_id,
            causenote_id,
            deliverydate,
            origin,
            amount,
            finishingmethod_id,
            fixedamount,
            distributionpoint_id,
            sizedefinition_id,
            reference,
            systemuser_id,
            processed,
            timestamp,
            updaterentqty,
            soilcountsubtype,
            processbusinessunit_id,
            internalprocessingbu_id)
        VALUES
          (seq_deliveryvariations.nextval,
           MERGE_SUBQUERY.product_id,
           MERGE_SUBQUERY.packingnote_id, -- packingnote
           null, -- cause note
           MERGE_SUBQUERY.deliverydate,
           1,    -- origin
           MERGE_SUBQUERY.qty,
           MERGE_SUBQUERY.finishingmethod_id,
           'N',  -- fixedamount
           MERGE_SUBQUERY.distributionpoint_id,
           MERGE_SUBQUERY.sizedefinition_id,
           null, -- reference
           gv_systemuser_id,
           case when MERGE_SUBQUERY.packingnote_id is null then 'N' else 'Y' end,  -- processed
           sysdate,
           'N',  -- update rent qty
           7,     -- soil count inscan
           f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
           gv_businessunit_id);
    exception
      when no_data_found then
        null;
    end;
   end create_delivery_variations;


   procedure create_packingnotelines is
     procedure create_pklines is
       begin
         writemultireaddebuglog(gv_code_block);
         MERGE INTO packingnoteline pkl
         USING (SELECT nvl(p.distributionpoint_id, m1.distributionpoint_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.finishingmethod_id,
                    m1.plannedoutdate deliverydate,
                    max(m1.packingnote_id) packingnote_id,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.delayedevenexchange > 0  -- only those with delayed even exchange
                and nvl(p.distributionpoint_id, m1.distributionpoint_id) is not null
                and m1.plpc_id is not null
                and m1.uniqueitem_id is not null
                and m1.plannedoutdate is not null -- delivery date found
                and m1.multireadexception_id is null
                and m1.stay_id <> gc_stay_id_sent_to_laundry
              GROUP BY nvl(p.distributionpoint_id, m1.distributionpoint_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.finishingmethod_id,
                       m1.plannedoutdate
              HAVING max(m1.packingnote_id) is not null
            ) MERGE_SUBQUERY
        ON (pkl.product_id = MERGE_SUBQUERY.product_id
        AND pkl.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
        AND pkl.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
        AND pkl.packingnote_id = MERGE_SUBQUERY.packingnote_id
        )
        WHEN MATCHED THEN
          UPDATE
             SET pkl.variationamount = pkl.variationamount + MERGE_SUBQUERY.qty,
                 pkl.tobedeliveredamount = pkl.tobedeliveredamount + MERGE_SUBQUERY.qty,
                 pkl.systemuser_id = gv_systemuser_id,
                 pkl.timestamp = sysdate
        WHEN NOT MATCHED THEN
          INSERT
            (packingnoteline_id,
             packingnote_id,
             product_id,
             sizedefinition_id,
             finishingmethod_id,
             packingsequence,
             standardamount,
             variationamount,
             deliveredamount,
             systemuser_id,
             timestamp,
             tobedeliveredamount,
             origin,
             putuptype,
             creationtimestamp,
             creationsystemuser_id,
             nochargefirstissue,
             nochargeactiveseason,
             discount,
             replacementqty,
             autoreplacementqty,
             updaterentqty,
             bundleqty)
          VALUES
            (seq_packingnoteline.nextval,
             MERGE_SUBQUERY.packingnote_id,
             MERGE_SUBQUERY.product_id,
             MERGE_SUBQUERY.sizedefinition_id,
             MERGE_SUBQUERY.finishingmethod_id,
             0, --packingsequence,
             0, --standardamount,
             MERGE_SUBQUERY.qty, --variationamount,
             0, --deliveredamount,
             gv_systemuser_id,
             sysdate,
             MERGE_SUBQUERY.qty, --tobedeliveredamount,
             0, --origin,
             1, --putuptype,
             sysdate, --creationtimestamp,
             gv_systemuser_id, --creationsystemuser_id,
             0, --nochargefirstissue,
             0, --nochargeactiveseason,
             0, --discount,
             0, --replacementqty,
             0, --autoreplacementqty,
             0, --updaterentqty,
             1  --bundleqty
            );
    exception
      when no_data_found then
        null;
    end create_pklines;
   begin
     gv_code_block := 'Create packingnotelines pool for transaction type 39 only';
     if gv_unatendedscantransactypeid = 39 then
       begin
         create_pklines;
       end;
     end if;
   end create_packingnotelines;

   procedure create_delivery_var_chiprate is
   begin
    gv_code_block := 'Create delivery variations pool for chiprate';
    --log for debugging
    writemultireaddebuglog(gv_code_block);
    if lv_year is not null and lv_week is not null then
      begin
        --Determine if exists ChippingRate for the
        --current BusinessUnit_ID
        --Product_ID
        --SizeDefinition_ID
        --FinishingMethod_ID
        --last Year / Week.
        --If not found then ChippingRate is considered 100 % and no additional correction is done.
        --If ChippingRate found and ChippingRate.ChippingRate <> 100 then
        --Deviation = Round (Scanned * 100 / ChippingRate) - Scanned.
        --If Deviation > 0 then Create additional DeliveryVariation same as for scanned items
        --except SoilCountSubType = 1 (Soil count) and DeliveryVariation.Amount = Deviation.
        MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
          USING (SELECT nvl(p.distributionpoint_id, m1.distributionpoint_id) distributionpoint_id,
                        m1.product_id,
                        m1.sizedefinition_id,
                        m1.finishingmethod_id,
                        m1.plannedoutdate deliverydate,
                        round(count(1)*100/max(cr.chippingrate))-count(1) qty
                   FROM multireadscanbatchcontents m1
                   JOIN chippingrate cr on
                      ( cr.businessunit_id = gv_businessunit_id
                   and cr.product_link_id = m1.product_id
                   and cr.sizedefinition_link_id = m1.sizedefinition_id
                   and cr.finishingmethod_id = m1.finishingmethod_id
                   and cr.year = lv_year
                   and cr.week = lv_week)
                   JOIN productlistpercustomer l on
                      l.productlistpercustomer_id = m1.plpc_id
                   JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
                   LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber
                  WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                    and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and m1.poolitemyn = 'Y'
                    and m1.delayedevenexchange > 0
                    and nvl(p.distributionpoint_id, m1.distributionpoint_id) is not null
                    and m1.plpc_id is not null
                    and m1.uniqueitem_id is not null
                    and m1.plannedoutdate is not null
                    and m1.multireadexception_id is null
                    and m1.stay_id <> gc_stay_id_sent_to_laundry
                    and cr.chippingrate not in (0, 100)
                    and l.usechippingratedee = 1
                  GROUP BY nvl(p.distributionpoint_id, m1.distributionpoint_id),
                           m1.product_id,
                           m1.sizedefinition_id,
                           m1.finishingmethod_id,
                           m1.plannedoutdate
                  HAVING round(count(1)*100/max(cr.chippingrate))-count(1) > 0
                ) MERGE_SUBQUERY
          ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
          AND d.product_id = MERGE_SUBQUERY.product_id
          AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
          AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
          AND d.deliverydate = MERGE_SUBQUERY.deliverydate
          AND d.packingnote_id is null
          AND d.processed = 'N'
          AND d.causenote_id is null
          AND d.updaterentqty = 'N'
          AND d.origin = 1
          AND d.soilcountsubtype = 1 -- soilcount
          AND d.weborderline_id is null
          AND d.reference is null
          AND d.adjustmentreason_id is null
          AND d.reasoncode_id is null
          )
          WHEN MATCHED THEN
            UPDATE
               SET d.amount = d.amount + MERGE_SUBQUERY.qty,
                   d.systemuser_id = gv_systemuser_id,
                   d.timestamp = sysdate
          WHEN NOT MATCHED THEN
            INSERT
               (deliveryvariations_id,
                product_id,
                packingnote_id,
                causenote_id,
                deliverydate,
                origin,
                amount,
                finishingmethod_id,
                fixedamount,
                distributionpoint_id,
                sizedefinition_id,
                reference,
                systemuser_id,
                processed,
                timestamp,
                updaterentqty,
                soilcountsubtype,
                processbusinessunit_id,
                internalprocessingbu_id)
            VALUES
              (seq_deliveryvariations.nextval,
               MERGE_SUBQUERY.product_id,
               null, -- packingnote
               null, -- cause note
               MERGE_SUBQUERY.deliverydate,
               1,    -- origin
               MERGE_SUBQUERY.qty,
               MERGE_SUBQUERY.finishingmethod_id,
               'N',  -- fixedamount
               MERGE_SUBQUERY.distributionpoint_id,
               MERGE_SUBQUERY.sizedefinition_id,
               null, -- reference
               gv_systemuser_id,
               'N',  -- processed
               sysdate,
               'N',  -- update rent qty
               1,     -- soil count
               f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
               gv_businessunit_id);
        exception
          when no_data_found then
            null; --ok, nothing to be done
       end;
     end if;
   end create_delivery_var_chiprate;

   ---------------------------------------------
   procedure inscan_update_unique_item is
   begin
     begin
      writemultireaddebuglog('Update_unique item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    case when m1.poolitemyn='Y' and m1.secondaryid is null
                      then mb.businessunit_id -- update BU upon inscan only for pool items without secID
                      else m1.businessunit_id -- original BU
                    end businessunit_id,
                    m1.stay_id,
                    m1.status_id,
                    case when u1.status_id <> gc_status_id_in_circ
                     then m1.scantimestamp
                     else u1.statuschangedate
                    end statuschangedate,
                    m1.distributionpoint_id,
                    m1.plannedoutdate,
                    m1.poolitemyn,
                    m1.uniqueitembatchnumber,
                    m1.weareremployment_id
               FROM multireadscanbatch mb, multireadscanbatchcontents m1, uniqueitem u1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.businessunit_id = MERGE_SUBQUERY.businessunit_id, -- update BU upon inscan
                u.lastinscandate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal = case when gc_ss_countwashesat = 'I'
                                       or (gc_ss_countwashesat='O'
                                      and gc_ss_inscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_in_laundry)
                                then u.washestotal + 1
                                else u.washestotal
                                end,
                u.prevstatus_id = case when MERGE_SUBQUERY.status_id <> gc_status_id_in_circ
                                   then MERGE_SUBQUERY.status_id
                                   else null
                                  end,
               u.status_id = case when MERGE_SUBQUERY.status_id = gc_status_id_assigned and gs_ss_bringincircatinscan = 1
                                       and not exists
                                       (SELECT 1 FROM DELIVERYSCAN DS JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
                                         WHERE UI.STARTRENTFROM = 3 and DS.PACKINGNOTE_ID IS NOT NULL
                                         and DS.UNIQUEITEM_LINK_ID = MERGE_SUBQUERY.uniqueitem_id
                                         and DS.WEAREREMPLOYMENT_LINK_ID = MERGE_SUBQUERY.weareremployment_id)
                               then
                                 gc_status_id_assigned
                               else
                                 gc_status_id_in_circ
                               end,
                u.statuschangedate = MERGE_SUBQUERY.statuschangedate,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = case when fp_transactiontypeid = 55
                              then gc_stay_id_inscan_cleanreturn
                              else gc_stay_id_in_laundry
                             end,
                u.distributionpoint_id = null,   -- disconnect from previous user
                u.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.poolitemyn = 'Y'
                                                   then MERGE_SUBQUERY.distributionpoint_id
                                                   else null
                                                  end,
                u.unrelatedloan_id = null,       -- disconnect from unrelated loan
                u.currentuniquebundle_id = null, -- disconnect from bundle
                u.planneddeliverydate = case when MERGE_SUBQUERY.poolitemyn = 'N'
                                         then MERGE_SUBQUERY.plannedoutdate
                                         else null
                                        end,
                u.batchnumber = MERGE_SUBQUERY.uniqueitembatchnumber,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
      --
      writemultireaddebuglog('Update unique item non pool');
      MERGE INTO uniqueitemnonpool u
      USING (SELECT m1.uniqueitem_id,
                    m1.stay_id
               FROM multireadscanbatchcontents m1, uniqueitemnonpool u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.washesthisissue = case when gc_ss_countwashesat = 'I'
                                       or (gc_ss_countwashesat='O'
                                      and gc_ss_inscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_in_laundry)
                                then u.washesthisissue + 1
                                else u.washesthisissue
                                end,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    --
    writemultireaddebuglog('Update unique item loss');
    merge into uniqueitemloss u
    using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
             from multireadscanbatchcontents m, uniqueitemloss ul
            where m.multireadscanbatch_id = gv_multireadscanbatch_id
              and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              and ul.uniqueitem_link_id = m.uniqueitem_id
              and ul.lossstatus <= 1 -- loss charged
              and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
              and m.multireadexception_id is null) mergequery
    on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
    when matched then
      update set u.returneddate = trunc(sysdate),
                 u.timestamp = sysdate,
                 u.systemuser_id = gv_systemuser_id;
    exception
      when no_data_found then
        null;
    end;
   end; -- inscan_update_unique_item

   --------------------------------------------------------------
   procedure inscan_update_unique_item_rte is

   begin
     begin
      writemultireaddebuglog('Update unique item route');
      MERGE INTO uniqueitemroute u
      USING (SELECT m1.uniqueitem_id,
                    m1.lastindate,
                    m1.lastinroute_id,
                    m1.lastinstop_id,
                    m1.plannedoutdate,
                    m1.plannedoutroute_id,
                    m1.plannedoutstop_id
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.poolitemyn = 'N'
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET u.lastindate = MERGE_SUBQUERY.lastindate,
               u.lastinroute_id = MERGE_SUBQUERY.lastinroute_id,
               u.lastinstop_id =  MERGE_SUBQUERY.lastinstop_id,
               u.plannedoutdate = MERGE_SUBQUERY.plannedoutdate,
               u.plannedoutroute_id = MERGE_SUBQUERY.plannedoutroute_id,
               u.plannedoutstop_id = MERGE_SUBQUERY.plannedoutstop_id,
               u.systemuser_id = gv_systemuser_id,
               u.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (uniqueitem_id,
            lastinroute_id,
            lastoutroute_id,
            plannedoutroute_id,
            lastindate,
            lastoutdate,
            plannedoutdate,
            systemuser_id,
            timestamp,
            lastinstop_id,
            lastoutstop_id,
            plannedoutstop_id
            )
        VALUES
          (MERGE_SUBQUERY.uniqueitem_id,
           MERGE_SUBQUERY.lastinroute_id,
           null, --lastoutroute_id
           MERGE_SUBQUERY.plannedoutroute_id,
           MERGE_SUBQUERY.lastindate,
           null, -- lastoutdate
           MERGE_SUBQUERY.plannedoutdate,
           gv_systemuser_id,
           sysdate,
           MERGE_SUBQUERY.lastinstop_id,
           null, -- lastoutstop_id
           MERGE_SUBQUERY.plannedoutstop_id
           );

      if gc_ss_routecontrolcreation >= 3 then
       begin
         writemultireaddebuglog('Create Route Control');
         for vcursorR in  (SELECT m1.plannedoutdate,
                                  m1.plannedoutroute_id
                             FROM multireadscanbatchcontents m1
                            WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                              AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                              AND m1.plannedoutdate is not null
                              AND m1.plannedoutroute_id is not null
                              AND not exists (select 1
                                                from routecontrol r
                                               where r.route_id = m1.plannedoutroute_id
                                                 and r.originaldrivingdate = m1.plannedoutdate)
                              AND m1.multireadexception_id is null
                         GROUP BY m1.plannedoutdate,
                                  m1.plannedoutroute_id
                          )
         loop
           create_route_control(vcursorR.plannedoutroute_id,
                                vcursorR.plannedoutdate);
         end loop;
       exception
          when no_data_found then
            null;
       end;
      end if; -- gc_ss_usetreatmentcheck <> 0
    exception
      when no_data_found then
        null;
    end;
   end; -- inscan_update_unique_item_route

   ---------------------------------------------
   procedure create_inscans is
   begin
    -- populate scan_ID in case it was not yet populated by retrieve item info
    begin
    writemultireaddebuglog('Create inscans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create inscans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, scandateoffset, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan,
             batchnumber )
    select mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id) distributionpoint_id, -- ABS-44277
           mbc.product_id,
           mbc.sizedefinition_id,
           case when fp_transactiontypeid = 55
             then
               gc_stay_id_inscan_cleanreturn
             else
               gc_stay_id_in_laundry
           end,
           case when mbc.status_id = gc_status_id_assigned and gs_ss_bringincircatinscan = 1
                     and not exists
                     (SELECT 1 FROM DELIVERYSCAN DS JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
                       WHERE UI.STARTRENTFROM = 3 and DS.PACKINGNOTE_ID IS NOT NULL
                       and DS.UNIQUEITEM_LINK_ID = mbc.uniqueitem_id
                       and DS.WEAREREMPLOYMENT_LINK_ID = mbc.weareremployment_id)
             then
               gc_status_id_assigned
             else
               gc_status_id_in_circ
             end,
           w.code, -- workstation code
           mbc.lastissuedate,
           mbc.lastinroute_id,
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           fp_transactiontypeid, -- transaction type inscan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           gv_pickupdate - trunc(mbc.scantimestamp), -- scandateoffset
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
           mbc.uniqueitembatchnumber
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end create_inscans; -- create_inscans

   --------------------------------------------------------
   procedure inscan_Update_OR_Pack_Status is
   begin
     begin
     writemultireaddebuglog('Update OR Pack Inscan Timestamp');
     update uniqueORpack up
        set up.inscantimestamp = trunc(sysdate)
      where up.uniqueitem_id in
           (select ui.uniqueitem_id
              from multireadscanbatchcontents mbc,
                   uniqueitem ui,
                   uniqueorpack uop,
                   uniqueorpackcontents uopc,
                   uniqueorpackuniquecontents uopuc
             WHERE ui.uniqueitem_id = uop.uniqueitem_id
               AND uop.uniqueitem_id = uopc.uniqueitem_id
               AND uopc.uniqueorpackcontents_id = uopuc.uniqueorpackcontents_id
               AND uopuc.uniqueitem_id = mbc.uniqueitem_id
               AND ui.status_id NOT IN (SELECT s.status_id
                                          FROM status s
                                         WHERE s.statustype = 'OR'
                                           AND s.code in ('50','60','70')) -- NOT USED,CANCELLED,RECALLED
               AND mbc.multireadscanbatch_id = gv_multireadscanbatch_id
               AND (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
               AND mbc.poolitemyn = 'Y'
               AND mbc.multireadexception_id is null);
     writemultireaddebuglog('Update OR Pack Status');
     update uniqueitem u
        set u.status_id = gc_status_id_or_used,
            u.prevstatus_id = u.status_id,
            u.statuschangedate = trunc(sysdate)
      where u.uniqueitem_id in
           (select ui.uniqueitem_id
              from multireadscanbatchcontents mbc,
                   uniqueitem ui,
                   uniqueorpack uop,
                   uniqueorpackcontents uopc,
                   uniqueorpackuniquecontents uopuc
             WHERE ui.uniqueitem_id = uop.uniqueitem_id
               AND uop.uniqueitem_id = uopc.uniqueitem_id
               AND uopc.uniqueorpackcontents_id = uopuc.uniqueorpackcontents_id
               AND uopuc.uniqueitem_id = mbc.uniqueitem_id
               AND ui.status_id NOT IN (SELECT s.status_id
                                          FROM status s
                                         WHERE s.statustype = 'OR'
                                           AND s.code in ('50','60','70')) -- NOT USED,CANCELLED,RECALLED
               AND mbc.multireadscanbatch_id = gv_multireadscanbatch_id
               AND (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
               AND mbc.poolitemyn = 'Y'
               AND mbc.multireadexception_id is null);
     exception
        when no_data_found then
          null;
      end;
   end; -- inscan_Update_OR_Pack_Status

   procedure Create_ExchangeCartCycle is
   begin
    --Create_ExchangeCartCycle
    gv_code_block := 'Create ExchangeCartCycle InscanBatch';
    writemultireaddebuglog(gv_code_block);
    if lv_year is not null and lv_week is not null then
      begin
        MERGE INTO exchangecartcycle ecc
          USING (
          select ec.exchangecart_id, m1.product_id, m1.sizedefinition_id,
                 m1.finishingmethod_id, count(1) realscannedin,
             nvl(max((select max(cr.chippingrate)
                      from  chippingrate cr
                      where cr.businessunit_id = gv_businessunit_id
                        and cr.product_link_id = m1.product_id
                        and cr.sizedefinition_link_id = m1.sizedefinition_id
                        and cr.finishingmethod_id = m1.finishingmethod_id
                        and cr.year = lv_year
                        and cr.week = lv_week))
                 ,100) chippingrate,
                 l.usechippingratedee
          from  multireadscanbatchcontents m1
          JOIN productlistpercustomer l on
               l.productlistpercustomer_id = m1.plpc_id
          cross join exchangecart ec
          where m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
          and ec.exchangecart_id = fp_exchangecart_id
          group by ec.exchangecart_id,
                   m1.product_id,
                   m1.sizedefinition_id,
                   m1.finishingmethod_id,
                   l.usechippingratedee
           ) MERGE_SUBQUERY
          ON ( ecc.exchangecart_id = MERGE_SUBQUERY.exchangecart_id
          AND  ecc.product_link_id = MERGE_SUBQUERY.product_id
          AND  ecc.sizedefinition_link_id = MERGE_SUBQUERY.sizedefinition_id
          AND  ecc.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
          AND  ecc.deliverydate is null
           )
          WHEN MATCHED THEN
            UPDATE
               SET ecc.realscannedin = ecc.realscannedin + MERGE_SUBQUERY.realscannedin,
                   ecc.calculatedscannedin =
                     case when ecc.chippingrate <> 0
                           and MERGE_SUBQUERY.usechippingratedee = 1
                       then round((MERGE_SUBQUERY.realscannedin*100)/MERGE_SUBQUERY.chippingrate)
                       else ecc.realscannedin + MERGE_SUBQUERY.realscannedin
                     end,
                   ecc.systemuser_id = gv_systemuser_id,
                   ecc.timestamp = sysdate
          WHEN NOT MATCHED THEN
            INSERT
               (exchangecartcycle_id,
                exchangecart_id,
                cleanreturndate,
                deliverydate,
                codeuniquely,
                product_link_id,
                sizedefinition_link_id,
                finishingmethod_id,
                par,
                chippingrate,
                realscannedin,
                calculatedscannedin,
                countedin,
                realscannedout,
                calculatedscannedout,
                systemuser_id,
                timestamp
                )
            VALUES
              (seq_exchangecartcycle.nextval,
              MERGE_SUBQUERY.exchangecart_id,
              trunc(sysdate), --cleanreturndate
              null, --deliverydate
              1, --codeuniquely
              MERGE_SUBQUERY.product_id,
              MERGE_SUBQUERY.sizedefinition_id,
              MERGE_SUBQUERY.finishingmethod_id,
              0, --par
              MERGE_SUBQUERY.chippingrate, --chippingrate
              MERGE_SUBQUERY.realscannedin, --realscannedin
              case when MERGE_SUBQUERY.chippingrate <> 0
                    and MERGE_SUBQUERY.usechippingratedee = 1
                 then round((MERGE_SUBQUERY.realscannedin*100)/MERGE_SUBQUERY.chippingrate)
                 else MERGE_SUBQUERY.realscannedin
              end, --calculatedscannedin
              0, --countedin
              0, --realscannedout
              0, --calculatedscannedout
              gv_systemuser_id,
              sysdate
               );
         exception
            when no_data_found then
              null;
       end;
     end if;
   end Create_ExchangeCartCycle;

   procedure Create_Soilcount is
   begin
     --Create_Soilcount
    --Create_ExchangeCartCycle
    gv_code_block := 'Create SoilCount InscanBatch(Clean)';
    writemultireaddebuglog(gv_code_block);
    --distributionpoint_link_id, countdate=trunc(sysdate),
    --processbusinessunit_id, bagtag_id is null, referencenumber
    begin
      merge into soilcount sc
          using (
          select m1.distributionpoint_id, cc.primaryid
          from  multireadscanbatchcontents m1
          join productlistpercustomer l on
               l.productlistpercustomer_id = m1.plpc_id
          cross join exchangecart ec
          join container cc on cc.container_id = ec.exchangecart_id
          where m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
          and ec.exchangecart_id = fp_exchangecart_id
          and l.usechippingratedee = 1
          group by m1.distributionpoint_id,
                   cc.primaryid
          having max((select max(cr.chippingrate)
                      from  chippingrate cr
                      where cr.businessunit_id = gv_businessunit_id
                        and cr.product_link_id = m1.product_id
                        and cr.sizedefinition_link_id = m1.sizedefinition_id
                        and cr.finishingmethod_id = m1.finishingmethod_id
                        and cr.year = lv_year
                        and cr.week = lv_week)) between 1 and 100
           ) merge_subquery
          on (sc.distributionpoint_link_id = merge_subquery.distributionpoint_id
          and sc.countdate=trunc(sysdate)
          and sc.processbusinessunit_id = gv_businessunit_id
          and bagtag_id is null
          and referencenumber = merge_subquery.primaryid
           )
          when matched then
            update
            set sc.systemuser_id = gv_systemuser_id,
                sc.timestamp = sysdate
          when not matched then
            insert
               (soilcount_id,
                distributionpoint_link_id,
                processbusinessunit_id,
                countdate,
                systemuser_id,
                timestamp,
                bagtag_id,
                referencenumber
                )
            values
              (seq_soilcount.nextval,
               merge_subquery.distributionpoint_id,
               gv_businessunit_id,
               trunc(sysdate),
               gv_systemuser_id,
               sysdate,
               null,
               merge_subquery.primaryid
               );
         exception
            when no_data_found then
              null;
    end;  --soilcount
    begin
      --soilcount_id,
      --product_link_id, sizedefinition_link_id, finishingmethod_id,
      --unrelatedloan = 'N'
      merge into soilcountline scl
          using (
          select sc.soilcount_id,
                 m1.product_id,
                 m1.sizedefinition_id,
                 m1.finishingmethod_id,
                 max(l.delayedevenexchange) delayedevenexchange,
                 count(1) realqty,
                 max((select max(cr.chippingrate)
                  from  chippingrate cr
                  where cr.businessunit_id = gv_businessunit_id
                    and cr.product_link_id = m1.product_id
                    and cr.sizedefinition_link_id = m1.sizedefinition_id
                    and cr.finishingmethod_id = m1.finishingmethod_id
                    and cr.year = lv_year
                    and cr.week = lv_week)) chippingrate
          from multireadscanbatchcontents m1
          join productlistpercustomer l
            on l.productlistpercustomer_id = m1.plpc_id
          cross join exchangecart ec
          join container cc on cc.container_id = ec.exchangecart_id
          join soilcount sc
            on sc.distributionpoint_link_id = m1.distributionpoint_id
          and sc.countdate=trunc(sysdate)
          and sc.processbusinessunit_id = gv_businessunit_id
          and bagtag_id is null
          and referencenumber = cc.primaryid
          where m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
          and ec.exchangecart_id = fp_exchangecart_id
          and l.usechippingratedee = 1
          group by sc.soilcount_id,
                   m1.product_id,
                   m1.sizedefinition_id,
                   m1.finishingmethod_id
          having max((select max(cr.chippingrate)
                      from  chippingrate cr
                      where cr.businessunit_id = gv_businessunit_id
                        and cr.product_link_id = m1.product_id
                        and cr.sizedefinition_link_id = m1.sizedefinition_id
                        and cr.finishingmethod_id = m1.finishingmethod_id
                        and cr.year = lv_year
                        and cr.week = lv_week)) between 1 and 100
           ) merge_subquery
          on (scl.soilcount_id = merge_subquery.soilcount_id
          and scl.product_link_id = merge_subquery.product_id
          and scl.sizedefinition_link_id = merge_subquery.sizedefinition_id
          and scl.finishingmethod_id = merge_subquery.finishingmethod_id
          and scl.unrelatedloan = 'N'
           )
          when matched then
            update
            set scl.countkeypad = scl.countkeypad +
                     round((merge_subquery.realqty*100)/merge_subquery.chippingrate),
                scl.systemuser_id = gv_systemuser_id,
                scl.timestamp = sysdate
          when not matched then
            insert
               (soilcountline_id,
                soilcount_id,
                product_link_id,
                sizedefinition_link_id,
                finishingmethod_id,
                countconverted,
                countkeypad,
                countlightframe,
                countabused,
                soilweight,
                delayevenexchange,
                unrelatedloan,
                systemuser_id,
                timestamp
                )
            values
              (seq_soilcountline.nextval,
               merge_subquery.soilcount_id,
               merge_subquery.product_id,
               merge_subquery.sizedefinition_id,
               merge_subquery.finishingmethod_id,
               0, --countconverted,
               round((merge_subquery.realqty*100)/merge_subquery.chippingrate),--countkeypad,
               0, --countlightframe,
               0, --countabused,
               0, --soilweight,
               merge_subquery.delayedevenexchange,
               'N', --unrelatedloan,
               gv_systemuser_id,
               sysdate
               );
         exception
            when no_data_found then
              null;
    end; --soilcountline
   end Create_Soilcount;

----------------------------------------------------------------
   procedure disconnect_pool_temp_assigned is
   begin
     begin
      writemultireaddebuglog('disconnect_pool_temp_assigned');
      MERGE INTO wearertempassignment wtaRecord
      USING (SELECT wta.uniqueitem_link_id
               FROM multireadscanbatchcontents m1, wearertempassignment wta
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = wta.uniqueitem_link_id
                and m1.multireadexception_id is null
                and m1.poolitemyn = 'Y'
                and wta.returnfromwearerdate is null
             ) MERGE_SUBQUERY
      ON (wtaRecord.uniqueitem_link_id = MERGE_SUBQUERY.uniqueitem_link_id)
      WHEN MATCHED THEN
        UPDATE
           SET wtaRecord.returnfromwearerdate = sysdate,
               wtaRecord.systemuser_id = gv_systemuser_id,
               wtaRecord.timestamp = trunc(sysdate);

    exception
      when no_data_found then
        null;
    end;
   end; -- disconnect_pool_temp_assigned
------------------------------------------------------------------
   -- Begin f_processmultireadinscanbatch
   begin
      begin
        if fp_called_by_inscan_YN = 'Y'
         then gv_main_code_block := 'Process Inscan Batch';
         else gv_main_code_block := 'Process Laundry Buffer Scan Batch';
        end if;
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items,
               sum(case when m.orpackitemyn='Y' then 1 else 0 end) number_orpack_items,
               sum(case when s.code='30' then 1 else 0 end) number_assigned_items,
               sum(case when s.code='40' then 1 else 0 end) number_ragged_items,
               sum(case when m.unrelatedloan_id is not null then 1 else 0 end) number_loan_items,
               sum(case when s.code='30' and gs_ss_bringincircatinscan = 1 and exists
               ( SELECT 1 FROM DELIVERYSCAN DS
                 JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
                 JOIN UNIQUEITEMNONPOOL UINP on UINP.UNIQUEITEM_ID = UI.UNIQUEITEM_ID
               WHERE UI.STARTRENTFROM = 3 and DS.PACKINGNOTE_ID IS NOT NULL
               and DS.UNIQUEITEM_LINK_ID = m.uniqueitem_id
               and DS.WEAREREMPLOYMENT_LINK_ID = UINP.WEAREREMPLOYMENT_ID )
               then 1 else 0 end) number_assigned_items_deliverd

          into lv_number_pool_items,
               lv_number_nonpool_items,
               lv_number_orpack_items,
               lv_number_assigned_items,
               lv_number_ragged_items,
               lv_number_loan_items,
               lv_number_assigned_items_deliv
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;
     -- undo rags
     if gv_result = 0 and lv_number_ragged_items > 0 then
       undo_rags;
     end if;

    if gv_result = 0 then
     Retrieve_main_item_info;
    end if;

     -- bring in circ assigned items
    if gv_result = 0 and lv_number_assigned_items > 0 and (gs_ss_bringincircatinscan = 0 or lv_number_assigned_items_deliv > 0) then
      bring_in_circ_assigned_items;
      if gv_result = gc_result_duplicate_scan_err then
         --try again
         gv_result := 0;
         bring_in_circ_assigned_items;
      end if;
    end if;

    if gv_result = 0 then
    begin  -- exception block
     retrieve_item_info_for_delvar;

     if (gv_databasecode not in ('FIS','PLS')) and    -- ABS-17369 + ABS-38833
        (gv_ss_uhfinscantrackingonly = 'N') -- ABS-31879 when UHF tracking only do not create delvar + decr. onsite inv.
        then
       if lv_number_pool_items > 0 then
         begin
           create_delivery_variations;
           create_packingnotelines;
           create_delivery_var_chiprate;
         end;
       end if;

       if gs_ss_recordonsiteinventory = 'Y' then
         decrease_onsite_inventory;
       end if;

     end if;

     if lv_number_pool_items > 0 and lv_number_loan_items > 0 then
       incr_qty_returned_unrel_loans;
     end if;

     Inscan_update_unique_item;

     if lv_number_pool_items > 0 then
       inscan_Update_OR_Pack_Status;
     end if;

     if gc_ss_scanbyroute='Y' and lv_number_nonpool_items > 0 then
       inscan_update_unique_item_rte;
     end if;

     if lv_number_nonpool_items > 0 then
       add_flag_for_decrease_max_inv;
     end if;

     Create_flags_maxwash_spectreat;

     Create_inscans;

     Remove_Flags('InScan');

     if gv_prodprocessbuffer_id is not null then
         delete_uniqueitem_buffer_info; -- first clear bufferinfo
         if fp_called_by_inscan_YN='Y' then -- only then do the buffer processing otherwise it will be done later
           load_uniqueitem_buffer_info;
           insertupdate_uniqueitembufinfo(1);
           create_prodprocessbufscans(1);
         end if;
     end if;

     if fp_called_by_inscan_YN='Y' then
       Create_reject_scans(fp_transactiontypeid); -- 1 = transactiontype inscan
     end if;

     if fp_exchangecart_id is not null then
       begin
         if fp_transactiontypeid = 1 then
           begin
             Create_Soilcount;
           end;
         else
           begin
             Create_ExchangeCartCycle;
           end;
         end if;
       end;
     end if;

    -- disconnect_pool_temp_assigned
    if lv_number_pool_items > 0 then
        disconnect_pool_temp_assigned;
    end if;

     delete_uhfbundle(gv_subbatchnumber);

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
     when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(fp_transactiontypeid, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processinscanbatch;


  -----------------------------------------------------------------------------------------
  function f_processinscanbatchKNT return number is

   ---------------------------------------------
   procedure inscan_update_container is
   begin
     begin
      writemultireaddebuglog('Update Container');
      MERGE INTO container c
      USING (SELECT m1.container_id,
                    m1.scantimestamp,
                    mb.businessunit_id current_bu,
                    m1.businessunit_id last_bu,
                    m1.stay_id,
                    m1.distributionpoint_id,
                    m1.lastdistribpoint_id,
                    c1.staychangedate,
                    c1.numberofdaysatcustprev,
                    trunc(c1.lastoutscandate) lastoutscandate
               FROM multireadscanbatch mb, multireadscanbatchcontknt m1, container c1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.container_id = c1.container_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (c.container_id = MERGE_SUBQUERY.container_id)
      WHEN MATCHED THEN
        UPDATE
           SET  c.businessunit_id = MERGE_SUBQUERY.current_bu, -- update BU upon inscan
                c.lastbusinessunit_id = MERGE_SUBQUERY.last_bu,
                c.distributionpoint_id = null,   -- disconnect from previous user
                c.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                   then MERGE_SUBQUERY.distributionpoint_id
                                                   else MERGE_SUBQUERY.lastdistribpoint_id -- leave unchanged
                                                  end,
                c.prevstay_id = MERGE_SUBQUERY.stay_id,
                c.stay_id = gc_stay_id_knt_in_laundry,
                c.staychangedate = case when MERGE_SUBQUERY.stay_id <> gc_stay_id_knt_in_laundry
                                      then MERGE_SUBQUERY.scantimestamp
                                      else MERGE_SUBQUERY.staychangedate -- leave unchanged
                                   end,
                c.lastinscandate = MERGE_SUBQUERY.scantimestamp,
                c.numberofdaysatcustprev = case when MERGE_SUBQUERY.distributionpoint_id is not null and MERGE_SUBQUERY.lastoutscandate is not null
                                                   then MERGE_SUBQUERY.numberofdaysatcustprev + (trunc(MERGE_SUBQUERY.scantimestamp) - trunc(MERGE_SUBQUERY.lastoutscandate))
                                                   else MERGE_SUBQUERY.numberofdaysatcustprev -- leave unchanged
                                           end,
                c.systemuser_id = gv_systemuser_id,
                c.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- inscan_update_container

   ---------------------------------------------
   procedure create_container_inscans is
   begin
    -- populate scan_ID
    begin
    writemultireaddebuglog('Create Container inscans - populate scanID');
    UPDATE multireadscanbatchcontknt m
       set m.containerscan_id = seq_containerscan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.container_id is not null
       and m.containerscan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Container inscans');
    insert into containerscan
            (containerscan_id,
             scantimestamp,
             businessunit_id,
             primaryid,
             secondaryid,
             distributionpoint_link_id,
             containertype_id,
             stay_id,
             prevstay_id,
             transactiontype_id,
             scanstation,
             customerowned,
             year,
             week,
             dayno,
             container_id,
             tareweight,
             systemuser_id,
             timestamp)
    select mbc.containerscan_id,
           mbc.scantimestamp,
           mb.businessunit_id,
           mbc.idcode,
           mbc.secondaryid,
           case when mbc.distributionpoint_id is null
             then mbc.lastdistribpoint_id
             else mbc.distributionpoint_id
           end distributionpoint_link_id,
           mbc.containertype_id,
           gc_stay_id_knt_in_laundry,
           mbc.stay_id,
           511, -- transaction type inscan containers
           w.code,
           case when mbc.ownercustomer_id is not null
            then 'Y'
            else 'N'
           end,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.container_id,
           mbc.tareweight,
           mbc.systemuser_id,
           sysdate
      from multireadscanbatch            mb,
           multireadscanbatchcontknt     mbc,
           workstation                   w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.containerscan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_container_inscans

   ----------------------------------------------------------------
   -- Begin f_processmultireadinscanbatch
   begin
    begin
     gv_main_code_block := 'Process Inscan Batch Containers';

     Inscan_update_container;

     Update_container_rent;

     update_container_charges;

     Create_container_inscans;

     Create_reject_scans_knt(511); -- 511 = transactiontype inscan container

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processinscanbatchKNT;


  -----------------------------------------------------------------------------------------
  function f_processdisinfectscanbatchKNT return number is

   ---------------------------------------------
   procedure disinfectscan_update_container is
   begin
     begin
      writemultireaddebuglog('Update Container');
      MERGE INTO container c
      USING (SELECT m1.container_id,
                    m1.scantimestamp,
                    mb.businessunit_id current_bu,
                    m1.businessunit_id last_bu,
                    m1.stay_id,
                    m1.distributionpoint_id,
                    m1.lastdistribpoint_id,
                    c1.staychangedate,
                    c1.numberofdaysatcustprev,
                    trunc(c1.lastoutscandate) lastoutscandate
               FROM multireadscanbatch mb, multireadscanbatchcontknt m1, container c1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.container_id = c1.container_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (c.container_id = MERGE_SUBQUERY.container_id)
      WHEN MATCHED THEN
        UPDATE
           SET  c.businessunit_id = MERGE_SUBQUERY.current_bu, -- update BU upon disinfectscan
                c.lastbusinessunit_id = MERGE_SUBQUERY.last_bu,
                c.distributionpoint_id = null,   -- disconnect from previous user if not inscanned
                c.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                   then MERGE_SUBQUERY.distributionpoint_id
                                                   else MERGE_SUBQUERY.lastdistribpoint_id -- leave unchanged
                                                  end,
                c.prevstay_id = MERGE_SUBQUERY.stay_id,
                c.stay_id = gc_stay_id_knt_disinfect,
                c.staychangedate = case when MERGE_SUBQUERY.stay_id <> gc_stay_id_knt_disinfect
                                      then MERGE_SUBQUERY.scantimestamp
                                      else MERGE_SUBQUERY.staychangedate -- leave unchanged
                                   end,
                c.lastdisinfectiondate = MERGE_SUBQUERY.scantimestamp,
                c.numberofdisinfections = c.numberofdisinfections + 1,
                c.lastinscandate = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                       then MERGE_SUBQUERY.scantimestamp  -- if not inscanned assume inscan today
                                       else c.lastinscandate -- leave unchanged.
                                   end,
                c.numberofdaysatcustprev = case when MERGE_SUBQUERY.distributionpoint_id is not null and MERGE_SUBQUERY.lastoutscandate is not null
                                                   then MERGE_SUBQUERY.numberofdaysatcustprev + (trunc(MERGE_SUBQUERY.scantimestamp) - trunc(MERGE_SUBQUERY.lastoutscandate))
                                                   else MERGE_SUBQUERY.numberofdaysatcustprev -- leave unchanged
                                           end,
                c.systemuser_id = gv_systemuser_id,
                c.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- disinfectscan_update_container

   ---------------------------------------------
   procedure Create_container_disinfectscan is
   begin
    -- populate scan_ID
    begin
    writemultireaddebuglog('Create Container disinfectscans - populate scanID');
    UPDATE multireadscanbatchcontknt m
       set m.containerscan_id = seq_containerscan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.container_id is not null
       and m.containerscan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Container disinfectscans');
    insert into containerscan
            (containerscan_id,
             scantimestamp,
             businessunit_id,
             primaryid,
             secondaryid,
             distributionpoint_link_id,
             containertype_id,
             stay_id,
             prevstay_id,
             transactiontype_id,
             scanstation,
             customerowned,
             year,
             week,
             dayno,
             container_id,
             tareweight,
             systemuser_id,
             timestamp)
    select mbc.containerscan_id,
           mbc.scantimestamp,
           mb.businessunit_id,
           mbc.idcode,
           mbc.secondaryid,
           case when mbc.distributionpoint_id is null
             then mbc.lastdistribpoint_id
             else mbc.distributionpoint_id
           end distributionpoint_link_id,
           mbc.containertype_id,
           gc_stay_id_knt_disinfect,
           mbc.stay_id,
           520, -- transaction type disinfectscan containers
           w.code,
           case when mbc.ownercustomer_id is not null
            then 'Y'
            else 'N'
           end,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.container_id,
           mbc.tareweight,
           mbc.systemuser_id,
           sysdate
      from multireadscanbatch            mb,
           multireadscanbatchcontknt     mbc,
           workstation                   w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.containerscan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_container_disinfectscans

   ----------------------------------------------------------------
   -- Begin f_processdisinfectscanbatchKNT
   begin
    begin
     gv_main_code_block := 'Process Disinfect Batch Containers';

     Disinfectscan_update_container;

     Create_container_disinfectscan;

     Update_container_rent;

     update_container_charges;

     Create_reject_scans_knt(520); -- 520 = transactiontype disinfect container

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processdisinfectscanbatchKNT;

  -----------------------------------------------------------------------------------------
  function f_processinscanrejectbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;
   lv_number_orpack_items   number := 0;
   lv_number_ragged_items   number := 0;
   lv_number_loan_items     number := 0;
   ---------------------------------------------
   procedure retrieve_main_item_info is
   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    nvl(--nvl(u.relatedcustomer_id,  -- HVH 24/02/2015 removed related customer
                       (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = u.distributionpoint_id
                           and de1.department_id = di1.department_id), --),
                        (select de2.customer_id
                           from distributionpoint di2,
                                department de2
                          where di2.distributionpoint_id = u.lastdistributionpoint_link_id
                            and de2.department_id = di2.department_id)) customer_id,
                    coalesce(m1.distributionpoint_id, u.distributionpoint_id, u.lastdistributionpoint_link_id) distributionpoint_id,
                    u.lastdistributionpoint_link_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = coalesce(m1.distributionpoint_id, u.distributionpoint_id, u.lastdistributionpoint_link_id)) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.lastdistributionpoint_link_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;

    begin
    -- added step 1b for ABS-55410
    -- When customer related pool items are not outscanned then still you can know the
    -- department/conspoint in case the customer only has 1 active cons.point in order to create delivery variations
    -- of course can only be done when the items cannot be send to any other customer
    writemultireaddebuglog('Retrieve main item info step 1b cust related pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    m1.relatedcustomer_id customer_id,
                    dp.distributionpoint_id,
                    dp.deliverypoint_id
               FROM multireadscanbatchcontents m1, customer c,
                    department d, distributionpoint dp
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and c.customer_id = m1.relatedcustomer_id
                and d.customer_id = m1.relatedcustomer_id
                and dp.department_id = d.department_id
                and d.active = 'Y'
                and dp.active = 'Y'
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                and m1.distributionpoint_id is null -- not processed by query above
                and m1.relatedcustomer_id is not null -- only for customer related items
                and c.customer_id = m1.relatedcustomer_id  -- only if related customer is not billto/master/common/other cust
                and c.customerrelated = 1
                and not exists (select c2.customer_id from customer c2
                                where c2.debtor_id = m1.relatedcustomer_id
                                  and c2.customer_id <> m1.relatedcustomer_id)
                and not exists (select c3.customer_id from customer c3
                                where c3.masteraccount_id = m1.relatedcustomer_id
                                  and c3.customer_id <> m1.relatedcustomer_id)
                and not exists (select c4.customer_id from customer c4
                                where c4.commoncustomer_id = m1.relatedcustomer_id
                                  and c4.customer_id <> m1.relatedcustomer_id)
                and not exists (select c5.customer_id from customer c5
                                where c5.othercustomer_id = m1.relatedcustomer_id
                                  and c5.customer_id <> m1.relatedcustomer_id)
                and (select count(1)
                       from distributionpoint dp,
                            department de
                      where dp.department_id = de.department_id
                        and de.customer_id = m1.relatedcustomer_id
                        and dp.active = 'Y'
                        and de.active = 'Y') = 1  -- exactly 1 active cons.point
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id;
    exception
      when no_data_found then
        null;
    end;

   end if; -- step 1 pool items
   -------------
   if lv_number_nonpool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1c nonpool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    w.customer_id,
                    we.weareremployment_id,
                    we.distributionpoint_id,
                    case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select g.deliverypoint_id
                                    from garmentdispenser g
                                   where g.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u,
                    uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                    weareremployment we, wearer w
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.uniqueitem_id = unp.uniqueitem_id
                and we.weareremployment_id = unp.weareremployment_id
                and w.wearer_id = we.wearer_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                --and m1.multireadexception_id is null   --removed so that for rejected scans wearer is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 personalized garments (non pool)
   end retrieve_main_item_info; -- retrieve_main_item_info

  ----------------------------------------------------------------
   procedure decrease_delivery_variations is
   begin
    gv_code_block := 'Create delivery variations pool';
    writemultireaddebuglog(gv_code_block);
    MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
      USING (SELECT coalesce(p.distributionpoint_id, m1.distributionpoint_id, u.lastdistributionpoint_link_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.finishingmethod_id,
                    m1.plannedoutdate deliverydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.delayedevenexchange > 0  -- only those with delayed even exchange
                and coalesce(p.distributionpoint_id, m1.distributionpoint_id, u.lastdistributionpoint_link_id) is not null
                and m1.plpc_id is not null
                and m1.uniqueitem_id is not null
                and m1.plannedoutdate is not null -- delivery date found
                and m1.multireadexception_id is null
              GROUP BY coalesce(p.distributionpoint_id, m1.distributionpoint_id, u.lastdistributionpoint_link_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.finishingmethod_id,
                       m1.plannedoutdate
            ) MERGE_SUBQUERY
      ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
      AND d.product_id = MERGE_SUBQUERY.product_id
      AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
      AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
      AND d.deliverydate = MERGE_SUBQUERY.deliverydate
      AND d.packingnote_id is null
      AND d.processed = 'N'
      AND d.causenote_id is null
      AND d.updaterentqty = 'N'
      AND d.origin = 1
      AND d.soilcountsubtype = 7 -- inscan
      AND d.weborderline_id is null
      AND d.reference is null
      AND d.adjustmentreason_id is null
      AND d.reasoncode_id is null
      )
      WHEN MATCHED THEN
        UPDATE
           SET d.amount = d.amount - MERGE_SUBQUERY.qty,
               d.systemuser_id = gv_systemuser_id,
               d.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (deliveryvariations_id,
            product_id,
            packingnote_id,
            causenote_id,
            deliverydate,
            origin,
            amount,
            finishingmethod_id,
            fixedamount,
            distributionpoint_id,
            sizedefinition_id,
            reference,
            systemuser_id,
            processed,
            timestamp,
            updaterentqty,
            soilcountsubtype,
            processbusinessunit_id,
            internalprocessingbu_id)
        VALUES
          (seq_deliveryvariations.nextval,
           MERGE_SUBQUERY.product_id,
           null, -- packingnote
           null, -- cause note
           MERGE_SUBQUERY.deliverydate,
           1,    -- origin
           MERGE_SUBQUERY.qty * -1,
           MERGE_SUBQUERY.finishingmethod_id,
           'N',  -- fixedamount
           MERGE_SUBQUERY.distributionpoint_id,
           MERGE_SUBQUERY.sizedefinition_id,
           null, -- reference
           gv_systemuser_id,
           'N',  -- processed
           sysdate,
           'N',  -- update rent qty
           7,     -- soil count inscan
           f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
           gv_businessunit_id);
    exception
      when no_data_found then
        null;
   end decrease_delivery_variations;

   procedure create_rejectfromcustomer_scan is
   begin
    --create_rejectfromcustomer_scan
    writemultireaddebuglog('Create scan for Customer Reject');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, scandateoffset, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan,
             batchnumber )
    select seq_scan.nextval, -- new sequency because of inscan being created as well
           mb.businessunit_id,
           mbc.scantimestamp, -- other scan no seconds to be added
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           coalesce(mbc.distributionpoint_id, mbc.prev_distributionpoint_id) distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_reject,
           gc_status_id_in_circ,
           (select w.code from workstation w where w.workstation_id = mb.workstation_id), -- workstation code
           mbc.lastissuedate,
           mbc.lastinroute_id,
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           14, -- Reject from customer scan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           gv_pickupdate - trunc(mbc.scantimestamp), -- scandateoffset
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
           mbc.uniqueitembatchnumber
      from multireadscanbatch         mb
      join multireadscanbatchcontents mbc on mbc.multireadscanbatch_id = mb.multireadscanbatch_id
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
   end create_rejectfromcustomer_scan;

  procedure create_delivery_variations is
   begin
    begin
    gv_code_block := 'Create delivery variations pool';
    writemultireaddebuglog(gv_code_block);
    MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
      USING ( SELECT coalesce(p.distributionpoint_id, m1.distributionpoint_id, u.lastdistributionpoint_link_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.finishingmethod_id,
                    m1.plannedoutdate deliverydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.delayedevenexchange > 0  -- only those with delayed even exchange
                and coalesce(p.distributionpoint_id, m1.distributionpoint_id, u.lastdistributionpoint_link_id) is not null
                and m1.plpc_id is not null
                and m1.uniqueitem_id is not null
                and m1.plannedoutdate is not null -- delivery date found
                and m1.multireadexception_id is null
              GROUP BY coalesce(p.distributionpoint_id, m1.distributionpoint_id, u.lastdistributionpoint_link_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.finishingmethod_id,
                       m1.plannedoutdate
            ) MERGE_SUBQUERY
      ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
      AND d.product_id = MERGE_SUBQUERY.product_id
      AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
      AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
      AND d.deliverydate = MERGE_SUBQUERY.deliverydate
      AND d.packingnote_id is null
      AND d.processed = 'N'
      AND d.causenote_id is null
      AND d.updaterentqty = 'N'
      AND d.origin = 1
      AND d.soilcountsubtype = 3 -- Rejected
      AND d.weborderline_id is null
      AND d.reference is null
      AND d.adjustmentreason_id is null
      AND d.reasoncode_id is null
      )
      WHEN MATCHED THEN
        UPDATE
           SET d.amount = d.amount + MERGE_SUBQUERY.qty,
               d.systemuser_id = gv_systemuser_id,
               d.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (deliveryvariations_id,
            product_id,
            packingnote_id,
            causenote_id,
            deliverydate,
            origin,
            amount,
            finishingmethod_id,
            fixedamount,
            distributionpoint_id,
            sizedefinition_id,
            reference,
            systemuser_id,
            processed,
            timestamp,
            updaterentqty,
            soilcountsubtype,
            processbusinessunit_id,
            internalprocessingbu_id)
        VALUES
          (seq_deliveryvariations.nextval,
           MERGE_SUBQUERY.product_id,
           null, -- packingnote
           null, -- cause note
           MERGE_SUBQUERY.deliverydate,
           1,    -- origin
           MERGE_SUBQUERY.qty,
           MERGE_SUBQUERY.finishingmethod_id,
           'N',  -- fixedamount
           MERGE_SUBQUERY.distributionpoint_id,
           MERGE_SUBQUERY.sizedefinition_id,
           null, -- reference
           gv_systemuser_id,
           'N',  -- processed
           sysdate,
           'N',  -- update rent qty
           3,     -- Rejected
           f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
           gv_businessunit_id);
    exception
      when no_data_found then
        null;
    end;
   end create_delivery_variations;

   procedure update_uniqueitem_stay is
   begin
     --update_uniqueitem_stay
     writemultireaddebuglog('Update uniqueitem stay to Customer reject');
     merge into uniqueitem u
     using (select m1.uniqueitem_id, m1.scantimestamp
            from   multireadscanbatchcontents m1
            where  m1.multireadexception_id is null
            and    m1.multireadscanbatch_id = gv_multireadscanbatch_id
            and    (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)) merge_subquery
     on (u.uniqueitem_id = merge_subquery.uniqueitem_id)
     when matched then
       update
       set    u.lastscandate = merge_subquery.scantimestamp,
              u.staychangedate = merge_subquery.scantimestamp,
              u.prevstay_id = u.stay_id,
              u.stay_id = gc_stay_id_reject,
              u.systemuser_id = gv_systemuser_id,
              u.timestamp = sysdate;
   end update_uniqueitem_stay;

   -- Begin f_processinscanrejectbatch
   begin
     begin
        gv_main_code_block := 'Process Customer Reject Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items,
               sum(case when m.orpackitemyn='Y' then 1 else 0 end) number_orpack_items,
               sum(case when s.code='40' then 1 else 0 end) number_ragged_items,
               sum(case when m.unrelatedloan_id is not null then 1 else 0 end) number_loan_items
          into lv_number_pool_items,
               lv_number_nonpool_items,
               lv_number_orpack_items,
               lv_number_ragged_items,
               lv_number_loan_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
         end;
     end;
     --retrieve_main_item_info
     retrieve_main_item_info;
     --retrieve_item_info_for_delvar
     retrieve_item_info_for_delvar;
     --decrease_delivery_variations
     decrease_delivery_variations;
     --create_rejectfromcustomer_scan
     create_rejectfromcustomer_scan;
     --create_delivery_variations
     create_delivery_variations;
     --update_uniqueitem_stay
     update_uniqueitem_stay;
     --Create_reject_scans
     Create_reject_scans(14);  -- 14 = transactiontype reject from customer
     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
   end f_processinscanrejectbatch;

  -----------------------------------------------------------------------------------------
  function f_processoutscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_assigned_items number := 0;
   lv_number_loan_items     number := 0;

   ---------------------------------------------
   procedure outscan_update_unique_item is
   begin
     begin
      writemultireaddebuglog('Update_unique_item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    u1.status_id,
                    case when u1.status_id <> gc_status_id_in_circ
                     then trunc(m1.scantimestamp)
                     else u1.statuschangedate
                    end statuschangedate,
                    m1.distributionpoint_id,
                    m1.plannedoutdate
               FROM multireadscanbatchcontents m1, uniqueitem u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washestotal + 1
                                else u.washestotal
                                end,
                u.prevstatus_id = null,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_at_customer,
                u.planneddeliverydate = null,
                u.activestocklocation_id = null,
                u.deliveryfromstock = 'N',
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
      --
      writemultireaddebuglog('Update_unique_item_non_pool');
      MERGE INTO uniqueitemnonpool u
      USING (SELECT m1.uniqueitem_id,
                    m1.stay_id
               FROM multireadscanbatchcontents m1, uniqueitemnonpool u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.washesthisissue = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washesthisissue + 1
                                else u.washesthisissue
                                end,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- outscan_update_unique_item

   --------------------------------------------------------------
   procedure outscan_update_unique_item_rte is
   begin
     begin
      writemultireaddebuglog('Update_unique_item_route');
      MERGE INTO uniqueitemroute u
      USING (SELECT m1.uniqueitem_id,
                    m1.plannedoutdate,
                    m1.plannedoutroute_id,
                    m1.plannedoutstop_id
               FROM multireadscanbatchcontents m1, uniqueitem u
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.poolitemyn = 'N'
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET u.lastoutdate = MERGE_SUBQUERY.plannedoutdate,
               u.lastoutroute_id = MERGE_SUBQUERY.plannedoutroute_id,
               u.lastoutstop_id = MERGE_SUBQUERY.plannedoutstop_id,
               u.plannedoutdate = null,
               u.plannedoutroute_id = null,
               u.plannedoutstop_id = null,
               u.systemuser_id = gv_systemuser_id,
               u.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (uniqueitem_id,
            lastinroute_id,
            lastoutroute_id,
            plannedoutroute_id,
            lastindate,
            lastoutdate,
            plannedoutdate,
            systemuser_id,
            timestamp,
            lastinstop_id,
            lastoutstop_id,
            plannedoutstop_id
            )
        VALUES
          (MERGE_SUBQUERY.uniqueitem_id,
           null, -- lastinroute_id
           MERGE_SUBQUERY.plannedoutroute_id, -- lastoutroute_id
           null, -- plannedoutroute_id,
           null, -- lastindate,
           MERGE_SUBQUERY.plannedoutdate, -- lastoutdate
           null, -- plannedoutdate,
           gv_systemuser_id,
           sysdate,
           null, -- lastinstop_id
           MERGE_SUBQUERY.plannedoutstop_id, -- lastoutstop_id
           null -- plannedoutstop_id
           );
      --
      if gc_ss_routecontrolcreation >= 3 then
       begin
         writemultireaddebuglog('Create_Route Control');
         for vcursorR in  (SELECT m1.plannedoutdate,
                                  m1.plannedoutroute_id
                             FROM multireadscanbatchcontents m1
                            WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                              AND (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                              AND m1.plannedoutdate is not null
                              AND m1.plannedoutroute_id is not null
                              AND not exists (select 1
                                                from routecontrol r
                                               where r.route_id = m1.plannedoutroute_id
                                                 and r.originaldrivingdate = m1.plannedoutdate)
                              AND m1.multireadexception_id is null
                         GROUP BY m1.plannedoutdate,
                                  m1.plannedoutroute_id
                          )
         loop
           create_route_control(vcursorR.plannedoutroute_id,
                                vcursorR.plannedoutdate);
         end loop;
       exception
          when no_data_found then
            null;
       end;
      end if; -- gc_ss_routecontrolcreation >= 3
    exception
      when no_data_found then
        null;
    end;
   end; -- outscan_update_unique_item_route

   ---------------------------------------------
   procedure create_outscans is
   begin
    begin
    writemultireaddebuglog('Create delivery scans');
    insert into deliveryscan
           (businessunit_id,
            uniqueitem_link_id,
            scantimestamp,
            customer_link_id,
            weareremployment_link_id,
            distributionpoint_link_id,
            deliverypoint_link_id,
            product_link_id,
            sizedefinition_link_id,
            finishingmethod_id,
            routecontrol_id,
            packingnote_id,
            fromstock,
            previousstay_id,
            systemuser_id,
            timestamp,
            reasoncode_id,
            plantdepartment_id,
            chargewashing,
            locker_id,
            batchnumber,
            outscannodelivery,
            internalprocessingbu_id,
            scanstation,
            planneddeliverydate
           )
    select mb.businessunit_id,
           mbc.uniqueitem_id,
           mbc.scantimestamp,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.deliverypoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           mbc.finishingmethod_id,
           (select rc.routecontrol_id
              from routecontrol rc
             where rc.route_id = mbc.plannedoutroute_id
               and rc.drivingdate = mbc.plannedoutdate
           ), -- route control
           null, -- packingnote_id
           case when mbc.stay_id = gc_stay_id_in_stock
             then 'Y'
             else 'N'
           end,  -- FromStock
           mbc.stay_id,  -- prev stay
           gv_systemuser_id,
           sysdate,
           case when mbc.stay_id = gc_stay_id_in_stock
             then uf.reasoncode_id
             else null
            end, -- ReasonCode_ID
           nvl(works.plantdepartment_id,
               (select min(pd.plantdepartment_id)
                  from plantdepartment pd
                 where pd.plant_id = gv_plant_id
               )
              ), -- plant department
            case when ((mbc.stay_id = gc_stay_id_in_stock and c.chargewashfirstissue='N')
              or (w.dummyforpool = 'Y' and
                  (select nvl(max(cgd.noregularoutscan),0)
                   from customergarmentdispenser cgd
                   where cgd.customer_id = w.customer_id ) = 1  and
                  we.garmentdispenser_id is not null))
             then 'N'
             else 'Y'
           end,  -- ChargeWashing
           we.locker_id,
           null, -- batchnumber
           0,    -- OutscanNoDelivery
           gv_businessunit_id, -- internalprocessingbu_id
           works.code,
           mbc.plannedoutdate
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           weareremployment           we,
           wearer                     w,
           uniqueitemfixedinfo        uf,
           customer                   c,
           workstation                works
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and we.weareremployment_id = mbc.weareremployment_id
       and w.wearer_id = we.wearer_id
       and uf.uniqueitem_id = mbc.uniqueitem_id
       and c.customer_id = mbc.customer_id
       and works.workstation_id = mb.workstation_id
       and mbc.multireadexception_id is null;

    writemultireaddebuglog('Create_outscans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan)
    select mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_at_customer,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           mbc.plannedoutroute_id,  -- route_id
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           null, -- qualitygrade_id
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           2, -- transaction type outscan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
      end;

     create_scanflags;
   end create_outscans; -- create_outscans

   ----------------------------------------------------------------
   -- Begin f_processmultireadoutscanbatch
   begin
      begin
        gv_main_code_block := 'Process Outscan Batch';
        -- count number of items
        writemultireaddebuglog('Select contents');
        select sum(case when s.code='30' then 1 else 0 end) number_assigned_items,
               sum(case when m.unrelatedloan_id is not null then 1 else 0 end) number_loan_items
          into lv_number_assigned_items,
               lv_number_loan_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
    begin  -- exception block

     Outscan_update_unique_item;

     if gc_ss_scanbyroute='Y' then
       outscan_update_unique_item_rte;
     end if;

     Add_flag_for_decrease_max_inv;

     Create_flags_maxwash_spectreat;

     Create_outscans;

     Remove_Flags('OutScan');

     load_uniqueitem_buffer_info;
     insertupdate_uniqueitembufinfo(2);
     create_prodprocessbufscans(2);
     delete_uniqueitem_buffer_info; -- afterwards delete bufferinfo

     Create_reject_scans(2);  -- 2 = transactiontype outscan

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(2, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processoutscanbatch;

  -----------------------------------------------------------------------------------------
  function f_processoutscanpoolbatch(fp_exchangecart_id in number) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_year number(4);
   lv_week number(2);
   ---------------------------------------------
   procedure retrieve_item_info is

   begin
    -- find old plpc for items that where not scanned in
    begin
    writemultireaddebuglog('Retrieve item info step 1a old plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1, distributionpoint dip, department dep
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.prev_distributionpoint_id is not null
                and dip.distributionpoint_id = m1.prev_distributionpoint_id
                and dep.department_id = dip.department_id
                and m1.poolitemyn='Y'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.prev_plpc_id = MERGE_SUBQUERY.productlistpercustomer_id;
    exception
      when no_data_found then
        null;
    end;

    -- populate scan_ID
    begin
    writemultireaddebuglog('Retrieve item info step 2 scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null;
    exception
      when no_data_found then
        null;
    end;

    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 primID and secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid,
                    u.primaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su, uniqueitem u
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode         = MERGE_SUBQUERY.primaryid,
               m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;
   if fp_exchangecart_id is null then
     begin
       lv_year := null;
       lv_week := null;
     end;
   else
   begin
     --Determine the last ChippingRate.Year, ChippingRate.Week
     --selecting the Max(ChippingRate_ID) for the current BusinessUnit
     select max(cr.year), max(cr.week)
     into   lv_year, lv_week
     from   chippingrate cr
     where  cr.businessunit_id = gv_businessunit_id
     and    cr.chippingrate_id =
            (select max(crx.chippingrate_id)
              from   chippingrate crx
              where  crx.businessunit_id = cr.businessunit_id);
   exception
     when no_data_found then
       lv_year := null;
       lv_week := null;
   end;
   end if;
   end; -- retrieve_item_info

   ---------------------------------------------
   procedure populate_childpackingnote_id is
   -- this procedure distributes the items to the child packingnotes of the bulk packingnote
   -- and populates the childpackingnote_id in multireadscanbatchcontents
   -- this column is used further down for linking uniqueitems and scans to the child packingnote
   -- and assigns them to the distribution point of the child packingnote.
    lv_childpnlfound boolean;
    lv_childpnlexist boolean;
    lv_lastchildpnl  number;

    begin
       for m_cur in
             (select m1.multireadscanbatch_id, m.packingnote_id, m1.idcode,
                    m1.product_id, m1.sizedefinition_id, m1.finishingmethod_id
               from multireadscanbatchcontents m1, multireadscanbatch m
              where m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
--                and m1.uniqueitem_id is not null   -- removed so also non uniques get allocated
                and m1.poolitemyn='Y'
                and m1.multireadexception_id is null
--                and m1.packingnoteline_id > 0      -- removed so that also new lines for not ordered items get allocated
                and m1.childpackingnoteline_id is null
              order by m1.packingnoteline_id) loop
          lv_childpnlfound := false;
          lv_childpnlexist := false;
          for p_cur in
                   (select pnl.packingnoteline_id, pnl.tobedeliveredamount, pnl.deliveredamount
                      from packingnoteline pnl, packingnote pn
                     where pnl.packingnote_id = pn.packingnote_id
                       and pn.bulkpackingnote_id = m_cur.packingnote_id
                       and pnl.product_id = m_cur.product_id
                       and pnl.sizedefinition_id = m_cur.sizedefinition_id
                       and pnl.finishingmethod_id = m_cur.finishingmethod_id
                     order by pn.notenumber
                   ) loop
                  lv_childpnlexist := true;
                  if p_cur.tobedeliveredamount > p_cur.deliveredamount then
                    update packingnoteline pl
                       set pl.deliveredamount = nvl(pl.scannedqty,0) + 1,
                           pl.scannedqty = nvl(pl.scannedqty,0) + 1,
                           pl.timestamp = sysdate
                     where pl.packingnoteline_id = p_cur.packingnoteline_id;
                    update multireadscanbatchcontents mbc
                       set mbc.childpackingnoteline_id = p_cur.packingnoteline_id
                     where mbc.multireadscanbatch_id = m_cur.multireadscanbatch_id
                       and mbc.idcode = m_cur.idcode;
                    lv_childpnlfound := true;
                    exit;   -- exit loop
                  end if;
          end loop; -- inner
          if not lv_childpnlfound and lv_childpnlexist then
            -- link overdeliveries to the last PNL
            begin
              select x.packingnoteline_id
                into lv_lastchildpnl
                from (select pnl.packingnoteline_id
                        from packingnoteline pnl, packingnote pn
                       where pnl.packingnote_id = pn.packingnote_id
                         and pn.bulkpackingnote_id = m_cur.packingnote_id
                         and pnl.product_id = m_cur.product_id
                         and pnl.sizedefinition_id = m_cur.sizedefinition_id
                         and pnl.finishingmethod_id = m_cur.finishingmethod_id
                       order by pn.notenumber desc) x
               where rownum = 1;
            exception
             when no_data_found then
                 lv_lastchildpnl := null;
            end;
            if lv_lastchildpnl is not null then
              update packingnoteline pl
                 set pl.deliveredamount = nvl(pl.scannedqty,0) + 1,
                     pl.scannedqty = nvl(pl.scannedqty,0) + 1,
                     pl.timestamp = sysdate
               where pl.packingnoteline_id = lv_lastchildpnl;
              update multireadscanbatchcontents mbc
                 set mbc.childpackingnoteline_id = lv_lastchildpnl
               where mbc.multireadscanbatch_id = m_cur.multireadscanbatch_id
                 and mbc.idcode = m_cur.idcode;
             end if; --  lv_lastchildpnl is not null
          end if; -- not lv_childpnlfound and lv_childpnlexist
      end loop; -- outer loop on multiread scan batch contents
   end;

   ---------------------------------------------
   procedure decrease_onsite_inventory is
   begin
    begin
    writemultireaddebuglog('Decrease onsite inventory');
    MERGE INTO onsiteinventoryadjustment o
      USING (SELECT p.productlistperdistribpoint_id,
                    5 origin,
                    trunc(sysdate) inventorydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1,
                    uniqueitem u,
                    productlistperdistribpoint p,
                    productlistpercustomer plpc
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.stay_id = gc_stay_id_at_customer -- only for items not scanned in
                and m1.poolitemyn ='Y'
                and u.uniqueitem_id = m1.uniqueitem_id
                and p.distributionpoint_id = m1.prev_distributionpoint_id
                and p.product_id = m1.product_id
                and p.sizedefinition_id = m1.sizedefinition_id
                and p.finishingmethod_id = m1.prev_finishingmethod_id
                and plpc.productlistpercustomer_id = m1.prev_plpc_id
                and plpc.soilcountmethod <> 0
                and m1.multireadexception_id is null
              GROUP BY p.productlistperdistribpoint_id
            ) MERGE_SUBQUERY
      ON (o.productlistperdistribpoint_id = MERGE_SUBQUERY.productlistperdistribpoint_id
      AND o.origin                        = MERGE_SUBQUERY.origin
      AND o.inventorydate                 = MERGE_SUBQUERY.inventorydate
      AND o.reference is null)
      WHEN MATCHED THEN
        UPDATE
           SET o.quantity = o.quantity - MERGE_SUBQUERY.qty,
               o.systemuser_id = gv_systemuser_id,
               o.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
          (onsiteinventoryadjustment_id,
           productlistperdistribpoint_id,
           origin,
           inventorydate,
           quantity,
           reference,
           systemuser_id,
           timestamp,
           invoiceheader_id)
        VALUES
          (seq_onsiteinventoryadjustment.nextval,
           MERGE_SUBQUERY.productlistperdistribpoint_id,
           MERGE_SUBQUERY.origin,
           MERGE_SUBQUERY.inventorydate,
           MERGE_SUBQUERY.qty * -1,
           null, -- reference
           gv_systemuser_id,
           sysdate,
           null);
    exception
      when no_data_found then
        null;
    end;
   end; --decrease_onsite_inventory

   procedure create_delivery_variations is
   begin
    begin
    writemultireaddebuglog('Create delivery variations pool');
    MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
      USING (SELECT nvl(pn.distributionpoint_id,m1.prev_distributionpoint_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.prev_finishingmethod_id finishingmethod_id,
                    p.packingnote_id,
                    p.deliverydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote pn on pn.notenumber = u.lastdeliverynotenumber,
                    multireadscanbatch mb,
                    packingnote p,
                    productlistpercustomer plpc
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.packingnote_id = mb.packingnote_id
                and m1.prev_distributionpoint_id is not null
                and m1.poolitemyn = 'Y'
                and plpc.productlistpercustomer_id = m1.prev_plpc_id
                and m1.stay_id = gc_stay_id_at_customer -- only for items not scanned in
                and plpc.delayedevenexchange > 0  -- only those with delayed even exchange
                and m1.prev_finishingmethod_id is not null
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
              GROUP BY nvl(pn.distributionpoint_id,m1.prev_distributionpoint_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.prev_finishingmethod_id,
                       p.packingnote_id,
                       p.deliverydate
            ) MERGE_SUBQUERY
      ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
      AND d.product_id = MERGE_SUBQUERY.product_id
      AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
      AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
      AND d.deliverydate = MERGE_SUBQUERY.deliverydate
      AND d.packingnote_id is null
      AND d.processed = 'N'
      AND d.causenote_id = MERGE_SUBQUERY.packingnote_id
      AND d.updaterentqty = 'N'
      AND d.origin = 1
      AND d.soilcountsubtype = 7 -- inscan
      AND d.weborderline_id is null
      AND d.reference is null
      AND d.adjustmentreason_id is null
      AND d.reasoncode_id is null
      )
      WHEN MATCHED THEN
        UPDATE
           SET d.amount = d.amount + MERGE_SUBQUERY.qty,
               d.systemuser_id = gv_systemuser_id,
               d.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (deliveryvariations_id,
            product_id,
            packingnote_id,
            causenote_id,
            deliverydate,
            origin,
            amount,
            finishingmethod_id,
            fixedamount,
            distributionpoint_id,
            sizedefinition_id,
            reference,
            systemuser_id,
            processed,
            timestamp,
            updaterentqty,
            soilcountsubtype,
            processbusinessunit_id,
            internalprocessingbu_id)
        VALUES
          (seq_deliveryvariations.nextval,
           MERGE_SUBQUERY.product_id,
           null, -- packingnote
           MERGE_SUBQUERY.packingnote_id, -- cause note
           MERGE_SUBQUERY.deliverydate,
           1,    -- origin
           MERGE_SUBQUERY.qty,
           MERGE_SUBQUERY.finishingmethod_id,
           'N',  -- fixedamount
           MERGE_SUBQUERY.distributionpoint_id,
           MERGE_SUBQUERY.sizedefinition_id,
           null, -- reference
           gv_systemuser_id,
           'N',  -- processed
           sysdate,
           'N',  -- update rent qty
           7,     -- soilcount subtype inscan
           f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
           gv_businessunit_id);
    exception
      when no_data_found then
        null;
    end;
   end; -- create_delivery_variations

   ---------------------------------------------
   procedure create_upd_packingnote_lines is
   lv_highestchildpn number;
   lv_charge_washes_garmentdisp varchar2(1);

   procedure create_packingnote_lines(fp_packingnote_id number, fp_is_child_YN varchar2) is
   begin
    begin
      writemultireaddebuglog('Create Packingnote Lines');
      INSERT INTO packingnoteline pl
             (packingnoteline_id,
              product_id,
              packingsequence,
              standardamount,
              variationamount,
              finishingmethod_id,
              deliveredamount,
              price,
              discount,
              packingnote_id,
              sizedefinition_id,
              systemuser_id,
              location,
              timestamp,
              remarkforpackinginstructions,
              tobedeliveredamount,
              customcode,
              customdescription,
              replacementqty,
              autoreplacementqty,
              updaterentqty,
              adjustmentreason_id,
              origin,
              putuptype,
              freeofchargereason_id,
              nochargefirstissue,
              nochargeactiveseason,
              auxiliarystatus,
              deliveredcogqty,
              amount,
              taxgroupcode,
              bundleqty,
              nochargefirstissuecog,
              scannedbundles,
              pricecog,
              mountingorderline_id,
              invoiceheader_id,
              nodeliveryamount,
              nochargeprevrejected,
              nochargeprevshortage,
              deliveredamountnopickup,
              creationtimestamp,
              creationsystemuser_id,
              scannedqty,
              nochargegddeliveryforpool,
              nochargegddeliveryforpoolcog)
           SELECT seq_packingnoteline.nextval, --  packingnoteline_id
                  x.product_id,
                  x.packingsequence,
                  0, -- standardamount
                  0, -- variationamount
                  x.finishingmethod_id,
                  case when fp_is_child_YN='N'
                   then x.qty -- deliveredamount
                   else 0
                  end,
                  null,     -- price
                  0,        -- discount
                  fp_packingnote_id,
                  x.sizedefinition_id,
                  gv_systemuser_id, --systemuser_id
                  null,             -- location
                  sysdate,          -- timestamp
                  null,             -- remarkforpackinginstructions
                  0,                -- tobedeliveredamount
                  x.customcode,
                  x.customdescription,
                  0,    -- replacementqty
                  0,    -- autoreplacementqty
                  0,    -- updaterentqty
                  null, -- adjustmentreason_id
                  1,    -- origin 1 means manually added
                  case when x.specificputuptype <> 0
                    then x.specificputuptype
                    else case when nvl((select pp.putuptype
                                          from plantproductsettings pp
                                         where pp.plant_id = gv_plant_id
                                           and pp.product_id = x.product_id),0) = 0
                                then x.putuptype
                                else (select pp.putuptype
                                          from plantproductsettings pp
                                         where pp.plant_id = gv_plant_id
                                           and pp.product_id = x.product_id)
                         end
                  end,  -- putuptype
                  null, -- freeofchargereason_id
                  0, -- nochargefirstissue
                  0, -- nochargeactiveseason
                  0, -- auxiliarystatus
                  case when fp_is_child_YN='N'
                   then x.cogqty -- deliveredcogqty
                   else 0
                  end,
                  0, -- amount
                  null, -- taxgroupcode
                  0, -- bundleqty
                  0, -- nochargefirstissuecog
                  0, -- scannedbundles
                  null, -- pricecog
                  null, -- mountingorderline_id
                  null, -- invoiceheader_id
                  0, -- nodeliveryamount
                  0, -- nochargeprevrejected
                  0, -- nochargeprevshortage
                  0, -- deliveredamountnopickup
                  sysdate, -- creationtimestamp
                  gv_systemuser_id, -- creationsystemuser_id
                  case when fp_is_child_YN='N'
                   then x.qty -- scannedqty
                   else 0
                  end,
                  case when fp_is_child_YN='N'
                   then x.nochargegddeliveryforpool
                   else 0
                  end,
                  case when fp_is_child_YN='N'
                   then x.nochargegddeliveryforpoolcog
                   else 0
                  end
               FROM (SELECT m1.packingsequence,
                            m1.product_id,
                            m1.sizedefinition_id,
                            plpc.finishingmethod_id,
                            plpc.customcode,
                            plpc.customdescription,
                            plpc.specificputuptype,
                            p.putuptype,
                            count(*) qty,
                            sum(case when (plpc.billingmethod in (3,4,5)
                                       or (plpc.billingmethod = 1 and gv_ss_chargewashcogchgperweek='Y'))
                                      and p.typeofmerchandise in (1,2)
                                      and plpc.chargewashesonlyforcog in (1,3)
                                      and m1.customerowned = 'Y'
                                      then 1
                                      else 0
                                end) cogqty,
                            sum(case when m1.poolitemyn='Y'
                                      and lv_charge_washes_garmentdisp = 'N'
                                      and (m1.customerowned = 'N'
                                       or (m1.customerowned = 'Y'
                                      and not ((plpc.billingmethod in (3,4,5)
                                                or (plpc.billingmethod = 1 and gv_ss_chargewashcogchgperweek='Y'))
                                                and p.typeofmerchandise in (1,2)
                                                and plpc.chargewashesonlyforcog in (1,3)
                                              )))
                                then 1
                                else 0
                            end) nochargegddeliveryforpool,
                            sum(case when m1.poolitemyn='Y'
                                      and lv_charge_washes_garmentdisp = 'N'
                                      and m1.customerowned = 'Y'
                                      and ((plpc.billingmethod in (3,4,5)
                                            or (plpc.billingmethod = 1 and gv_ss_chargewashcogchgperweek='Y'))
                                            and p.typeofmerchandise in (1,2)
                                            and plpc.chargewashesonlyforcog in (1,3)
                                          )
                                then 1
                                else 0
                            end)  nochargegddeliveryforpoolcog
                       FROM multireadscanbatchcontents m1,
                            productlistpercustomer plpc, product p
                      WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                        and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                        and m1.multireadexception_id is null
                        and m1.packingnoteline_id is null
                        and plpc.productlistpercustomer_id = m1.plpc_id
                        and p.product_id = m1.product_id
                   GROUP BY m1.packingsequence,
                            m1.product_id,
                            m1.sizedefinition_id,
                            plpc.finishingmethod_id,
                            plpc.customcode,
                            plpc.customdescription,
                            plpc.specificputuptype,
                            p.putuptype
                            ) x;
    exception
      when no_data_found then
        null;
    end;
   end; -- create packingnotelines


   begin -- main create_upd_packingnote_lines
    begin

      begin
         select 'N'
           into lv_charge_washes_garmentdisp
            from packingnote p,
                 distributionpoint dp,
                 department d,
                 garmentdispenser gd,
                 customergarmentdispenser cgd
           where p.packingnote_id = gv_packingnote_id
             and dp.distributionpoint_id = p.distributionpoint_id
             and d.department_id = dp.department_id
             and gd.customer_id = d.customer_id
             and gd.deliverypoint_id = dp.deliverypoint_id
             and cgd.customer_id = d.customer_id
             and cgd.processtrans2asoutscan = 'Y'
             and gd.usedforpool = 'Y'
             and ((cgd.customerrelatedpool = 'Y' and cgd.noregularoutscancustpool = 1)
               or (cgd.generalpool = 'Y' and cgd.noregularoutscangenpool = 1));
      exception
          when no_data_found then
            lv_charge_washes_garmentdisp := 'Y';
      end;


    create_packingnote_lines(gv_packingnote_id,'N'); -- child note = N

    if gv_isbulkshipmentnote='Y' then -- then also create packingnotelines for the childPN note with highest #
      begin
          select x.packingnote_id
            into lv_highestchildpn
            from (select pn.packingnote_id
                  from packingnote pn, multireadscanbatch mb
                  where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and pn.bulkpackingnote_id = mb.packingnote_id
                  order by pn.notenumber desc) x
           where rownum = 1;
        exception
         when no_data_found then
             lv_highestchildpn := null;
      end;
      if lv_highestchildpn is not null
       then create_packingnote_lines(lv_highestchildpn,'Y'); -- child note = Y
      end if;
    end if; -- if gv_isbulkshipmentnote=Y

    writemultireaddebuglog('Update Packingnote Lines no Plpc');
    MERGE INTO packingnoteline p
      USING (SELECT m.packingnoteline_id,
                    count(*) qty
               FROM multireadscanbatchcontents m
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                AND m.multireadexception_id is null
                AND m.packingnoteline_id is not null
                AND m.partofpackyn <> 'Y'
                AND m.processedyn <> 'Y'
                AND m.plpc_id is null
              GROUP BY m.packingnoteline_id
            ) MERGE_SUBQUERY
      ON (p.packingnoteline_id = MERGE_SUBQUERY.packingnoteline_id)
      WHEN MATCHED THEN
        UPDATE
           SET p.deliveredamount = nvl(p.scannedqty,0) + MERGE_SUBQUERY.qty,
               p.scannedqty = nvl(p.scannedqty,0) + MERGE_SUBQUERY.qty,
               p.systemuser_id = gv_systemuser_id,
               p.timestamp = sysdate;

    writemultireaddebuglog('Update Packingnote Lines with Plpc');
    MERGE INTO packingnoteline p
      USING (SELECT m.packingnoteline_id,
                    count(*) qty,
                    sum(case when (plpc.billingmethod in (3,4,5)
                               or (plpc.billingmethod = 1 and gv_ss_chargewashcogchgperweek='Y'))
                              and p.typeofmerchandise in (1,2)
                              and plpc.chargewashesonlyforcog in (1,3)
                              and m.customerowned = 'Y'
                              then 1
                              else 0
                        end) cogqty,
                    sum(case when m.poolitemyn='Y'
                              and lv_charge_washes_garmentdisp = 'N'
                              and (m.customerowned = 'N'
                               or (m.customerowned = 'Y'
                              and not ((plpc.billingmethod in (3,4,5)
                                        or (plpc.billingmethod = 1 and gv_ss_chargewashcogchgperweek='Y'))
                                        and p.typeofmerchandise in (1,2)
                                        and plpc.chargewashesonlyforcog in (1,3)
                                      )))
                        then 1
                        else 0
                    end) nochargegddeliveryforpool,
                    sum(case when m.poolitemyn='Y'
                              and lv_charge_washes_garmentdisp = 'N'
                              and m.customerowned = 'Y'
                              and ((plpc.billingmethod in (3,4,5)
                                    or (plpc.billingmethod = 1 and gv_ss_chargewashcogchgperweek='Y'))
                                    and p.typeofmerchandise in (1,2)
                                    and plpc.chargewashesonlyforcog in (1,3)
                                  )
                        then 1
                        else 0
                    end)  nochargegddeliveryforpoolcog
               FROM multireadscanbatchcontents m,
                    productlistpercustomer plpc, product p
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                AND m.multireadexception_id is null
                AND m.packingnoteline_id is not null
                AND m.partofpackyn <> 'Y'
                AND m.processedyn <> 'Y'
                AND plpc.productlistpercustomer_id = m.plpc_id
                AND p.product_id = m.product_id
              GROUP BY m.packingnoteline_id
            ) MERGE_SUBQUERY
      ON (p.packingnoteline_id = MERGE_SUBQUERY.packingnoteline_id)
      WHEN MATCHED THEN
        UPDATE
           SET p.deliveredamount = nvl(p.scannedqty,0) + MERGE_SUBQUERY.qty,
               p.scannedqty = nvl(p.scannedqty,0) + MERGE_SUBQUERY.qty,
               p.deliveredcogqty = p.deliveredcogqty + MERGE_SUBQUERY.cogqty,
               p.nochargegddeliveryforpool = nvl(p.nochargegddeliveryforpool,0) + MERGE_SUBQUERY.nochargegddeliveryforpool,
               p.nochargegddeliveryforpoolcog = nvl(p.nochargegddeliveryforpoolcog,0) + MERGE_SUBQUERY.nochargegddeliveryforpoolcog,
               p.systemuser_id = gv_systemuser_id,
               p.timestamp = sysdate;

    -- update scannedqty in packingnotelinecontent
    writemultireaddebuglog('Update Packingnote Line Contents');
    MERGE INTO packingnotelinecontent plc
      USING (SELECT m.packingnoteline_id,
                    m.product_id,
                    m.sizedefinition_id,
                    m.finishingmethod_id,
                    count(*) qty
               FROM multireadscanbatchcontents m
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                AND (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                AND m.multireadexception_id is null
                AND m.packingnoteline_id is not null
                AND m.partofpackyn = 'Y'
                AND m.processedyn <> 'Y'
           GROUP BY m.packingnoteline_id,
                    m.product_id,
                    m.sizedefinition_id,
                    m.finishingmethod_id
            ) MERGE_SUBQUERY
      ON (plc.packingnoteline_id = MERGE_SUBQUERY.packingnoteline_id and
          plc.product_id = MERGE_SUBQUERY.product_id and
          plc.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id and
          plc.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id)
      WHEN MATCHED THEN
        UPDATE
           SET plc.scannedqty = nvl(plc.scannedqty,0) + MERGE_SUBQUERY.qty,
               plc.systemuser_id = gv_systemuser_id,
               plc.timestamp = sysdate;

      -- link multiread scan batch contents to just created packingnoteline
      begin
      writemultireaddebuglog('Update Packingnoteline for newly created packingnotelines');
      MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.multireadscanbatch_id,
                      m1.subbatchnumber,
                      m1.uniqueitem_id,
                      pl.packingnoteline_id
                 FROM multireadscanbatch mb,
                      multireadscanbatchcontents m1,
                      packingnoteline pl
                WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                  and m1.multireadexception_id is null
                  and m1.packingnoteline_id is null
                  and m1.plpc_id is not null
                  and pl.packingnote_id = mb.packingnote_id
                  and pl.product_id = m1.product_id
                  and pl.sizedefinition_id = m1.sizedefinition_id
                  and pl.finishingmethod_id = m1.finishingmethod_id
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
        AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.packingnoteline_id = MERGE_SUBQUERY.packingnoteline_id;
      exception
        when no_data_found then
          null;
      end;

      writemultireaddebuglog('Mark Packingnotelines as processed');
      UPDATE multireadscanbatchcontents m1
         SET m1.processedyn = 'Y'
--         SET m1.packingnoteline_id = -1
       WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
         and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         and m1.multireadexception_id is null;

      writemultireaddebuglog('Set packingnote in progress');
      UPDATE packingnote p
         SET p.status_id = (select status_id from status s where s.statustype='PN' and s.code='20') -- In Progress
       WHERE p.packingnote_id = (select b.packingnote_id
                                   from multireadscanbatch b
                                  where b.multireadscanbatch_id = gv_multireadscanbatch_id)
         AND p.status_id = (select status_id from status s where s.statustype='PN' and s.code='10'); -- Packingnote
      if SQL%ROWCOUNT = 1 then
        UPDATE routecontrol rc
           SET rc.packingstatus = 3 -- in progress
         WHERE rc.routecontrol_id = (select p.routecontrol_id
                                       from multireadscanbatch b, packingnote p
                                      where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                        and p.packingnote_id = b.packingnote_id)
           AND rc.packingstatus = 2; -- put up printed
      end if;

      if gv_isbulkshipmentnote='Y' or gv_iscustomernote='Y' then -- then also mark child packingnotes as in progress
        UPDATE packingnote p
           SET p.status_id = (select status_id from status s where s.statustype='PN' and s.code='20') -- In Progress
         WHERE p.bulkpackingnote_id = (select b.packingnote_id
                                     from multireadscanbatch b
                                    where b.multireadscanbatch_id = gv_multireadscanbatch_id)
           AND p.status_id = (select status_id from status s where s.statustype='PN' and s.code='10'); -- Packingnote
        UPDATE routecontrol rc
           SET rc.packingstatus = 3 -- in progress
         WHERE rc.routecontrol_id in (select p.routecontrol_id
                                       from multireadscanbatch b, packingnote p
                                      where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                        and p.bulkpackingnote_id = b.packingnote_id)
           AND rc.packingstatus = 2; -- put up printed
      end if; -- if gv_isbulkshipmentnote=Y or gv_iscustomernote='Y'

     if gv_iscustomernote='Y' then -- don't allow to outscan on child customer packing notes if scanning on customer pn
        UPDATE packingnote p
           SET p.availableforoutscan = 1
         WHERE p.bulkpackingnote_id = (select b.packingnote_id
                                         from multireadscanbatch b
                                        where b.multireadscanbatch_id = gv_multireadscanbatch_id)
           AND p.packingnote_id <> p.bulkpackingnote_id
           AND p.availableforoutscan = 0;
      end if;

      update packingnote pn -- don't allow to outscan on customer pn if scanning on child customer pn
         set pn.availableforoutscan = 1
       where pn.packingnote_id =
             (select a.bulkpackingnote_id
                from packingnote a, multireadscanbatch b
               where a.packingnote_id =  b.packingnote_id
               and b.multireadscanbatch_id = gv_multireadscanbatch_id)
             and pn.availableforoutscan = 0
             and pn.origin = 16;

    exception
      when no_data_found then
        null;
    end;
   end; -- Create_upd_packingnotelines

   ---------------------------------------------
   -- ABS-21481
   procedure update_bundle_status is
   begin
     writemultireaddebuglog('Update Bundle Status');
     -- set bundle status to 2: delivered
     update uhfbundle b
        set b.deliverystatus = 2 -- delivered
      where b.uhfbundle_id in
             (select distinct mbc.uhfbundle_id
                from multireadscanbatchcontents mbc
               where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                 and mbc.bundleaddedyn = 'Y'
                 and mbc.multireadexception_id is null -- only those that have at least one item approved
             );
     commit;
   end; -- update_bundle_status
   --- end ABS-21481

   ---------------------------------------------
   procedure outscanpool_update_unique_item is
   begin
    begin
      writemultireaddebuglog('Update Unique Pool Item');
      -- For items not linked to a child packingnoteline
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    case when m1.secondaryid is null
                      then m.businessunit_id -- update BU upon outscan only for pool items without secID
                      else m1.businessunit_id -- original BU
                    end businessunit_id,
                    m1.stay_id,
                    u1.status_id,
                    u1.distributionpoint_id,
                    u1.lastdistributionpoint_link_id,
                    m1.distributionpoint_id new_distributionpoint_id,
                    m1.finishingmethod_id,
                    m1.prev_finishingmethod_id,
                    p.notenumber,
                    p.deliverydate
               FROM multireadscanbatch m, multireadscanbatchcontents m1, packingnote p, uniqueitem u1
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.packingnote_id = m.packingnote_id
                and m1.uniqueitem_id = u1.uniqueitem_id
                and m1.poolitemyn = 'Y'
                and m1.multireadexception_id is null
                and m1.childpackingnoteline_id is null -- not linked to a child packingnoteline
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.businessunit_id = MERGE_SUBQUERY.businessunit_id,
                u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washestotal + 1
                                else u.washestotal
                                end,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_at_customer,
                u.finishingmethod_id = case when gs_ss_changefmforpoolmultiread = 0
                                              OR gv_dbSetting in ('ANG','TLK')
                                              OR gv_outscantrackonly = 'Y' -- then do not update finishingmethod
                                         then MERGE_SUBQUERY.prev_finishingmethod_id
                                         else MERGE_SUBQUERY.finishingmethod_id
                                       end,
                u.distributionpoint_id = MERGE_SUBQUERY.new_distributionpoint_id,
                u.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                    then MERGE_SUBQUERY.distributionpoint_id
                                                    else MERGE_SUBQUERY.lastdistributionpoint_link_id
                                                  end,
                u.unrelatedloan_id = null,       -- disconnect from unrelated loan
                u.planneddeliverydate = null,
                u.activestocklocation_id = null,
                u.deliveryfromstock = 'N',
                u.lastdeliverynotenumber = MERGE_SUBQUERY.notenumber,
                u.lastdeliverydate = MERGE_SUBQUERY.deliverydate,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;

      if gv_isbulkshipmentnote='Y' or gv_iscustomernote='Y' then
        writemultireaddebuglog('Update Unique Pool Item link to Child Packingnote');
        -- for items linked to a child packingnoteline
        MERGE INTO uniqueitem u
        USING (SELECT m1.uniqueitem_id,
                      m1.scantimestamp,
                      case when m1.secondaryid is null
                        then m.businessunit_id -- update BU upon outscan only for pool items without secID
                        else m1.businessunit_id -- original BU
                      end businessunit_id,
                      m1.stay_id,
                      u1.status_id,
                      u1.distributionpoint_id,
                      u1.lastdistributionpoint_link_id,
                      p.distributionpoint_id new_distributionpoint_id, -- distribution point of child packingnote
                      m1.finishingmethod_id,
                      m1.prev_finishingmethod_id,
                      p.notenumber,
                      p.deliverydate
                 FROM multireadscanbatch m, multireadscanbatchcontents m1,
                      packingnote p, packingnoteline pnl, uniqueitem u1
                WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = m.multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                  and m1.uniqueitem_id = u1.uniqueitem_id
                  and m1.poolitemyn = 'Y'
                  and m1.multireadexception_id is null
                  and pnl.packingnoteline_id = m1.childpackingnoteline_id
                  and p.packingnote_id = pnl.packingnote_id
              ) MERGE_SUBQUERY
        ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET  u.businessunit_id = MERGE_SUBQUERY.businessunit_id,
                  u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                  u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                  u.washestotal = case when gc_ss_countwashesat = 'O'
                                         or (gc_ss_countwashesat='I'
                                        and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                        and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                  then u.washestotal + 1
                                  else u.washestotal
                                  end,
                  u.prevstay_id = MERGE_SUBQUERY.stay_id,
                  u.stay_id = gc_stay_id_at_customer,
                  u.finishingmethod_id = case when gs_ss_changefmforpoolmultiread = 0 OR gv_dbSetting in ('ANG','TLK')
                                           then MERGE_SUBQUERY.prev_finishingmethod_id
                                           else MERGE_SUBQUERY.finishingmethod_id
                                         end,
                  u.distributionpoint_id = MERGE_SUBQUERY.new_distributionpoint_id,
                  u.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                      then MERGE_SUBQUERY.distributionpoint_id
                                                      else MERGE_SUBQUERY.lastdistributionpoint_link_id
                                                    end,
                  u.unrelatedloan_id = null,       -- disconnect from unrelated loan
                  u.planneddeliverydate = null,
                  u.activestocklocation_id = null,
                  u.deliveryfromstock = 'N',
                  u.lastdeliverynotenumber = MERGE_SUBQUERY.notenumber,
                  u.lastdeliverydate = MERGE_SUBQUERY.deliverydate,
                  u.systemuser_id = gv_systemuser_id,
                  u.timestamp = sysdate;
    end if; -- gv_isbulkshipmentnote='Y' or gv_iscustomernote='Y'

    if gv_outscangarmentsaswell then
      writemultireaddebuglog('Update Unique Garment');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    u1.status_id,
                    case when u1.status_id <> gc_status_id_in_circ
                     then trunc(m1.scantimestamp)
                     else u1.statuschangedate
                    end statuschangedate,
                    m1.distributionpoint_id,
                    m1.plannedoutdate,
                    p.notenumber,
                    p.deliverydate
               FROM multireadscanbatch m, multireadscanbatchcontents m1,  packingnote p, uniqueitem u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.poolitemyn = 'N'
                and m1.deliveryscantimestamp is null -- no pending deliverys scans
                and m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.packingnote_id = m.packingnote_id
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washestotal + 1
                                else u.washestotal
                                end,
                u.prevstatus_id = null,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_at_customer,
                u.planneddeliverydate = null,
                u.activestocklocation_id = null,
                u.deliveryfromstock = 'N',
                u.lastdeliverynotenumber = MERGE_SUBQUERY.notenumber,
                u.lastdeliverydate = MERGE_SUBQUERY.deliverydate,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
      --
      writemultireaddebuglog('Update Unique Itemn Non Pool');
      MERGE INTO uniqueitemnonpool u
      USING (SELECT m1.uniqueitem_id,
                    m1.stay_id
               FROM multireadscanbatchcontents m1, uniqueitemnonpool u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.deliveryscantimestamp is null -- no pending deliverys scans
                and m1.poolitemyn = 'N'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.washesthisissue = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washesthisissue + 1
                                else u.washesthisissue
                                end,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    end if; -- if gv_outscangarmentsaswell

    writemultireaddebuglog('Update unique item loss');
    merge into uniqueitemloss u
    using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
             from multireadscanbatchcontents m, uniqueitemloss ul
            where m.multireadscanbatch_id = gv_multireadscanbatch_id
              and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              and ul.uniqueitem_link_id = m.uniqueitem_id
              and ul.lossstatus <= 1 -- loss charged
              and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
              and m.multireadexception_id is null
              and m.poolitemyn='Y') mergequery
    on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
    when matched then
      update set u.returneddate = trunc(sysdate),
                 u.timestamp = sysdate,
                 u.systemuser_id = gv_systemuser_id;
    exception
      when no_data_found then
        null;
    end;
   end; -- outscanpool_update_unique_item

   --------------------------------------------------------------
   procedure outscan_update_unique_item_rte is
   begin
     begin
      writemultireaddebuglog('Update_unique_item_route');
      MERGE INTO uniqueitemroute u
      USING (SELECT m1.uniqueitem_id,
                    p.deliverydate,
                    p.route_id,
                    p.stop_id,
                    m1.plannedoutdate,
                    m1.plannedoutroute_id,
                    m1.plannedoutstop_id
               FROM multireadscanbatch m, multireadscanbatchcontents m1, packingnote p, uniqueitem u
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.packingnote_id = m.packingnote_id
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.deliveryscantimestamp is null -- no pending deliverys scans
                and m1.poolitemyn = 'N'
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET u.lastoutdate = MERGE_SUBQUERY.deliverydate,
               u.lastoutroute_id = MERGE_SUBQUERY.route_id,
               u.lastoutstop_id = MERGE_SUBQUERY.stop_id,
               u.plannedoutdate = null,
               u.plannedoutroute_id = null,
               u.plannedoutstop_id = null,
               u.systemuser_id = gv_systemuser_id,
               u.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (uniqueitem_id,
            lastinroute_id,
            lastoutroute_id,
            plannedoutroute_id,
            lastindate,
            lastoutdate,
            plannedoutdate,
            systemuser_id,
            timestamp,
            lastinstop_id,
            lastoutstop_id,
            plannedoutstop_id
            )
        VALUES
          (MERGE_SUBQUERY.uniqueitem_id,
           null, -- lastinroute_id
           MERGE_SUBQUERY.route_id, -- lastoutroute_id
           null, -- plannedoutroute_id,
           null, -- lastindate,
           MERGE_SUBQUERY.deliverydate, -- lastoutdate
           null, -- plannedoutdate,
           gv_systemuser_id,
           sysdate,
           null, -- lastinstop_id
           MERGE_SUBQUERY.stop_id, -- lastoutstop_id
           null -- plannedoutstop_id
           );
    exception
      when no_data_found then
        null;
    end;
   end; -- outscan_update_unique_item_route



   ---------------------------------------------
   procedure create_outscans is
   begin
    begin
    if gv_outscangarmentsaswell then   -- only create delivery scans for garments
      writemultireaddebuglog('Create delivery scans');
      insert into deliveryscan
             (businessunit_id,
              uniqueitem_link_id,
              scantimestamp,
              customer_link_id,
              weareremployment_link_id,
              distributionpoint_link_id,
              deliverypoint_link_id,
              product_link_id,
              sizedefinition_link_id,
              finishingmethod_id,
              routecontrol_id,
              packingnote_id,
              fromstock,
              previousstay_id,
              systemuser_id,
              timestamp,
              reasoncode_id,
              plantdepartment_id,
              chargewashing,
              locker_id,
              batchnumber,
              outscannodelivery,
              internalprocessingbu_id,
              scanstation,
              planneddeliverydate
             )
      select /*+index(mb XPKMULTIREADBATCH)*/
             mb.businessunit_id,
             mbc.uniqueitem_id,
             mbc.scantimestamp,
             mbc.customer_id,
             mbc.weareremployment_id,
             mbc.distributionpoint_id,
             mbc.deliverypoint_id,
             mbc.product_id,
             mbc.sizedefinition_id,
             mbc.finishingmethod_id,
             p.routecontrol_id,
              case when gv_iscustomernote='Y'
               then mbc.childpackingnoteline_id
               else p.packingnote_id
             end,
             case when mbc.stay_id = gc_stay_id_in_stock
               then 'Y'
               else 'N'
             end,  -- FromStock
             mbc.stay_id,  -- prev stay
             gv_systemuser_id,
             sysdate,
             case when mbc.stay_id = gc_stay_id_in_stock
               then uf.reasoncode_id
               else null
              end, -- ReasonCode_ID
             p.plantdepartment_id,
              case when ((mbc.stay_id = gc_stay_id_in_stock and c.chargewashfirstissue='N')
                 or (w.dummyforpool = 'Y' and
                  (select nvl(max(cgd.noregularoutscan),0)
                   from customergarmentdispenser cgd
                   where cgd.customer_id = w.customer_id ) = 1  and
                  we.garmentdispenser_id is not null))
               then 'N'
               else 'Y'
             end,  -- ChargeWashing
             we.locker_id,
             null, -- batchnumber
             0,    -- OutscanNoDelivery
             gv_businessunit_id, -- internalprocessingbu_id
             works.code,
             mbc.plannedoutdate
        from multireadscanbatch         mb,
             multireadscanbatchcontents mbc,
             packingnote                p,
             weareremployment           we,
             wearer                     w,
             uniqueitemfixedinfo        uf,
             customer                   c,
             workstation                works
       where mb.multireadscanbatch_id = gv_multireadscanbatch_id
         and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
         and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         and mbc.scan_id is not null
         and p.packingnote_id = mb.packingnote_id
         and we.weareremployment_id = mbc.weareremployment_id
         and w.wearer_id = we.wearer_id
         and uf.uniqueitem_id = mbc.uniqueitem_id
         and c.customer_id = mbc.customer_id
         and works.workstation_id = mb.workstation_id
         and mbc.poolitemyn = 'N' -- only create delivery scans for garments
         and mbc.deliveryscantimestamp is null -- no pending deliverys scans
         and mbc.multireadexception_id is null;

        writemultireaddebuglog('Link_existing_delivery_scans_to_packingnote');
        MERGE INTO deliveryscan ds
        USING (SELECT m.businessunit_id,
                      m1.uniqueitem_id,
                      m1.deliveryscantimestamp,
                      m.packingnote_id
                 FROM multireadscanbatch m, multireadscanbatchcontents m1, packingnote p, uniqueitem u
                WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.multireadscanbatch_id = m.multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                  and p.packingnote_id = m.packingnote_id
                  and m1.uniqueitem_id = u.uniqueitem_id
                  and m1.multireadexception_id is null
                  and m1.deliveryscantimestamp is not null -- no pending deliverys scans
                  and m1.poolitemyn = 'N'
              ) MERGE_SUBQUERY
        ON (ds.businessunit_id = MERGE_SUBQUERY.businessunit_id AND
            ds.uniqueitem_link_id = MERGE_SUBQUERY.uniqueitem_id AND
            ds.scantimestamp = MERGE_SUBQUERY.deliveryscantimestamp)
        WHEN MATCHED THEN
          UPDATE
             SET ds.packingnote_id = MERGE_SUBQUERY.packingnote_id;
    end if; -- gv_outscangarmentsaswell

    writemultireaddebuglog('Create Outscans');

    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid,deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
             dayssincelastscan,virtualyn)
    select /*+index(mb XPKMULTIREADBATCH)*/
           mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_at_customer,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           mbc.plannedoutroute_id,
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           null, -- qualitygrade_id
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           2, -- transaction type outscan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           p.notenumber,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
           nvl(mbc.virtualyn,'N') virtualyn
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           packingnote                p,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and p.packingnote_id = mb.packingnote_id
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
       and mbc.deliveryscantimestamp is null -- no pending deliverys scans
       and mbc.childpackingnoteline_id is null -- NOT linked to child packingnote
       and w.workstation_id = mb.workstation_id;

    if gv_isbulkshipmentnote='Y' or gv_iscustomernote='Y' then
      writemultireaddebuglog('Create Outscans link to Child Packingnotes');
      -- for items to be linked to child packingnote
      insert into scan
              (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
               weareremployment_link_id, distributionpoint_link_id, product_link_id,
               sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
               reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
               timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
               secondaryid,deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
               dayssincelastscan,virtualyn)
      select /*+index(mb XPKMULTIREADBATCH)*/
             mbc.scan_id,
             mb.businessunit_id,
             mbc.scantimestamp,
             mbc.idcode,
             mbc.customer_id,
             mbc.weareremployment_id,
             p.distributionpoint_id, -- distribution point of child packingnote
             mbc.product_id,
             mbc.sizedefinition_id,
             gc_stay_id_at_customer,
             gc_status_id_in_circ,
             w.code, -- workstation code
             mbc.lastissuedate,
             mbc.plannedoutroute_id,
             null, -- reasoncode
             mbc.customerowned,
             getyearofweek(trunc(mbc.scantimestamp)),
             getisoweek(trunc(mbc.scantimestamp)),
             getabsdaynumber(trunc(mbc.scantimestamp)),
             null, -- qualitygrade_id
             mb.systemuser_id,
             sysdate,
             mbc.stay_id, -- prev stay
             2, -- transaction type outscan
             0, -- days late
             mbc.uniqueitem_id,
             mbc.secondaryid,
             p.notenumber,
             trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
             trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
             trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
             nvl(mbc.virtualyn,'N') virtualyn
        from multireadscanbatch         mb,
             multireadscanbatchcontents mbc,
             packingnote                p,
             packingnoteline            pnl,
             workstation                w
       where mb.multireadscanbatch_id = gv_multireadscanbatch_id
         and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
         and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         and mbc.scan_id is not null
         and mbc.multireadexception_id is null
         and mbc.deliveryscantimestamp is null -- no pending deliverys scans
         and w.workstation_id = mb.workstation_id
         and pnl.packingnoteline_id = mbc.childpackingnoteline_id
         and p.packingnote_id = pnl.packingnote_id;
     end if;

     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end; -- create_outscans


   procedure create_pnotecontainercontent is
   lv_container_id            number;
   lv_packingnotecontainer_id number;

   begin
    gv_code_block := 'Create Packingnote Container Content';
    -- step 1: determine container_id
    writemultireaddebuglog('Create PN Container Content: Step 1 Determine Container ID');
    begin
      select msbc.container_id
        into lv_container_id
        from multireadscanbatchcontknt msbc
       where msbc.multireadscanbatch_id = gv_multireadscanbatch_id
         and (msbc.multireadexception_id is null or msbc.multireadexception_id = 20)
         and msbc.container_id is not null
       group by msbc.container_id;
    exception
      when too_many_rows then lv_container_id := null;
      when no_data_found then lv_container_id := null;
    end;

    --step 2: determine packingnotecontainer_id
    lv_packingnotecontainer_id := null;
    if lv_container_id is not null then
      begin
         writemultireaddebuglog('Create PN Container Content: Step 2 Determine PNContainer ID');
         select min(pnc.packingnotecontainer_id)
           into lv_packingnotecontainer_id
           from packingnotecontainer pnc
          where pnc.packingnote_id = gv_packingnote_id
            and pnc.container_id = lv_container_id;
      exception
        when no_data_found then lv_packingnotecontainer_id := null;
      end;

    --step 3: insert when not yet in
      if lv_packingnotecontainer_id is not null then
        begin
          writemultireaddebuglog('Create PN Container Content: Step 3 Insert into PNContainerContent');
          merge into packingnotecontainercontent pncc using
           (select distinct m.uniqueitem_id, m.packingnoteline_id
              from multireadscanbatchcontents m
             where m.multireadscanbatch_id = gv_multireadscanbatch_id
               and m.uniqueitem_id is not null
               and m.packingnoteline_id is not null
               and m.multireadexception_id is null
           ) mq
         on (pncc.packingnotecontainer_id = lv_packingnotecontainer_id and
             pncc.uniqueitem_link_id = mq.uniqueitem_id)
         when not matched then
          insert (packingnotecontainer_id,
                  uniqueitem_link_id,
                  packingnoteline_id,
                  systemuser_id,
                  timestamp
                  )
          values (lv_packingnotecontainer_id,
                  mq.uniqueitem_id,
                  mq.packingnoteline_id,
                  gv_systemuser_id,
                  sysdate
                 );
         exception
            when no_data_found then
              null;
         end;
       end if; -- lv_packingnotecontainer_id is not null
    end if; -- lv_container_id is not null
   end; -- create_pnotecontainercontent

   procedure Create_ExchangeCartCycle is
   begin
    --Create_ExchangeCartCycle
    gv_code_block := 'Create ExchangeCartCycle OutscanPoolBatch';
    writemultireaddebuglog(gv_code_block);
    if lv_year is not null and lv_week is not null and
       fp_exchangecart_id is not null then
      begin
        MERGE INTO exchangecartcycle ecc
          USING (
          select ec.exchangecart_id, m1.product_id, m1.sizedefinition_id,
                 m1.finishingmethod_id, count(1) realscannedout,
             nvl(max((select max(cr.chippingrate)
                      from  chippingrate cr
                      where cr.businessunit_id = gv_businessunit_id
                        and cr.product_link_id = m1.product_id
                        and cr.sizedefinition_link_id = m1.sizedefinition_id
                        and cr.finishingmethod_id = m1.finishingmethod_id
                        and cr.year = lv_year
                        and cr.week = lv_week))
                 ,100) chippingrate,
                 l.usechippingratedee,
                pk.deliverydate,
                pkl.standardamount
          from  multireadscanbatchcontents m1
          JOIN productlistpercustomer l on
               l.productlistpercustomer_id = m1.plpc_id
          JOIN packingnoteline pkl on pkl.packingnoteline_id = m1.packingnoteline_id
          JOIN packingnote pk on pk.packingnote_id = pkl.packingnote_id
          cross join exchangecart ec
          where m1.multireadscanbatch_id = gv_multireadscanbatch_id
          and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
          and ec.exchangecart_id = fp_exchangecart_id
          group by ec.exchangecart_id,
                   m1.product_id,
                   m1.sizedefinition_id,
                   m1.finishingmethod_id,
                   l.usechippingratedee,
                   pk.deliverydate,
                   pkl.standardamount
           ) MERGE_SUBQUERY
          ON ( ecc.exchangecart_id = MERGE_SUBQUERY.exchangecart_id
          AND  ecc.product_link_id = MERGE_SUBQUERY.product_id
          AND  ecc.sizedefinition_link_id = MERGE_SUBQUERY.sizedefinition_id
          AND  ecc.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
          AND  ecc.deliverydate = MERGE_SUBQUERY.deliverydate
           )
          WHEN MATCHED THEN
            UPDATE
               SET ecc.realscannedout = ecc.realscannedout + MERGE_SUBQUERY.realscannedout,
                   ecc.calculatedscannedout =
                     case when ecc.chippingrate <> 0
                           and MERGE_SUBQUERY.usechippingratedee = 1
                       then round((MERGE_SUBQUERY.realscannedout*100)/MERGE_SUBQUERY.chippingrate)
                       else ecc.realscannedout + MERGE_SUBQUERY.realscannedout
                     end,
                   ecc.systemuser_id = gv_systemuser_id,
                   ecc.timestamp = sysdate
          WHEN NOT MATCHED THEN
            INSERT
               (exchangecartcycle_id,
                exchangecart_id,
                cleanreturndate,
                deliverydate,
                codeuniquely,
                product_link_id,
                sizedefinition_link_id,
                finishingmethod_id,
                par,
                chippingrate,
                realscannedin,
                calculatedscannedin,
                countedin,
                realscannedout,
                calculatedscannedout,
                systemuser_id,
                timestamp
                )
            VALUES
              (seq_exchangecartcycle.nextval,
              MERGE_SUBQUERY.exchangecart_id,
              trunc(sysdate), --cleanreturndate
              MERGE_SUBQUERY.deliverydate, --deliverydate
              1, --codeuniquely
              MERGE_SUBQUERY.product_id,
              MERGE_SUBQUERY.sizedefinition_id,
              MERGE_SUBQUERY.finishingmethod_id,
              MERGE_SUBQUERY.standardamount, --par
              MERGE_SUBQUERY.chippingrate, --chippingrate
              0, --realscannedin
              0, --calculatedscannedin
              0, --countedin
              MERGE_SUBQUERY.realscannedout, --realscannedout
              case when MERGE_SUBQUERY.chippingrate <> 0
                    and MERGE_SUBQUERY.usechippingratedee = 1
                 then round((MERGE_SUBQUERY.realscannedout*100)/MERGE_SUBQUERY.chippingrate)
                 else MERGE_SUBQUERY.realscannedout
              end, --calculatedscannedout
              gv_systemuser_id,
              sysdate
               );
         exception
            when no_data_found then
              null;
       end;
       if gg_ss_uhfpoolitemstartupphase = 'N' then
         begin
           update packingnoteline pkl
           set    pkl.deliveredamount =
                   (select round((count(1) * 100) /
                                  nvl(max((select max(cr.chippingrate)
                                          from   chippingrate cr
                                          where  cr.businessunit_id = gv_businessunit_id
                                          and    cr.product_link_id = mbc.product_id
                                          and    cr.sizedefinition_link_id = mbc.sizedefinition_id
                                          and    cr.finishingmethod_id = mbc.finishingmethod_id
                                          and    cr.year = lv_year
                                          and    cr.week = lv_week)), 100))
                    from   multireadscanbatchcontents mbc
                    join   productlistpercustomer l
                    on     l.productlistpercustomer_id = mbc.plpc_id
                    where  mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                    and    (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and    mbc.childpackingnoteline_id = pkl.packingnoteline_id
                    and    l.usechippingratedee = 1)
            where  exists (select 1
                   from   multireadscanbatchcontents mbc
                   join   productlistpercustomer l
                   on     l.productlistpercustomer_id = mbc.plpc_id
                   where  mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                   and    (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                   and    mbc.childpackingnoteline_id = pkl.packingnoteline_id
                   and    l.usechippingratedee = 1
                   and    nvl((select max(cr.chippingrate)
                              from   chippingrate cr
                              where  cr.businessunit_id = gv_businessunit_id
                              and    cr.product_link_id = mbc.product_id
                              and    cr.sizedefinition_link_id = mbc.sizedefinition_id
                              and    cr.finishingmethod_id = mbc.finishingmethod_id
                              and    cr.year = lv_year
                              and    cr.week = lv_week), 100) between 1 and 99);
         end;
       end if;
     end if;
   end Create_ExchangeCartCycle;

   procedure update_child_customer_pn is
   -- this procedure distributes the items to the child packingnotes of the customer packingnote
   -- and populates the childpackingnote_id in multireadscanbatchcontents
   -- this column is used further down for linking uniqueitems and delivery scans to the child packingnote
   -- and assigns them to the distribution point of the child packingnote.
   -- it is used under module CUSTOMERPACKINGNOTE
    lv_childpnlfound boolean;
    lv_childpnlexist boolean;

    begin
       for curr_batch_content in
             (select m1.multireadscanbatch_id, m.packingnote_id, m1.idcode,
                    m1.product_id, m1.sizedefinition_id, m1.finishingmethod_id
               from multireadscanbatchcontents m1, multireadscanbatch m
              where m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.poolitemyn='Y'
                and m1.multireadexception_id is null
                and m1.childpackingnoteline_id is null
              order by m1.packingnoteline_id) loop
          lv_childpnlfound := false;
          lv_childpnlexist := false;
          for curr_pnl in
                   (select pnl.packingnoteline_id, pnl.actualdelivery, pnl.deliveredamount
                      from packingnoteline pnl, packingnote pn
                     where pnl.packingnote_id = pn.packingnote_id
                       and pn.bulkpackingnote_id = curr_batch_content.packingnote_id
                       and pnl.product_id = curr_batch_content.product_id
                       and pnl.sizedefinition_id = curr_batch_content.sizedefinition_id
                       and pnl.finishingmethod_id = curr_batch_content.finishingmethod_id
                     order by pnl.deliveredamount / pnl.actualdelivery asc, pnl.actualdelivery desc
                   ) loop
                  lv_childpnlexist := true;

                  update packingnoteline pl
                     set pl.deliveredamount = pl.deliveredamount + 1,
                         pl.scannedqty = nvl(pl.scannedqty,0) + 1,
                         pl.timestamp = sysdate
                   where pl.packingnoteline_id = curr_pnl.packingnoteline_id;

                  update multireadscanbatchcontents mbc
                     set mbc.childpackingnoteline_id = curr_pnl.packingnoteline_id
                   where mbc.multireadscanbatch_id = curr_batch_content.multireadscanbatch_id
                     and mbc.idcode = curr_batch_content.idcode;
                  lv_childpnlfound := true;
                  exit;

          end loop;
      end loop;
   end;

   procedure update_customer_pn is
   -- this procedure updates the delivered amount on the customer packing note
   -- when outscanning on a child customer packing note
   -- it is used under module CUSTOMERPACKINGNOTE

    begin
      for curr_batch_content in
             (select m1.multireadscanbatch_id, m.packingnote_id, m1.idcode,
                    m1.product_id, m1.sizedefinition_id, m1.finishingmethod_id
               from multireadscanbatchcontents m1, multireadscanbatch m
              where m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.poolitemyn='Y'
                and m1.multireadexception_id is null
                and m1.childpackingnoteline_id is null
              order by m1.packingnoteline_id) loop

                  update packingnoteline pl
                     set pl.deliveredamount = pl.deliveredamount + 1,
                         pl.scannedqty = nvl(pl.scannedqty, 0) + 1,
                         pl.timestamp = sysdate
                   where pl.packingnoteline_id = (select pnl.packingnoteline_id
                                                    from packingnoteline pnl, packingnote pn_customer, packingnote pn_child
                                                   where pnl.packingnote_id = pn_customer.packingnote_id
                                                     and pn_customer.packingnote_id = pn_child.bulkpackingnote_id
                                                     and pn_child.packingnote_id = curr_batch_content.packingnote_id
                                                     and pnl.product_id = curr_batch_content.product_id
                                                     and pnl.sizedefinition_id = curr_batch_content.sizedefinition_id
                                                     and pnl.finishingmethod_id = curr_batch_content.finishingmethod_id
                                                     and pn_customer.origin = 16);
      end loop;
   end;

   ----------------------------------------------------------------
   -- Begin f_processmultireadoutscanpoolbatch
   begin
    begin -- exception block
     gv_main_code_block := 'Process Outscan Pool Batch';

     retrieve_item_info;

     if (gv_databasecode not in ('FIS','PLS')) and (gv_outscantrackonly <> 'Y') then    -- ABS-17369
       if gs_ss_recordonsiteinventory = 'Y' then
         decrease_onsite_inventory;   -- for pool items not scanned in
       end if;

       Create_delivery_variations;  -- for pool items not scanned in
     end if;

     Create_garmdisp_transactions;  -- for pool items not scanned in

     incr_qty_returned_unrel_loans;

     if gv_outscantrackonly <> 'Y' then
       Create_upd_packingnote_lines;

     if gv_isbulkshipmentnote='Y' then populate_childpackingnote_id; end if;
     end if;

     if gv_iscustomernote='Y' then update_child_customer_pn;
     end if;

     if gv_ischildcustomernote='Y' then update_customer_pn;
     end if;

     if gc_ss_uhfoutscanbundleperc > 0 then
       Update_Bundle_Status;
     end if;

     Outscanpool_update_unique_item;

     if gc_ss_scanbyroute='Y' and gv_outscangarmentsaswell then
       outscan_update_unique_item_rte;
     end if;

     Create_flags_maxwash_spectreat;

     Create_outscans;

     if gv_items_in_batch_knt > 0 then
       create_pnotecontainercontent;
     end if;

     Create_ExchangeCartCycle;

     Remove_Flags('OutScan');

     load_uniqueitem_buffer_info;
     insertupdate_uniqueitembufinfo(2);
     create_prodprocessbufscans(2);
     delete_uniqueitem_buffer_info; -- afterwards delete bufferinfo

     Create_reject_scans(2);  -- 2 = transactiontype outscan

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
     when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(2, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processoutscanpoolbatch;

 -----------------------------------------------------------------------------------------
  function f_processoutscanbatchKNT return number is

   ---------------------------------------------
   procedure outscan_update_container is
   begin
     begin
      writemultireaddebuglog('Update Container');
      MERGE INTO container c
      USING (SELECT m1.container_id,
                    m1.scantimestamp,
                    mb.businessunit_id current_bu,
                    m1.businessunit_id last_bu,
                    m1.stay_id,
                    p.distributionpoint_id new_distributionpoint_id,
                    m1.distributionpoint_id,
                    m1.lastdistribpoint_id,
                    c1.staychangedate,
                    c1.numberofdaysatcustprev,
                    trunc(c1.lastoutscandate) lastoutscandate,
                    p.notenumber
               FROM multireadscanbatch mb, multireadscanbatchcontknt m1, container c1, packingnote p
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.container_id = c1.container_id
                and m1.multireadexception_id is null
                and p.packingnote_id = mb.packingnote_id
            ) MERGE_SUBQUERY
      ON (c.container_id = MERGE_SUBQUERY.container_id)
      WHEN MATCHED THEN
        UPDATE
           SET  c.businessunit_id = MERGE_SUBQUERY.current_bu, -- update BU upon outscan
                c.lastbusinessunit_id = MERGE_SUBQUERY.last_bu,
                c.distributionpoint_id = new_distributionpoint_id, -- link to dp of packingnote
                c.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                   then MERGE_SUBQUERY.distributionpoint_id
                                                   else MERGE_SUBQUERY.lastdistribpoint_id -- leave unchanged
                                                  end,
                c.prevstay_id = MERGE_SUBQUERY.stay_id,
                c.stay_id = gc_stay_id_knt_at_customer,
                c.staychangedate = case when MERGE_SUBQUERY.stay_id <> gc_stay_id_knt_at_customer
                                      then MERGE_SUBQUERY.scantimestamp
                                      else MERGE_SUBQUERY.staychangedate -- leave unchanged
                                   end,
                c.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                c.lastnotenumber = MERGE_SUBQUERY.notenumber,
                c.numberofdaysatcustprev = case when MERGE_SUBQUERY.stay_id = gc_stay_id_knt_at_customer and MERGE_SUBQUERY.lastoutscandate is not null
                                                   then MERGE_SUBQUERY.numberofdaysatcustprev + (trunc(MERGE_SUBQUERY.scantimestamp) - trunc(MERGE_SUBQUERY.lastoutscandate))
                                                   else MERGE_SUBQUERY.numberofdaysatcustprev -- leave unchanged
                                           end,
                c.numberofshipments = c.numberofshipments + 1,
                c.systemuser_id = gv_systemuser_id,
                c.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- outscan_update_container

   ---------------------------------------------
   procedure create_packingnote_container is
   lv_next_seqnr number;
   lv_packingnote_id number;

   begin
    begin
    writemultireaddebuglog('Select max seq# Packingnote Container');

    select mb.packingnote_id
      into lv_packingnote_id
      from multireadscanbatch mb
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id;

    begin
      select nvl(max(pnc.sequencenumber),0) + 1
        into lv_next_seqnr
        from packingnotecontainer pnc
       where pnc.packingnote_id = lv_packingnote_id;
      exception
        when no_data_found then
          lv_next_seqnr := 1;
    end;

    writemultireaddebuglog('Create Packingnote Container');

    for c_container in (select mbc.containertype_id,
                               mbc.container_id,
                               mbc.systemuser_id,
                               mbc.tareweight
                          from multireadscanbatchcontknt mbc
                         where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                           and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                           and mbc.multireadexception_id is null
                           and mbc.container_id is not null
                       ) loop
    insert
      into packingnotecontainer pnc
           (packingnotecontainer_id,
            packingnote_id,
            sequencenumber,
            containertype_id,
            container_id,
            weighingcategory_id,
            tareweight,
            grossweight,
            soilportion,
            weightdecimals,
            weighingsequencenr,
            weighingtimestamp,
            systemuser_id,
            timestamp)
       values(seq_packingnotecontainer.nextval,
               lv_packingnote_id,
               lv_next_seqnr,
               c_container.containertype_id,
               c_container.container_id,
               null,
               c_container.tareweight,
               0,
               0,
               0,
               null,
               null,
               c_container.systemuser_id,
               sysdate
             );
       lv_next_seqnr := lv_next_seqnr + 1;
    end loop;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_packingnote_container

   ---------------------------------------------
   procedure create_container_outscans is
   begin
    -- populate scan_ID
    begin
    writemultireaddebuglog('Create Container outscans - populate scanID');
    UPDATE multireadscanbatchcontknt m
       set m.containerscan_id = seq_containerscan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.container_id is not null
       and m.containerscan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Container outscans');
    insert into containerscan
            (containerscan_id,
             scantimestamp,
             businessunit_id,
             primaryid,
             secondaryid,
             distributionpoint_link_id,
             containertype_id,
             stay_id,
             prevstay_id,
             transactiontype_id,
             scanstation,
             customerowned,
             year,
             week,
             dayno,
             container_id,
             tareweight,
             systemuser_id,
             timestamp)
    select mbc.containerscan_id,
           mbc.scantimestamp,
           mb.businessunit_id,
           mbc.idcode,
           mbc.secondaryid,
           p.distributionpoint_id,
           mbc.containertype_id,
           gc_stay_id_knt_at_customer,
           mbc.stay_id,
           540, -- transaction type outscan container via delivery note
           w.code,
           case when mbc.ownercustomer_id is not null
            then 'Y'
            else 'N'
           end,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.container_id,
           mbc.tareweight,
           mbc.systemuser_id,
           sysdate
      from multireadscanbatch            mb,
           multireadscanbatchcontknt     mbc,
           workstation                   w,
           packingnote                   p
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.containerscan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id
       and p.packingnote_id = mb.packingnote_id;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_container_outscans
   -----------------------------------------------


   ----------------------------------------------------------------
   -- Begin f_processmultireadoutscanbatchKNT
   begin
    begin
     gv_main_code_block := 'Process Outscan Batch Containers';

     Outscan_update_container;

     Create_packingnote_container;

     Create_container_outscans;

     Create_reject_scans_knt(540); -- 540 = transactiontype outscan container via deliverynote

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processoutscanbatchKNT;

  -----------------------------------------------------------------------------------------
  function f_processscanandcountbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   ---------------------------------------------
   procedure retrieve_item_info is

   begin
    -- find old plpc for items that where not scanned in
    begin
    writemultireaddebuglog('Retrieve item info step 1a old plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = dep.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.prev_finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1, distributionpoint dip, department dep
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.prev_distributionpoint_id is not null
                and dip.distributionpoint_id = m1.prev_distributionpoint_id
                and dep.department_id = dip.department_id
                and m1.poolitemyn='Y'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.prev_plpc_id = MERGE_SUBQUERY.productlistpercustomer_id;
    exception
      when no_data_found then
        null;
    end;

    -- populate scan_ID
    begin
    writemultireaddebuglog('Retrieve item info step 2 scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null;
    exception
      when no_data_found then
        null;
    end;

    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 primID and secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid,
                    u.primaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su, uniqueitem u
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode         = MERGE_SUBQUERY.primaryid,
               m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;
   end; -- retrieve_item_info

   ---------------------------------------------
   procedure decrease_onsite_inventory is
   begin
    begin
    writemultireaddebuglog('Decrease onsite inventory');
    MERGE INTO onsiteinventoryadjustment o
      USING (SELECT p.productlistperdistribpoint_id,
                    5 origin,
                    trunc(sysdate) inventorydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1,
                    uniqueitem u,
                    productlistperdistribpoint p,
                    productlistpercustomer plpc
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.stay_id = gc_stay_id_at_customer -- only for items not scanned in
                and m1.poolitemyn ='Y'
                and u.uniqueitem_id = m1.uniqueitem_id
                and p.distributionpoint_id = m1.prev_distributionpoint_id
                and p.product_id = m1.product_id
                and p.sizedefinition_id = m1.sizedefinition_id
                and p.finishingmethod_id = m1.prev_finishingmethod_id
                and plpc.productlistpercustomer_id = m1.prev_plpc_id
                and plpc.soilcountmethod <> 0
                and m1.multireadexception_id is null
                and m1.deliveryscantimestamp is null -- only when it is not a rescan
              GROUP BY p.productlistperdistribpoint_id
            ) MERGE_SUBQUERY
      ON (o.productlistperdistribpoint_id = MERGE_SUBQUERY.productlistperdistribpoint_id
      AND o.origin                        = MERGE_SUBQUERY.origin
      AND o.inventorydate                 = MERGE_SUBQUERY.inventorydate
      AND o.reference is null)
      WHEN MATCHED THEN
        UPDATE
           SET o.quantity = o.quantity - MERGE_SUBQUERY.qty,
               o.systemuser_id = gv_systemuser_id,
               o.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
          (onsiteinventoryadjustment_id,
           productlistperdistribpoint_id,
           origin,
           inventorydate,
           quantity,
           reference,
           systemuser_id,
           timestamp,
           invoiceheader_id)
        VALUES
          (seq_onsiteinventoryadjustment.nextval,
           MERGE_SUBQUERY.productlistperdistribpoint_id,
           MERGE_SUBQUERY.origin,
           MERGE_SUBQUERY.inventorydate,
           MERGE_SUBQUERY.qty * -1,
           null, -- reference
           gv_systemuser_id,
           sysdate,
           null);
    exception
      when no_data_found then
        null;
    end;
   end; --decrease_onsite_inventory

   procedure create_delivery_variations is
   begin
    begin
    writemultireaddebuglog('Create delivery variations pool');
    MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
      USING (SELECT nvl(p.distributionpoint_id,m1.prev_distributionpoint_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.prev_finishingmethod_id finishingmethod_id,
                    gv_planneddeliverydate deliverydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber,
                    multireadscanbatch mb,
                    productlistpercustomer plpc
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.prev_distributionpoint_id is not null
                and m1.poolitemyn = 'Y'
                and plpc.productlistpercustomer_id = m1.prev_plpc_id
                and m1.stay_id = gc_stay_id_at_customer -- only for items not scanned in
                and plpc.delayedevenexchange > 0  -- only those with delayed even exchange
                and m1.prev_finishingmethod_id is not null
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
                and m1.deliveryscantimestamp is null -- only when it is not a rescan
              GROUP BY nvl(p.distributionpoint_id,m1.prev_distributionpoint_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.prev_finishingmethod_id
            ) MERGE_SUBQUERY
      ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
      AND d.product_id = MERGE_SUBQUERY.product_id
      AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
      AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
      AND d.deliverydate = MERGE_SUBQUERY.deliverydate
      AND d.packingnote_id is null
      AND d.processed = 'N'
      AND d.causenote_id is null
      AND d.updaterentqty = 'N'
      AND d.origin = 1
      AND d.soilcountsubtype = 7 -- inscan
      AND d.weborderline_id is null
      AND d.reference is null
      AND d.adjustmentreason_id is null
      AND d.reasoncode_id is null
      )
      WHEN MATCHED THEN
        UPDATE
           SET d.amount = d.amount + MERGE_SUBQUERY.qty,
               d.systemuser_id = gv_systemuser_id,
               d.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (deliveryvariations_id,
            product_id,
            packingnote_id,
            causenote_id,
            deliverydate,
            origin,
            amount,
            finishingmethod_id,
            fixedamount,
            distributionpoint_id,
            sizedefinition_id,
            reference,
            systemuser_id,
            processed,
            timestamp,
            updaterentqty,
            soilcountsubtype,
            processbusinessunit_id,
            internalprocessingbu_id)
        VALUES
          (seq_deliveryvariations.nextval,
           MERGE_SUBQUERY.product_id,
           null, -- packingnote
           null, -- cause note
           MERGE_SUBQUERY.deliverydate,
           1,    -- origin
           MERGE_SUBQUERY.qty,
           MERGE_SUBQUERY.finishingmethod_id,
           'N',  -- fixedamount
           MERGE_SUBQUERY.distributionpoint_id,
           MERGE_SUBQUERY.sizedefinition_id,
           null, -- reference
           gv_systemuser_id,
           'N',  -- processed
           sysdate,
           'N',  -- update rent qty
           7,     -- soilcount subtype inscan
           f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
           gv_businessunit_id);
    exception
      when no_data_found then
        null;
    end;
   end; -- create_delivery_variations

   ---------------------------------------------
   -- ABS-21481
   procedure update_bundle_status is
   begin
     writemultireaddebuglog('Update Bundle Status');
     -- set bundle status to 2: delivered
     update uhfbundle b
        set b.deliverystatus = 2 -- delivered
      where b.uhfbundle_id in
             (select distinct mbc.uhfbundle_id
                from multireadscanbatchcontents mbc
               where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                 and mbc.bundleaddedyn = 'Y'
                 and mbc.multireadexception_id is null -- only those that have at least one item approved
             );
     commit;
   end; -- update_bundle_status
   --- end ABS-21481

   ---------------------------------------------
   procedure outscanpool_update_unique_item is
   begin
    begin
      writemultireaddebuglog('Update Unique Pool Item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    case when m1.secondaryid is null
                      then m.businessunit_id -- update BU upon outscan only for pool items without secID
                      else m1.businessunit_id -- original BU
                    end businessunit_id,
                    m1.stay_id,
                    u1.status_id,
                    u1.distributionpoint_id,
                    u1.lastdistributionpoint_link_id,
                    m1.distributionpoint_id new_distributionpoint_id,
                    m1.finishingmethod_id,
                    m1.prev_finishingmethod_id
               FROM multireadscanbatch m, multireadscanbatchcontents m1, uniqueitem u1
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u1.uniqueitem_id
                and m1.poolitemyn = 'Y'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.businessunit_id = MERGE_SUBQUERY.businessunit_id,
                u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washestotal + 1
                                else u.washestotal
                                end,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_at_customer,
                u.finishingmethod_id = case when gs_ss_changefmforpoolmultiread = 0 OR gv_dbSetting in ('ANG','TLK')
                                         then MERGE_SUBQUERY.prev_finishingmethod_id
                                         else MERGE_SUBQUERY.finishingmethod_id
                                       end,
                u.distributionpoint_id = MERGE_SUBQUERY.new_distributionpoint_id,
                u.lastdistributionpoint_link_id = case when MERGE_SUBQUERY.distributionpoint_id is not null
                                                    then MERGE_SUBQUERY.distributionpoint_id
                                                    else MERGE_SUBQUERY.lastdistributionpoint_link_id
                                                  end,
                u.unrelatedloan_id = null,       -- disconnect from unrelated loan
                u.planneddeliverydate = gv_planneddeliverydate,
                u.activestocklocation_id = null,
                u.deliveryfromstock = 'N',
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate,
                u.batchnumber = nvl(gv_batchnumber,u.batchnumber);


    if gv_outscangarmentsaswell then
      writemultireaddebuglog('Update Unique Garment');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    u1.status_id,
                    case when u1.status_id <> gc_status_id_in_circ
                     then trunc(m1.scantimestamp)
                     else u1.statuschangedate
                    end statuschangedate,
                    m1.distributionpoint_id
               FROM multireadscanbatch m, multireadscanbatchcontents m1, uniqueitem u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.poolitemyn = 'N'
                and m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
--                and m1.deliveryscantimestamp is null -- no pending deliverys scans
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal =  case when gc_ss_countwashesat = 'O'
                                             or (gc_ss_countwashesat='I'
                                            and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                            and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                      then u.washestotal + 1
                                      else u.washestotal
                                  end,
                u.prevstatus_id = null,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_at_customer,
                u.planneddeliverydate = null,
                u.activestocklocation_id = null,
                u.deliveryfromstock = 'N',
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate,
                u.batchnumber = nvl(gv_batchnumber,batchnumber);
      --
      writemultireaddebuglog('Update Unique Itemn Non Pool');
      MERGE INTO uniqueitemnonpool u
      USING (SELECT m1.uniqueitem_id,
                    m1.stay_id
               FROM multireadscanbatchcontents m1, uniqueitemnonpool u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
--                and m1.deliveryscantimestamp is null -- no pending deliverys scans
                and m1.poolitemyn = 'N'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.washesthisissue = case when gc_ss_countwashesat = 'O'
                                       or (gc_ss_countwashesat='I'
                                      and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                      and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                then u.washesthisissue + 1
                                else u.washesthisissue
                                end,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    end if; -- if gv_outscangarmentsaswell

    writemultireaddebuglog('Update unique item loss');
    merge into uniqueitemloss u
    using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
             from multireadscanbatchcontents m, uniqueitemloss ul
            where m.multireadscanbatch_id = gv_multireadscanbatch_id
              and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              and ul.uniqueitem_link_id = m.uniqueitem_id
              and ul.lossstatus <= 1 -- loss charged
              and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
              and m.multireadexception_id is null
              and m.poolitemyn='Y') mergequery
    on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
    when matched then
      update set u.returneddate = trunc(sysdate),
                 u.timestamp = sysdate,
                 u.systemuser_id = gv_systemuser_id;
    exception
      when no_data_found then
        null;
    end;
   end; -- outscanpool_update_unique_item

   --------------------------------------------------------------
   procedure outscan_update_unique_item_rte is
   begin
     begin
      writemultireaddebuglog('Update_unique_item_route');
      MERGE INTO uniqueitemroute u
      USING (SELECT m1.uniqueitem_id,
                    gv_planneddeliverydate deliverydate,
                    gv_route_id route_id,
                    nvl(
                    (select min(s.stop_id)
                       from routecontrol rc, stop s
                      where rc.route_id = gv_route_id
                        and rc.drivingdate = gv_planneddeliverydate
                        and s.routecontrol_id = rc.routecontrol_id
                        and s.customer_link_id = m1.customer_id
                        and s.deliverypoint_id = m1.deliverypoint_id
                        and s.stoptype <> 2),  -- not get
                    (select min(s.stop_id)
                       from routecontrol rc, stop s
                      where rc.route_id = gv_route_id
                        and rc.drivingdate = gv_planneddeliverydate
                        and s.routecontrol_id = rc.routecontrol_id
                        and s.customer_link_id = m1.customer_id
                        and s.deliverypoint_id is null
                        and s.stoptype <> 2)  -- not get
                    ) stop_id
               FROM multireadscanbatch m, multireadscanbatchcontents m1
              WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.multireadexception_id is null
--                and m1.deliveryscantimestamp is null -- no pending deliverys scans
                and m1.poolitemyn = 'N'
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET u.lastoutdate = MERGE_SUBQUERY.deliverydate,
               u.lastoutroute_id = MERGE_SUBQUERY.route_id,
               u.lastoutstop_id = MERGE_SUBQUERY.stop_id,
               u.plannedoutdate = null,
               u.plannedoutroute_id = null,
               u.plannedoutstop_id = null,
               u.systemuser_id = gv_systemuser_id,
               u.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (uniqueitem_id,
            lastinroute_id,
            lastoutroute_id,
            plannedoutroute_id,
            lastindate,
            lastoutdate,
            plannedoutdate,
            systemuser_id,
            timestamp,
            lastinstop_id,
            lastoutstop_id,
            plannedoutstop_id
            )
        VALUES
          (MERGE_SUBQUERY.uniqueitem_id,
           null, -- lastinroute_id
           MERGE_SUBQUERY.route_id, -- lastoutroute_id
           null, -- plannedoutroute_id,
           null, -- lastindate,
           MERGE_SUBQUERY.deliverydate, -- lastoutdate
           null, -- plannedoutdate,
           gv_systemuser_id,
           sysdate,
           null, -- lastinstop_id
           MERGE_SUBQUERY.stop_id, -- lastoutstop_id
           null -- plannedoutstop_id
           );
    exception
      when no_data_found then
        null;
    end;
   end; -- outscan_update_unique_item_route



   ---------------------------------------------
   procedure create_outscans is
   lv_routecontrol_id number;
   lv_charge_washes_garmentdisp varchar2(1); -- charge washes because of garment dispenser setup
   begin
    begin
       select r.routecontrol_id
         into lv_routecontrol_id
         from routecontrol r
        where r.route_id = gv_route_id
          and r.drivingdate = gv_planneddeliverydate;
    exception
        when no_data_found then
          lv_routecontrol_id := null;
    end;
    begin
       select 'N'
         into lv_charge_washes_garmentdisp
          from garmentdispenser gd,
               customergarmentdispenser cgd,
               distributionpoint dp,
               department d
         where dp.distributionpoint_id = gv_consumptionpoint_id
           and d.department_id = dp.department_id
           and gd.customer_id = d.customer_id
           and gd.deliverypoint_id = dp.deliverypoint_id
           and cgd.customer_id = d.customer_id
           and cgd.processtrans2asoutscan = 'Y'
           and gd.usedforpool = 'Y'
           and ((cgd.customerrelatedpool = 'Y' and cgd.noregularoutscancustpool = 1)
             or (cgd.generalpool = 'Y' and cgd.noregularoutscangenpool = 1));
    exception
        when no_data_found then
          lv_charge_washes_garmentdisp := 'Y';
    end;

    begin
    writemultireaddebuglog('Create delivery scans');
    insert into deliveryscan
           (businessunit_id,
            uniqueitem_link_id,
            scantimestamp,
            customer_link_id,
            weareremployment_link_id,
            distributionpoint_link_id,
            deliverypoint_link_id,
            product_link_id,
            sizedefinition_link_id,
            finishingmethod_id,
            routecontrol_id,
            packingnote_id,
            fromstock,
            previousstay_id,
            systemuser_id,
            timestamp,
            reasoncode_id,
            plantdepartment_id,
            chargewashing,
            locker_id,
            batchnumber,
            outscannodelivery,
            internalprocessingbu_id,
            planneddeliverydate,
            scanstation
           )
    select /*+index(mb XPKMULTIREADBATCH)*/
           mb.businessunit_id,
           mbc.uniqueitem_id,
           mbc.scantimestamp,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.deliverypoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           mbc.finishingmethod_id,
           lv_routecontrol_id,
           null, -- packingnote_id
           case when mbc.stay_id = gc_stay_id_in_stock
             then 'Y'
             else 'N'
           end,  -- FromStock
           mbc.stay_id,  -- prev stay
           gv_systemuser_id,
           sysdate,
           case when mbc.stay_id = gc_stay_id_in_stock
             then uf.reasoncode_id
             else null
            end, -- ReasonCode_ID
           works.plantdepartment_id,
            case when ((mbc.poolitemyn = 'N' and mbc.stay_id = gc_stay_id_in_stock and c.chargewashfirstissue = 'N')
               or (mbc.poolitemyn = 'N' and w.dummyforpool = 'Y' and
                (select nvl(max(cgd.noregularoutscan),0)
                 from customergarmentdispenser cgd
                 where cgd.customer_id = w.customer_id ) = 1  and
                we.garmentdispenser_id is not null)
               or (mbc.poolitemyn = 'Y' and lv_charge_washes_garmentdisp = 'N'))
             then 'N'
             else 'Y'
           end,  -- ChargeWashing
           we.locker_id,
           gv_batchnumber, -- batchnumber
           0,    -- OutscanNoDelivery
           gv_businessunit_id, -- internalprocessingbu_id
           gv_planneddeliverydate,
           works.code
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc
           left outer join (weareremployment we
                            join wearer w on (w.wearer_id = we.wearer_id))
                   on (we.weareremployment_id = mbc.weareremployment_id),
           uniqueitemfixedinfo        uf,
           customer                   c,
           workstation                works
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and uf.uniqueitem_id = mbc.uniqueitem_id
       and c.customer_id = mbc.customer_id
       and works.workstation_id = mb.workstation_id
--       and mbc.deliveryscantimestamp is null -- no pending deliverys scans
       and mbc.multireadexception_id is null;

    writemultireaddebuglog('Create Outscans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid,deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
             dayssincelastscan,virtualyn, batchnumber)
    select /*+index(mb XPKMULTIREADBATCH)*/
           mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_at_customer,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           mbc.plannedoutroute_id,
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           null, -- qualitygrade_id
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           2, -- transaction type outscan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           null, -- notenumber,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
           nvl(mbc.virtualyn,'N') virtualyn,
           gv_batchnumber
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
--       and mbc.deliveryscantimestamp is null -- no pending deliverys scans
       and w.workstation_id = mb.workstation_id;

     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end create_outscans; -- create_outscans

   ----------------------------------------------------------------
   -- Begin f_processscanandcountbatch
   begin
    begin -- exception block
     gv_main_code_block := 'Process Scans and Counts Batch';

     retrieve_item_info;

     if (gv_databasecode not in ('FIS','PLS')) and (gv_outscantrackonly <> 'Y') then    -- ABS-17369
       if gs_ss_recordonsiteinventory = 'Y' then
         decrease_onsite_inventory;   -- for pool items not scanned in
       end if;

       Create_delivery_variations;  -- for pool items not scanned in

     end if;

     Create_garmdisp_transactions; -- for pool items not scanned in

     incr_qty_returned_unrel_loans;

     if gc_ss_uhfoutscanbundleperc > 0 then
       Update_Bundle_Status;
     end if;

     Outscanpool_update_unique_item;

     if gc_ss_scanbyroute='Y' and gv_outscangarmentsaswell then
       outscan_update_unique_item_rte;
     end if;

     Create_flags_maxwash_spectreat;

     Create_outscans;

     Remove_Flags('OutScan');

     load_uniqueitem_buffer_info;
     insertupdate_uniqueitembufinfo(2);
     create_prodprocessbufscans(2);
     delete_uniqueitem_buffer_info; -- afterwards delete bufferinfo

     Create_reject_scans(2);  -- 2 = transactiontype outscan

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(2, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processscanandcountbatch;

  -----------------------------------------------------------------------------------------
  function f_processstack(fp_stacksize number,fp_result number,fpo_virtualbundle_id out number) return number is

  --  lv_real_stacksize          number;
  --  lv_min_product_id          number;
  --  lv_min_sizedefinition_id   number;
  --  lv_max_product_id          number;
  --  lv_max_sizedefinition_id   number;
  lv_uhfbundle_id             number;
  lv_number_nonpool_items     number;
  lv_number_distinct_products number;
  lv_related_customer_id      number;
  lv_stored_packingnote_id    number;

    ---------------------------------------------
    function f_getrelatedcustomer return number is
    -- returns the customer of the packingnote
    -- or in case of no packingnote the relatedcustomerID if the same for all items in batch
    lv_relatedcustomerid   number;
    begin
     if gv_packingnote_id is not null and gv_packingnote_id > 0 then
      begin
       select d.customer_id
         into lv_relatedcustomerid
         from packingnote p
         join distributionpoint dp on dp.distributionpoint_id = p.distributionpoint_id
         join department d on d.department_id = dp.department_id
        where p.packingnote_id = gv_packingnote_id;
        return(lv_relatedcustomerid);
      exception
        when no_data_found then
          begin
            lv_relatedcustomerid := null;
            return(lv_relatedcustomerid);
          end;
      end;
     else -- gv_packingnote_id is null
      begin
        --check if the relatedcustomer_id is the same
        --and if not null and > 0
        --for any of rows in current multireadscanbatch
        select msbc.relatedcustomer_id
        into   lv_relatedcustomerid
        from   multireadscanbatchcontents msbc
        where  msbc.multireadscanbatch_id = gv_multireadscanbatch_id
        and    msbc.multireadexception_id is null
        group  by msbc.relatedcustomer_id;
        return(lv_relatedcustomerid);
      exception
        when too_many_rows then
          begin
            lv_relatedcustomerid := null; -->Do nothing customer not the same!
            return(lv_relatedcustomerid);
          end;
      end;
     end if;
    end;

    ---------------------------------------------
    procedure create_delnote_stackcheck is
      lv_businessunit_id        number;
      lv_businessunit_code      businessunit.code%type;
      lv_plantdepartmentid      plantdepartment.plantdepartment_id%type;
      lv_relatedcustomer_id     multireadscanbatchcontents.relatedcustomer_id%type;
      lv_rec_distrpoint_delnote distributionpoint%rowtype;
      lv_departmentid           department.department_id%type;
      lv_dep_occupancy          department.occupancy%type;
      lv_notenumber             packingnote.notenumber%type;

      procedure process_delnote_outscans is

        procedure get_distributionpoint_id is
        begin
          --get_distributionpoint_id
          --1)  Determine first cons.point
          --of first consumptionpoint of first department of related customer (lowest numbers)
          select t.department_id, t.occupancy
          into   lv_departmentid, lv_dep_occupancy
          from   department t
          where  t.customer_id = lv_relatedcustomer_id
          and    t.departmentnumber = (select min(tm.departmentnumber)
                                       from   department tm
                                       where  tm.customer_id = t.customer_id);
          --get distributionpoint for packingnote
          select dp.*
          into   lv_rec_distrpoint_delnote
          from   distributionpoint dp
          where  dp.department_id = lv_departmentid
          and    dp.distributionpointnumber =
                 (select min(dpm.distributionpointnumber)
                   from   distributionpoint dpm
                   where  dpm.department_id = lv_departmentid);
        end get_distributionpoint_id;

        procedure create_deliverynote is
          lv_packingnoteid packingnote.packingnote_id%type;

          procedure get_extra_info is
          begin
            --get_extra_info
            select mb.businessunit_id, bu.code,
                   (select min(pd.plantdepartment_id)
                     from   plantdepartment pd
                     where  pd.plant_id = bu.plant_id)
            into   lv_businessunit_id, lv_businessunit_code, lv_plantdepartmentid
            from   multireadscanbatch mb
            join   businessunit bu
            on     bu.businessunit_id = mb.businessunit_id
            where  mb.multireadscanbatch_id = gv_multireadscanbatch_id;
          end get_extra_info;

          procedure get_create_packingnote is

            procedure create_packingnote is
              lv_transportarticleid transportarticle.transportarticle_id%type;
            begin
              --create_packingnote
              --get defaulttransportarticle
              select ta.transportarticle_id
              into   lv_transportarticleid
              from   transportarticle ta
              where  ta.defaulttransportarticle = 'Y';
              --get packingnote number
              writemultireaddebuglog('Deliverynote for businessunit ' || lv_businessunit_code);
              execute immediate 'select SEQ_DELIVERYNOTE_' || lv_businessunit_code ||
                                '.nextval from dual'
                into lv_notenumber;
              --insert into packingnote
              insert into packingnote
                (packingnote_id, notenumber, productiondate, deliverydate, status_id, remark,
                 distributionpoint_id, deliverypoint_id, plantdepartment_id, transportarticle_id,
                 systemuser_id, processbusinessunit_id, route_id, timestamp, cleanreturn,
                 sequencenumber, deadline, occupancy, invoicebusinessunit_id, routecontrol_id,
                 originaldeliverydate, origin, stopnumber, daynumber, correctednotenumber,
                 creationtimestamp, referencenumber, returndateloan, stop_id, consignmentnote_id,
                 straightevenreturn, numberofgarmentsinlocker, numberoflockers, bulkpackingnote_id,
                 freeofchargereason_id, week, year, weighingticket_id, totalamount,
                 totalamountexcludingvat, pricescalculated, showoninvoiceappendix, deliveryremark,
                 exported, finishedpacking, picklistprinted, invoicestatus, numberofcolli,
                 emailstatus, emailmaybesent, processedtimestamp, processedsystemuser_id, signed,
                 internalprocessingbu_id, creationsystemuser_id, salesnote_id, parceltracecode,
                 calculatetransportcosts, pdfarchived, correctionfornote_id, enddateforuse,
                 correctconsignmentnote, pnremark, loadsequencenr, deliverysignature_id)
              values
                (seq_packingnote.nextval, lv_notenumber, trunc(sysdate), trunc(sysdate) + 1,
                 gc_pn_inprogress_statusid, lv_rec_distrpoint_delnote.remarkondeliverynote,
                 lv_rec_distrpoint_delnote.distributionpoint_id,
                 lv_rec_distrpoint_delnote.deliverypoint_id, lv_plantdepartmentid,
                 lv_transportarticleid, gv_systemuser_id, lv_businessunit_id, null, sysdate, 'N', 1,
                 null, lv_dep_occupancy, lv_businessunit_id, null, trunc(sysdate) + 1, 1, null,
                 getabsdaynumber(trunc(sysdate) + 1), 0, sysdate, 'STACKCHECK', null, null,
                 null, 'N', 0, 0, null, null, getisoweek(trunc(sysdate) + 1),
                 getyearofweek(trunc(sysdate) + 1), null, 0, 0, 'N', 'Y', 'N', 'N', 0, 'N', 0, 1, 0,
                 'N', null, 0, 'N', null, gv_systemuser_id, null, null, 'N', 'N', null,
                 trunc(sysdate) + 1, 0, lv_rec_distrpoint_delnote.remarkonpackingnote, 0, null)
              returning packingnote_id into lv_packingnoteid;
            end create_packingnote;
          begin
            --2) get_create_packingnote
            writemultireaddebuglog('get_create_packingnote');
            select max(pn.packingnote_id)
            into   lv_packingnoteid
            from   packingnote pn
            where  pn.distributionpoint_id = lv_rec_distrpoint_delnote.distributionpoint_id
            and    pn.deliverydate = trunc(sysdate) + 1 --Tomorrow
            and    pn.processbusinessunit_id = lv_businessunit_id
            and    pn.status_id = gc_pn_inprogress_statusid
            and    pn.referencenumber = 'STACKCHECK';
            --get existing note number
            select pn.notenumber
            into   lv_notenumber
            from   packingnote pn
            where  pn.packingnote_id = lv_packingnoteid;
            if lv_packingnoteid is null then
              begin
                create_packingnote;
              end;
              end if;
          exception
            when no_data_found then
              begin
                create_packingnote;
              end;
          end get_create_packingnote;

          procedure get_create_packingnoteline is
          begin
            --3) get_create_packingnoteline
            writemultireaddebuglog('get_create_packingnoteline');
            merge into packingnoteline pnl
            using (select lv_packingnoteid packingnote_id,
                          mbc.product_id,
                          mbc.sizedefinition_id sizedefinition_id,
                          mbc.finishingmethod_id finishingmethod_id,
                          max(p.packingsequence) packingsequence,
                          count(1) quantity
                   from   multireadscanbatchcontents mbc
                   join   product p
                   on     p.product_id = mbc.product_id
                   where  mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                   and    mbc.multireadexception_id is null
                   group by mbc.product_id,
                            mbc.sizedefinition_id,
                            mbc.finishingmethod_id) merge_subquery
            on (pnl.packingnote_id = merge_subquery.packingnote_id and
                pnl.product_id = merge_subquery.product_id and
                pnl.sizedefinition_id = merge_subquery.sizedefinition_id and
                pnl.finishingmethod_id = merge_subquery.finishingmethod_id)
            when matched then
              update
              set    pnl.deliveredamount = pnl.deliveredamount + merge_subquery.quantity,
                     pnl.scannedqty = pnl.scannedqty + merge_subquery.quantity,
                     pnl.systemuser_id = gv_systemuser_id,
                     pnl.timestamp = sysdate
            when not matched then
              insert
                (packingnoteline_id, product_id, packingsequence, finishingmethod_id, price,
                 discount, packingnote_id, sizedefinition_id, systemuser_id, location, timestamp,
                 remarkforpackinginstructions, customcode, customdescription, replacementqty,
                 updaterentqty, adjustmentreason_id, origin, putuptype, freeofchargereason_id,
                 nochargefirstissue, nochargeactiveseason, deliveredcogqty, auxiliarystatus,
                 standardamount, variationamount, deliveredamount, tobedeliveredamount, amount,
                 taxgroupcode, bundleqty, nochargefirstissuecog, scannedbundles, pricecog,
                 nodeliveryamount, creationtimestamp, creationsystemuser_id, autoreplacementqty, scannedqty)
              values
                (seq_packingnoteline.nextval, merge_subquery.product_id,
                 merge_subquery.packingsequence, merge_subquery.finishingmethod_id, null, 0,
                 merge_subquery.packingnote_id, merge_subquery.sizedefinition_id, gv_systemuser_id,
                 null, sysdate, null, null, null, 0, 0, null, 1, 1, null, 0, 0, 0, null, 0, 0,
                 merge_subquery.quantity, 0, 0, null, 0, 0, 0, null, 0, sysdate, gv_systemuser_id, 0,
                 merge_subquery.quantity);
          end get_create_packingnoteline;

        begin
          --create_deliverynote
          get_extra_info;
          --2) get_create_packingnote
          get_create_packingnote;
          --3) get_create_packingnoteline
          get_create_packingnoteline;
        end create_deliverynote;

        procedure update_uniqueitem is
        begin
          --4) update_uniqueitem
          writemultireaddebuglog('Update Unique Pool Item');
          -- For items not linked to a child packingnoteline
          MERGE INTO uniqueitem u
          USING (SELECT m1.uniqueitem_id,
                        m1.scantimestamp,
                        case when m1.secondaryid is null
                          then m.businessunit_id -- update BU upon outscan only for pool items without secID
                          else m1.businessunit_id -- original BU
                        end businessunit_id,
                        m1.stay_id,
                        u1.status_id,
                        u1.distributionpoint_id as last_distributionpoint_id
                   FROM multireadscanbatch m, multireadscanbatchcontents m1, uniqueitem u1
                  WHERE m.multireadscanbatch_id = gv_multireadscanbatch_id
                    and m1.multireadscanbatch_id = m.multireadscanbatch_id
                    and m1.uniqueitem_id = u1.uniqueitem_id
                    and m1.poolitemyn = 'Y'
                    and m1.multireadexception_id is null
                ) MERGE_SUBQUERY
          ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
          WHEN MATCHED THEN
            UPDATE
               SET  u.businessunit_id = MERGE_SUBQUERY.businessunit_id,
                    u.lastoutscandate = MERGE_SUBQUERY.scantimestamp,
                    u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                    u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                    u.washestotal = case when gc_ss_countwashesat = 'O'
                                           or (gc_ss_countwashesat='I'
                                          and gc_ss_outscanhourinterval>=gc_minimum_hour_interval -- ABS-118650
                                          and MERGE_SUBQUERY.stay_id = gc_stay_id_at_customer)
                                    then u.washestotal + 1
                                    else u.washestotal
                                    end,
                    u.prevstay_id = MERGE_SUBQUERY.stay_id,
                    u.stay_id = gc_stay_id_at_customer,
                    u.distributionpoint_id = lv_rec_distrpoint_delnote.distributionpoint_id,
                    u.lastdistributionpoint_link_id = MERGE_SUBQUERY.last_distributionpoint_id,
                    u.unrelatedloan_id = null,       -- disconnect from unrelated loan
                    u.planneddeliverydate = null,
                    u.activestocklocation_id = null,
                    u.deliveryfromstock = 'N',
                    u.lastdeliverynotenumber = lv_notenumber,
                    u.systemuser_id = gv_systemuser_id,
                    u.timestamp = sysdate;
          --update uniqueitemloss
          writemultireaddebuglog('Update unique item loss');
          merge into uniqueitemloss u
          using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
                   from multireadscanbatchcontents m, uniqueitemloss ul
                  where m.multireadscanbatch_id = gv_multireadscanbatch_id
                    and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and ul.uniqueitem_link_id = m.uniqueitem_id
                    and ul.lossstatus <= 1 -- loss charged
                    and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
                    and m.multireadexception_id is null
                    and m.poolitemyn='Y') mergequery
          on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
          when matched then
            update set u.returneddate = trunc(sysdate),
                       u.timestamp = sysdate,
                       u.systemuser_id = gv_systemuser_id;
        exception
          when no_data_found then
            null;
        end update_uniqueitem;

        procedure create_outscans is
        begin
          -- populate scan_ID
          begin
            writemultireaddebuglog('Retrieve item info step 2 scanID');
            update multireadscanbatchcontents m
            set    m.scan_id = seq_scan.nextval
            where  m.multireadscanbatch_id = gv_multireadscanbatch_id
            and    m.multireadexception_id is null
            and    m.uniqueitem_id is not null;
          exception
            when no_data_found then
              null;
          end;

          -- find secondary ID, to store in scan record when available
          begin
            writemultireaddebuglog('Retrieve item info step 3 primID and secID');
            merge /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/
            into multireadscanbatchcontents m
            using (select m1.multireadscanbatch_id, m1.subbatchnumber, su.uniqueitem_id,
                          su.secondaryid, u.primaryid
                   from   multireadscanbatchcontents m1, secondaryuniqueitem su, uniqueitem u
                   where  m1.uniqueitem_id = su.uniqueitem_id
                   and    m1.uniqueitem_id = u.uniqueitem_id
                   and    m1.multireadscanbatch_id = gv_multireadscanbatch_id
                   and    m1.uniqueitem_id is not null
                   and    m1.multireadexception_id is null) merge_subquery
            on (m.multireadscanbatch_id = merge_subquery.multireadscanbatch_id and m.subbatchnumber = merge_subquery.subbatchnumber and m.uniqueitem_id = merge_subquery.uniqueitem_id)
            when matched then
              update
              set    m.idcode = merge_subquery.primaryid, m.secondaryid = merge_subquery.secondaryid;
          exception
            when no_data_found then
              null;
          end;

          writemultireaddebuglog('Create Outscans');
          insert into scan
                  (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
                   weareremployment_link_id, distributionpoint_link_id, product_link_id,
                   sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
                   reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
                   timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
                   secondaryid,deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
                   dayssincelastscan,virtualyn)
          select /*+index(mb XPKMULTIREADBATCH)*/
                   mbc.scan_id,
                   mb.businessunit_id,
                   mbc.scantimestamp,
                   mbc.idcode,
                   mbc.relatedcustomer_id,
                   null, --weareremployment_id,
                   lv_rec_distrpoint_delnote.distributionpoint_id,
                   mbc.product_id,
                   mbc.sizedefinition_id,
                   gc_stay_id_at_customer,
                   gc_status_id_in_circ,
                   w.code, -- workstation code
                   mbc.lastissuedate,
                   null, -- plannedoutroute_id
                   null, -- reasoncode
                   nvl(mbc.customerowned,'N'),
                   getyearofweek(trunc(mbc.scantimestamp)),
                   getisoweek(trunc(mbc.scantimestamp)),
                   getabsdaynumber(trunc(mbc.scantimestamp)),
                   null, -- qualitygrade_id
                   mb.systemuser_id,
                   sysdate,
                   mbc.stay_id, -- prev stay
                   2, -- transaction type outscan
                   0, -- days late
                   mbc.uniqueitem_id,
                   mbc.secondaryid,
                   lv_notenumber,
                   trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
                   trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
                   trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
                   nvl(mbc.virtualyn,'N') virtualyn
              from multireadscanbatch         mb,
                   multireadscanbatchcontents mbc,
                   workstation                w
             where mb.multireadscanbatch_id = gv_multireadscanbatch_id
               and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
               and mbc.scan_id is not null
               and mbc.multireadexception_id is null
               and mbc.deliveryscantimestamp is null -- no pending deliverys scans
               and mbc.childpackingnoteline_id is null -- NOT linked to child packingnote
               and w.workstation_id = mb.workstation_id;
        exception
          when dup_val_on_index then
            raise gc_duplicate_exception;
          when no_data_found then
            null;
        end create_outscans;

      begin
        --process_delnote_outscansprocess_delnote_outscans
        --1)  Determine first cons.point
        get_distributionpoint_id;
        --2/3) Update/create deliverynote/line
        create_deliverynote;
        --4) update uniqueitem
        update_uniqueitem;
        --5) create_outscans
        create_outscans;
      end process_delnote_outscans;
    begin
      --ABS-54916 Create outscans and delivery note for approved stacks for customer related items
      lv_relatedcustomer_id := f_getrelatedcustomer;

      if lv_relatedcustomer_id > 0 then
        begin
          process_delnote_outscans;
          load_uniqueitem_buffer_info;
          insertupdate_uniqueitembufinfo(2);
          create_prodprocessbufscans(2);
          delete_uniqueitem_buffer_info; -- afterwards delete bufferinfo
        end;
      end if;
    end create_delnote_stackcheck;

  ---------------------------------------------
   procedure setPackingNoteInProgress is
      begin
         if gv_packingnote_id > 0 then
            update packingnote pn
            set pn.status_id = (select s.status_id from status s where s.statustype = 'PN' and s.code = '20'),
                pn.timestamp = sysdate, pn.systemuser_id = gv_systemuser_id
            where pn.packingnote_id = gv_packingnote_id
              and pn.status_id = (select s.status_id from status s where s.statustype = 'PN' and s.code = '10');
        end if;
      end;
  ---------------------------------------------

  begin
    begin
      -- exception block
      gv_main_code_block := 'Process Stack';
      gv_code_block      := 'Check Stack Size';
      fpo_virtualbundle_id := null;

      gv_code_block := 'Step 1 Delete Old Bundles';
      delete
        from uhfbundle ub
        where ub.uhfbundle_id in
            (select distinct mbc.uhfbundle_id
               from multireadscanbatchcontents mbc
              where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                and mbc.uhfbundle_id is not null);
      commit;

      if fp_result = 0 then
        --  When Stack Approved
        if gv_ss_createdelnotestackcheck = 0 then
          begin
            -- count number of garment items
            writemultireaddebuglog('Step 2a Determine Contents');
            select count(1) number_nonpool_items
              into lv_number_nonpool_items
              from multireadscanbatchcontents m
             where m.multireadscanbatch_id = gv_multireadscanbatch_id
               and m.poolitemyn='N';

            select count(distinct m.product_id) number_distinct_products
              into lv_number_distinct_products
              from multireadscanbatchcontents m
             where m.multireadscanbatch_id = gv_multireadscanbatch_id;

            -- do not create bundles if there are garments in the bundle and system setting stackchkpersonalbundle = N
            if lv_number_nonpool_items = 0 or
               (lv_number_nonpool_items > 0 and gv_ss_stackchkpersonalbundle = 'Y')  then
              gv_code_block := 'Step 2b Create UHF Bundle';

              lv_related_customer_id := f_getrelatedcustomer;

              --get sequence
              select seq_uniquebundle.nextval
               into lv_uhfbundle_id
               from dual;
               --
               if gv_packingnote_id is not null and gv_packingnote_id > 0 then
                 lv_stored_packingnote_id := gv_packingnote_id;
               else lv_stored_packingnote_id := null;
               end if;
              insert into uhfbundle
                 (uhfbundle_id,
                  businessunit_id,
                  product_link_id,
                  sizedefinition_link_id,
                  bundlesize,
                  workstation,
                  systemuser_id,
                  timestamp,
                  deliverystatus,
                  pack,
                  bundleprimaryid,
                  creationdate,
                  relatedcustomer_id,
                  packingnote_id
                  )
              select lv_uhfbundle_id,
                      mb.businessunit_id,
                      case when ((mb.stackcheckpack='Y' and mb.stackcheckproductidentified = 'N')
                              or (mb.stackcheckpack='N' and lv_number_distinct_products > 1))
                             and gv_dbSetting <> 'PED'
                        then null
                        else mb.stackcheckproduct_id
                      end,
                      case when mb.stackcheckpack='N' and (lv_number_distinct_products = 1 or gv_dbSetting = 'PED')
                        then mb.stackchecksize_id
                        else null
                      end,
                      fp_stacksize,
                      w.code,
                      gv_systemuser_id,
                      sysdate,
                      1, -- means not yet delivered
                      mb.stackcheckpack,
                      w.currentbatchno,
                      sysdate,
                      lv_related_customer_id,
                      lv_stored_packingnote_id
                 from multireadscanbatch mb,
                      workstation w
                where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                  and w.workstation_id = mb.workstation_id;

              gv_code_block := 'Step 3 Link UniqueItems to UHF Bundle';
              merge into uniqueitem u
              using
              (select mbc.uniqueitem_id
                 from multireadscanbatchcontents mbc
                where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                  and mbc.multireadexception_id is null) merge_subquery
             on (u.uniqueitem_id = merge_subquery.uniqueitem_id)
              when matched then
                update set u.uhfbundle_id = lv_uhfbundle_id;

              fpo_virtualbundle_id := lv_uhfbundle_id;
            end if;

            setPackingNoteInProgress;

            if gv_prodprocessbuffer_id is not null then
              load_uniqueitem_buffer_info;
              insertupdate_uniqueitembufinfo(0);
              create_prodprocessbufscans(0);
            end if;
          end;
        end if; -- gv_ss_createdelnotestackcheck = 0

        --ABS-54916
        if gv_ss_createdelnotestackcheck = 1 then
          begin
            create_delnote_stackcheck;
          end;
        end if;

        commit; -- overall commit on updates and inserts.
      end if; -- fp_result = 0 (Approved)

      return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
  end f_processstack;

  -----------------------------------------------------------------------------------------
  function f_processrewashscanbatch(fp_reason_id in number) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;
   lv_number_orpack_items   number := 0;
   lv_number_assigned_items number := 0;
   lv_number_ragged_items   number := 0;
   lv_number_loan_items     number := 0;
   lv_number_assigned_items_deliv     number := 0;


   ---------------------------------------------
   procedure retrieve_main_item_info is

   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    nvl(nvl(u.relatedcustomer_id,
                       (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = u.distributionpoint_id
                           and de1.department_id = di1.department_id)),
                        (select de2.customer_id
                           from distributionpoint di2,
                                department de2
                          where di2.distributionpoint_id = u.lastdistributionpoint_link_id
                            and de2.department_id = di2.department_id)) customer_id,
                    u.distributionpoint_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = u.distributionpoint_id) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 pool items
   -------------
   if lv_number_nonpool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1b nonpool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    w.customer_id,
                    we.weareremployment_id,
                    we.distributionpoint_id,
                    case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select g.deliverypoint_id
                                    from garmentdispenser g
                                   where g.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u,
                    uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                    weareremployment we, wearer w
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.uniqueitem_id = unp.uniqueitem_id
                and we.weareremployment_id = unp.weareremployment_id
                and w.wearer_id = we.wearer_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                --and m1.multireadexception_id is null   --removed so that for rejected scans wearer is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 personalized garments (non pool)
   end; -- retrieve_main_item_info

   ---------------------------------------------
   procedure retrieve_item_info is

   begin
    -- find plpc
    begin
    writemultireaddebuglog('Retrieve item info step 2a plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.customer_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id,
               m.scan_id = seq_scan.nextval;
    exception
      when no_data_found then
         null;
    end;
    -- load delayed even exchange and related dee delivery scheme
    begin
    writemultireaddebuglog('Retrieve item info step 2b plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    p.delayedevenexchange,
                    p.deedeliveryscheme_id
               FROM multireadscanbatchcontents m1, productlistpercustomer p
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.productlistpercustomer_id = m1.plpc_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.delayedevenexchange = MERGE_SUBQUERY.delayedevenexchange,
               m.deedeliveryscheme_id = MERGE_SUBQUERY.deedeliveryscheme_id;
    exception
      when no_data_found then
        null;
    end;

    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;
   end; -- retrieve_item_info

   ---------------------------------------------
   procedure rewash_update_unique_item is
   begin
     begin
      writemultireaddebuglog('Update_unique item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    case when m1.poolitemyn='Y' and m1.secondaryid is null
                      then m.businessunit_id -- update BU upon inscan only for pool items without secID
                      else m1.businessunit_id -- original BU
                    end businessunit_id,
                    m1.stay_id,
                    m1.status_id,
                    case when u1.status_id <> gc_status_id_in_circ
                     then m1.scantimestamp
                     else u1.statuschangedate
                    end statuschangedate,
                    u1.lastdistributionpoint_link_id,
                    m1.plannedoutdate,
                    u1.planneddeliverydate,
                    m1.distributionpoint_id,
                    m1.poolitemyn,
                    m1.weareremployment_id
               FROM multireadscanbatch m, multireadscanbatchcontents m1, uniqueitem u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and m.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.businessunit_id = MERGE_SUBQUERY.businessunit_id,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.washestotal = u.washestotal + 1,
                u.rewashtotal = u.rewashtotal + 1,
                u.prevstatus_id = case when MERGE_SUBQUERY.status_id <> gc_status_id_in_circ
                                   then MERGE_SUBQUERY.status_id
                                   else null
                                  end,
                u.status_id = case when MERGE_SUBQUERY.status_id = gc_status_id_assigned and gs_ss_bringincircatinscan = 1
                                       and not exists
                                       (SELECT 1 FROM DELIVERYSCAN DS JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
                                         WHERE UI.STARTRENTFROM = 3 and DS.PACKINGNOTE_ID IS NOT NULL
                                         and DS.UNIQUEITEM_LINK_ID = MERGE_SUBQUERY.uniqueitem_id
                                         and DS.WEAREREMPLOYMENT_LINK_ID = MERGE_SUBQUERY.weareremployment_id)
                               then
                                 gc_status_id_assigned
                               else
                                 gc_status_id_in_circ
                               end,
                u.statuschangedate = MERGE_SUBQUERY.statuschangedate,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_in_rewash,
                u.distributionpoint_id = null,   -- disconnect from previous user
                u.lastdistributionpoint_link_id =
                                                  case when MERGE_SUBQUERY.poolitemyn = 'Y'
                                                   then nvl(MERGE_SUBQUERY.distributionpoint_id,lastdistributionpoint_link_id)
                                                   else null
                                                  end,
                u.unrelatedloan_id = null,       -- disconnect from unrelated loan
                u.currentuniquebundle_id = null, -- disconnect from bundle
                u.planneddeliverydate = case when MERGE_SUBQUERY.poolitemyn = 'N'
                                         then nvl(MERGE_SUBQUERY.plannedoutdate,MERGE_SUBQUERY.planneddeliverydate)
                                         else null
                                        end,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
      --
      writemultireaddebuglog('Update unique item non pool');
      MERGE INTO uniqueitemnonpool u
      USING (SELECT m1.uniqueitem_id,
                    m1.stay_id
               FROM multireadscanbatchcontents m1, uniqueitemnonpool u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.washesthisissue = u.washesthisissue + 1,
                u.rewashthisissue = u.rewashthisissue + 1,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    --
    writemultireaddebuglog('Update unique item loss');
    merge into uniqueitemloss u
    using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
             from multireadscanbatchcontents m, uniqueitemloss ul
            where m.multireadscanbatch_id = gv_multireadscanbatch_id
              and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              and ul.uniqueitem_link_id = m.uniqueitem_id
              and ul.lossstatus <= 1 -- loss charged
              and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
              and m.multireadexception_id is null) mergequery
    on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
    when matched then
      update set u.returneddate = trunc(sysdate),
                 u.timestamp = sysdate,
                 u.systemuser_id = gv_systemuser_id;
    exception
      when no_data_found then
        null;
    end;
   end; -- rewash_update_unique_item

   --------------------------------------------------------------
   procedure rewash_update_unique_item_rte is
   lv_lastinroute             number;
   lv_inroutestop_id          number;
   lv_inroutecontrol_id       number;
   lv_lastinstop              number;
   lv_lastinroutestop_id      number;
   lv_lastindate              date;
   lv_plannedoutroute_id      number;
   lv_plannedoutroutestop_id  number;
   lv_outroutecontrol_id      number;
   lv_outstop_id              number;
   lv_plannedoutdate          date;
   lv_delayedevenexchange     number;
   lv_routecontrol_exists     varchar2(1);

   begin
     begin
       writemultireaddebuglog('Update unique item route');
       for vcursorO in (SELECT m1.uniqueitem_id,
                               uir.lastindate,
                               uir.lastinroute_id,
                               uir.lastinstop_id,
                               uir.plannedoutdate,
                               uir.plannedoutroute_id,
                               uir.lastoutdate,
                               m1.customer_id,
                               m1.deliverypoint_id,
                               m1.typeofmerchandize,
                               m1.plpc_id,
                               m1.delayedevenexchange,
                               m1.deedeliveryscheme_id,
                               m1.distributionpoint_id,
                               nvl(uir.uniqueitem_id,-1) uniqueitemroute_id
                          FROM multireadscanbatchcontents m1, uniqueitem u
                               left outer join uniqueitemroute uir on u.uniqueitem_id = uir.uniqueitem_id
                         WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                           and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                           and m1.uniqueitem_id = u.uniqueitem_id
                           and m1.multireadexception_id is null
                           and m1.poolitemyn = 'N'
                           and (nvl(uir.lastindate,to_date('01-01-1900','dd-mm-yyyy'))        =  to_date('01-01-1900','dd-mm-yyyy')
                                or nvl(uir.plannedoutdate,to_date('01-01-1900','dd-mm-yyyy')) <= nvl(uir.lastoutdate,to_date('01-01-1900','dd-mm-yyyy'))
                                or nvl(uir.plannedoutdate,to_date('01-01-1900','dd-mm-yyyy')) >  trunc(sysdate))
                       )
       loop
        lv_delayedevenexchange := vcursorO.Delayedevenexchange;
        -- safety net1: when plpc not found put delayed even exchange to 1.
        if vcursorO.plpc_id is null then
          lv_delayedevenexchange := 1;
        end if;
        -- safety net2: when dee not populated put delayed even exchange to 1 for garments.
        if vcursorO.delayedevenexchange = 7 AND vcursorO.deedeliveryscheme_id is null then
          lv_delayedevenexchange := 1;
        end if;

        -- initialize
        lv_outstop_id := null;
        lv_lastinstop := null;
        if vcursorO.lastindate is null or vcursorO.lastindate <= vcursorO.lastoutdate
          then -- items was probably not scanned in, so determine inscan date first.
            if gs_ss_deliverydetermination = 1 then
               pack_deliverybasics.determinedeldateroutesoil(gv_plant_id, vcursorO.customer_id, vcursorO.deliverypoint_id, null, vcursorO.typeofmerchandize,
                                                             trunc(sysdate), vcursorO.plpc_id, vcursorO.distributionpoint_id, 'N', lv_lastinroute, lv_inroutestop_id,
                                                             lv_inroutecontrol_id, lv_lastinstop, lv_lastindate, lv_plannedoutroute_id, lv_plannedoutroutestop_id,
                                                             lv_outroutecontrol_id, lv_outstop_id, lv_plannedoutdate);
            else
               pack_sort.getlastinroute(vcursorO.customer_id,trunc(sysdate),
                                        vcursorO.deliverypoint_id, vcursorO.typeofmerchandize,
                                        lv_lastinroute, lv_inroutestop_id, lv_lastindate);
               if lv_delayedevenexchange > 0 then
                 pack_sort.fillplannedoutroute(gv_plant_id,
                                              trunc(sysdate),
                                              vcursorO.typeofmerchandize,
                                              lv_delayedevenexchange,
                                              vcursorO.deedeliveryscheme_id,
                                              vcursorO.plpc_id,
                                              vcursorO.customer_id,
                                              vcursorO.deliverypoint_id,
                                              lv_lastinroute,
                                              nvl(lv_lastindate,trunc(sysdate)),
                                              lv_lastinroutestop_id,
                                              lv_plannedoutroutestop_id,
                                              lv_plannedoutroute_id,
                                              lv_plannedoutdate,
                                              gc_ss_scanbyroute);
               end if; -- lv_delayedevenexchange > 0 then
            end if; -- gs_ss_deliverydetermination = 1
          else  -- item was already scanned in. only determine new planned out date.
             lv_lastindate := vcursorO.lastindate;
             lv_lastinroute := vcursorO.lastinroute_id;
             lv_lastinstop := vcursorO.lastinstop_id;
             lv_lastinroutestop_id := null;
             if lv_delayedevenexchange >= 0 then
                if gs_ss_deliverydetermination = 1 then
                   pack_deliverybasics.determinedeldaterouteclean(gv_plant_id, vcursorO.customer_id, vcursorO.deliverypoint_id, null, vcursorO.typeofmerchandize,
                                                                 trunc(sysdate), vcursorO.plpc_id, vcursorO.distributionpoint_id, 'N',
                                                                 lv_plannedoutroutestop_id, lv_plannedoutroute_id,
                                                                 lv_outstop_id, lv_outroutecontrol_id, lv_plannedoutdate);
                else
                     pack_sort.fillplannedoutroute(gv_plant_id,
                                                  trunc(sysdate),
                                                  vcursorO.typeofmerchandize,
                                                  1,  --lv_delayedevenexchange put to first next visit
                                                  null, --deescheme
                                                  vcursorO.plpc_id,
                                                  vcursorO.customer_id,
                                                  vcursorO.deliverypoint_id,
                                                  lv_lastinroute,
                                                  nvl(lv_lastindate,trunc(sysdate)),
                                                  lv_lastinroutestop_id,
                                                  lv_plannedoutroutestop_id,
                                                  lv_plannedoutroute_id,
                                                  lv_plannedoutdate,
                                                  gc_ss_scanbyroute);
              end if; -- gs_ss_deliverydetermination = 1
             end if; --  lv_delayedevenexchange >= 0
        end if;  -- vcursorO.lastindate is null or vcursorO.lastindate <= vcursorO.lastoutdate

        if vcursorO.uniqueitemroute_id = -1 then
          INSERT INTO uniqueitemroute
             (uniqueitem_id,
              lastinroute_id,
              lastoutroute_id,
              plannedoutroute_id,
              lastindate,
              lastoutdate,
              plannedoutdate,
              systemuser_id,
              timestamp,
              lastinstop_id,
              lastoutstop_id,
              plannedoutstop_id
              )
          VALUES
            (vcursorO.uniqueitem_id,
             lv_lastinroute,
             null, --lastoutroute_id
             lv_plannedoutroute_id,
             lv_lastindate,
             null, -- lastoutdate
             lv_plannedoutdate,
             gv_systemuser_id,
             sysdate,
             lv_lastinstop,
             null, -- lastoutstop_id,
             lv_outstop_id
             );
        else
          UPDATE uniqueitemroute u
             SET u.lastindate = lv_lastindate,
                 u.lastinroute_id = lv_lastinroute,
                 u.lastinstop_id = lv_lastinstop,
                 u.plannedoutdate = lv_plannedoutdate,
                 u.plannedoutroute_id = lv_plannedoutroute_id,
                 u.plannedoutstop_id = lv_outstop_id,
                 u.systemuser_id = gv_systemuser_id,
                 u.timestamp = sysdate
           WHERE u.uniqueitem_id = vcursorO.uniqueitem_id;
        end if;

        update multireadscanbatchcontents mbc
           set mbc.plannedoutdate = lv_plannedoutdate
         where mbc.uniqueitem_id = vcursorO.uniqueitem_id;

        if gc_ss_routecontrolcreation >= 3 and lv_plannedoutroute_id is not null and lv_plannedoutdate is not null then
          begin
          select 'Y'
            into lv_routecontrol_exists
            from routecontrol r
           where r.route_id = lv_plannedoutroute_id
             and r.originaldrivingdate = lv_plannedoutdate;
          exception
          when no_data_found then
            lv_routecontrol_exists := 'N';
          end;
          if lv_routecontrol_exists = 'Y' then
             create_route_control(lv_plannedoutroute_id,lv_plannedoutdate);
          end if;
        end if; -- gc_ss_routecontrolcreation >= 3
       end loop;
      --
    exception
      when no_data_found then
        null;
    end;
   end; -- inscan_update_unique_item_route

   ---------------------------------------------
   procedure create_rewashscans is
   begin
    -- populate scan_ID in case it was not yet populated by retrieve item info
    begin
    writemultireaddebuglog('Create rewashscans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create rewashscans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan)
    select mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_in_rewash,
           case when mbc.status_id = gc_status_id_assigned and gs_ss_bringincircatinscan = 1
                     and not exists
                     (SELECT 1 FROM DELIVERYSCAN DS JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
                       WHERE UI.STARTRENTFROM = 3 and DS.PACKINGNOTE_ID IS NOT NULL
                       and DS.UNIQUEITEM_LINK_ID = mbc.uniqueitem_id
                       and DS.WEAREREMPLOYMENT_LINK_ID = mbc.weareremployment_id)
             then
               gc_status_id_assigned
             else
               gc_status_id_in_circ
             end,
           w.code, -- workstation code
           mbc.lastissuedate,
           uir.lastinroute_id,
           fp_reason_id, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           4, -- transaction type rewashscan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc
           left outer join uniqueitemroute uir on mbc.uniqueitem_id = uir.uniqueitem_id,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end; -- create_rewashscans
   ----------------------------------------------------------------
   procedure CREATE_PACKINGNOTE_FOR_REWASH is
     LV_PACKINGNOTEID        PACKINGNOTE.PACKINGNOTE_ID%type;
     LV_BUSINESSUNIT_ID      number;
     LV_BUSINESSUNIT_CODE    BUSINESSUNIT.CODE%type;
     LV_PLANTDEPARTMENTID    PLANTDEPARTMENT.PLANTDEPARTMENT_ID%type;
     LV_TRANSPORTARTICLEID   TRANSPORTARTICLE.TRANSPORTARTICLE_ID%type;
     LV_NOTENUMBER           PACKINGNOTE.NOTENUMBER%type;
     LV_DISTRIBUTIONPOINT_ID number;
     LV_DELIVERYPOINT_ID     number;
     LV_DEP_OCCUPANCY        number;

     procedure CREATE_PN is

     begin
       WRITEMULTIREADDEBUGLOG('CREATE PACKINGNOTE FOR REWASH');

       --get packingnote number

       execute immediate 'select SEQ_DELIVERYNOTE_' || LV_BUSINESSUNIT_CODE ||
                         '.nextval from dual'
         into LV_NOTENUMBER;

       WRITEMULTIREADDEBUGLOG('create packingnote');
       --insert into packingnote
       insert into PACKINGNOTE
         (PACKINGNOTE_ID,
          NOTENUMBER,
          PRODUCTIONDATE,
          DELIVERYDATE,
          STATUS_ID,
          REMARK,
          DISTRIBUTIONPOINT_ID,
          DELIVERYPOINT_ID,
          PLANTDEPARTMENT_ID,
          TRANSPORTARTICLE_ID,
          SYSTEMUSER_ID,
          PROCESSBUSINESSUNIT_ID,
          ROUTE_ID,
          timestamp,
          CLEANRETURN,
          SEQUENCENUMBER,
          DEADLINE,
          OCCUPANCY,
          INVOICEBUSINESSUNIT_ID,
          ROUTECONTROL_ID,
          ORIGINALDELIVERYDATE,
          ORIGIN,
          STOPNUMBER,
          DAYNUMBER,
          CORRECTEDNOTENUMBER,
          CREATIONTIMESTAMP,
          REFERENCENUMBER,
          RETURNDATELOAN,
          STOP_ID,
          CONSIGNMENTNOTE_ID,
          STRAIGHTEVENRETURN,
          NUMBEROFGARMENTSINLOCKER,
          NUMBEROFLOCKERS,
          BULKPACKINGNOTE_ID,
          FREEOFCHARGEREASON_ID,
          WEEK,
          year,
          WEIGHINGTICKET_ID,
          TOTALAMOUNT,
          TOTALAMOUNTEXCLUDINGVAT,
          PRICESCALCULATED,
          SHOWONINVOICEAPPENDIX,
          DELIVERYREMARK,
          EXPORTED,
          FINISHEDPACKING,
          PICKLISTPRINTED,
          INVOICESTATUS,
          NUMBEROFCOLLI,
          EMAILSTATUS,
          EMAILMAYBESENT,
          PROCESSEDTIMESTAMP,
          PROCESSEDSYSTEMUSER_ID,
          SIGNED,
          INTERNALPROCESSINGBU_ID,
          CREATIONSYSTEMUSER_ID,
          SALESNOTE_ID,
          PARCELTRACECODE,
          CALCULATETRANSPORTCOSTS,
          PDFARCHIVED,
          CORRECTIONFORNOTE_ID,
          ENDDATEFORUSE,
          CORRECTCONSIGNMENTNOTE,
          PNREMARK,
          LOADSEQUENCENR,
          DELIVERYSIGNATURE_ID)
       values
         (SEQ_PACKINGNOTE.NEXTVAL,
          LV_NOTENUMBER,
          TRUNC(sysdate),
          TRUNC(sysdate) + 1,
          GC_PN_PACKINGNOTE_STATUS_ID,
          null,
          LV_DISTRIBUTIONPOINT_ID,
          LV_DELIVERYPOINT_ID,
          LV_PLANTDEPARTMENTID,
          LV_TRANSPORTARTICLEID,
          GV_SYSTEMUSER_ID,
          LV_BUSINESSUNIT_ID,
          null,
          sysdate,
          'N',
          1,
          null,
          LV_DEP_OCCUPANCY,
          LV_BUSINESSUNIT_ID,
          null,
          TRUNC(sysdate) + 1,
          1,
          null,
          GETABSDAYNUMBER(TRUNC(sysdate) + 1),
          0,
          sysdate,
          null,
          null,
          null,
          null,
          'N',
          0,
          0,
          null,
          null,
          GETISOWEEK(TRUNC(sysdate) + 1),
          GETYEAROFWEEK(TRUNC(sysdate) + 1),
          null,
          0,
          0,
          'N',
          'Y',
          'N',
          'N',
          0,
          'N',
          0,
          1,
          0,
          'N',
          null,
          0,
          'N',
          null,
          GV_SYSTEMUSER_ID,
          null,
          null,
          'N',
          'N',
          null,
          TRUNC(sysdate) + 1,
          0,
          'REWASH',
          0,
          null)
       returning PACKINGNOTE_ID into LV_PACKINGNOTEID;
     end CREATE_PN;

     procedure CREATE_PNL is
     begin
       WRITEMULTIREADDEBUGLOG('add packingnoteline');
       merge into PACKINGNOTELINE PNL
       using (select LV_PACKINGNOTEID PACKINGNOTE_ID,
                     MBC.PRODUCT_ID,
                     MBC.SIZEDEFINITION_ID SIZEDEFINITION_ID,
                     MBC.FINISHINGMETHOD_ID FINISHINGMETHOD_ID,
                     (select PACKINGSEQUENCE
                        from PRODUCT
                       where PRODUCT_ID = MBC.PRODUCT_ID) PACKINGSEQUENCE
                from MULTIREADSCANBATCHCONTENTS MBC
                join UNIQUEITEM U
                  on U.UNIQUEITEM_ID = MBC.UNIQUEITEM_ID
               where MBC.MULTIREADSCANBATCH_ID = GV_MULTIREADSCANBATCH_ID
                 and MBC.MULTIREADEXCEPTION_ID is null
                 and MBC.POOLITEMYN = 'Y'
                 and NVL(MBC.DISTRIBUTIONPOINT_ID,
                         U.LASTDISTRIBUTIONPOINT_LINK_ID) =
                     LV_DISTRIBUTIONPOINT_ID
               group by MBC.PRODUCT_ID,
                        MBC.SIZEDEFINITION_ID,
                        MBC.FINISHINGMETHOD_ID) MERGE_SUBQUERY
       on (PNL.PACKINGNOTE_ID = MERGE_SUBQUERY.PACKINGNOTE_ID and PNL.PRODUCT_ID = MERGE_SUBQUERY.PRODUCT_ID and PNL.SIZEDEFINITION_ID = MERGE_SUBQUERY.SIZEDEFINITION_ID and PNL.FINISHINGMETHOD_ID = MERGE_SUBQUERY.FINISHINGMETHOD_ID)
       when not matched then
         insert
           (PACKINGNOTELINE_ID,
            PRODUCT_ID,
            PACKINGSEQUENCE,
            FINISHINGMETHOD_ID,
            PRICE,
            DISCOUNT,
            PACKINGNOTE_ID,
            SIZEDEFINITION_ID,
            SYSTEMUSER_ID,
            LOCATION,
            timestamp,
            REMARKFORPACKINGINSTRUCTIONS,
            CUSTOMCODE,
            CUSTOMDESCRIPTION,
            REPLACEMENTQTY,
            UPDATERENTQTY,
            ADJUSTMENTREASON_ID,
            ORIGIN,
            PUTUPTYPE,
            FREEOFCHARGEREASON_ID,
            NOCHARGEFIRSTISSUE,
            NOCHARGEACTIVESEASON,
            DELIVEREDCOGQTY,
            AUXILIARYSTATUS,
            STANDARDAMOUNT,
            VARIATIONAMOUNT,
            DELIVEREDAMOUNT,
            TOBEDELIVEREDAMOUNT,
            AMOUNT,
            TAXGROUPCODE,
            BUNDLEQTY,
            NOCHARGEFIRSTISSUECOG,
            SCANNEDBUNDLES,
            PRICECOG,
            NODELIVERYAMOUNT,
            CREATIONTIMESTAMP,
            CREATIONSYSTEMUSER_ID,
            AUTOREPLACEMENTQTY)
         values
           (SEQ_PACKINGNOTELINE.NEXTVAL,
            MERGE_SUBQUERY.PRODUCT_ID,
            MERGE_SUBQUERY.PACKINGSEQUENCE,
            MERGE_SUBQUERY.FINISHINGMETHOD_ID,
            null,
            0,
            MERGE_SUBQUERY.PACKINGNOTE_ID,
            MERGE_SUBQUERY.SIZEDEFINITION_ID,
            GV_SYSTEMUSER_ID,
            null,
            sysdate,
            null,
            null,
            null,
            0,
            0,
            null,
            1,
            1,
            null,
            0,
            0,
            0,
            null,
            0,
            0,
            0,
            0,
            0,
            null,
            0,
            0,
            0,
            null,
            0,
            sysdate,
            GV_SYSTEMUSER_ID,
            0);

     end CREATE_PNL;

  procedure CREATE_PNLSPECIAL is
  begin
    WRITEMULTIREADDEBUGLOG('add packingnotelinespecial for qtyRewash');
    merge into PACKINGNOTELINESPECIAL PNLS
    using (select (select PNL.PACKINGNOTELINE_ID
             from PACKINGNOTELINE PNL
            where PNL.PACKINGNOTE_ID = LV_PACKINGNOTEID
            and PNL.PRODUCT_ID = MBC.PRODUCT_ID
            and PNL.SIZEDEFINITION_ID = MBC.SIZEDEFINITION_ID
            and PNL.FINISHINGMETHOD_ID = MBC.FINISHINGMETHOD_ID) PACKINGNOTELINE_ID,
          count(*) QTY
         from MULTIREADSCANBATCHCONTENTS MBC
         join UNIQUEITEM U
         on U.UNIQUEITEM_ID = MBC.UNIQUEITEM_ID
        where MBC.MULTIREADSCANBATCH_ID = GV_MULTIREADSCANBATCH_ID
        and MBC.MULTIREADEXCEPTION_ID is null
        and MBC.POOLITEMYN = 'Y'
        and NVL(MBC.DISTRIBUTIONPOINT_ID,
            U.LASTDISTRIBUTIONPOINT_LINK_ID) =
          LV_DISTRIBUTIONPOINT_ID
        group by MBC.PRODUCT_ID,
             MBC.SIZEDEFINITION_ID,
             MBC.FINISHINGMETHOD_ID) MERGE_SUBQUERY
    on (PNLS.PACKINGNOTELINE_ID = MERGE_SUBQUERY.PACKINGNOTELINE_ID)
    when matched then
    update
       set PNLS.QTYREWASH     = PNLS.QTYREWASH + MERGE_SUBQUERY.QTY,
         PNLS.SYSTEMUSER_ID = GV_SYSTEMUSER_ID,
         PNLS.TIMESTAMP     = sysdate
    when not matched then
    insert
      (PACKINGNOTELINE_ID, QTYREWASH, SYSTEMUSER_ID, TIMESTAMP)
    values
      (MERGE_SUBQUERY.PACKINGNOTELINE_ID,
       MERGE_SUBQUERY.QTY,
       GV_SYSTEMUSER_ID,
       sysdate);
  end CREATE_PNLSPECIAL;

   begin
     --get businessunit info
     select MB.BUSINESSUNIT_ID,
            BU.CODE,
            (select min(PD.PLANTDEPARTMENT_ID)
               from PLANTDEPARTMENT PD
              where PD.PLANT_ID = BU.PLANT_ID)
       into LV_BUSINESSUNIT_ID, LV_BUSINESSUNIT_CODE, LV_PLANTDEPARTMENTID
       from MULTIREADSCANBATCH MB
       join BUSINESSUNIT BU
         on BU.BUSINESSUNIT_ID = MB.BUSINESSUNIT_ID
      where MB.MULTIREADSCANBATCH_ID = GV_MULTIREADSCANBATCH_ID;

     --get defaulttransportarticle
     select TA.TRANSPORTARTICLE_ID
       into LV_TRANSPORTARTICLEID
       from TRANSPORTARTICLE TA
      where TA.DEFAULTTRANSPORTARTICLE = 'Y';

     for X in (
               --get distributionpoint and deliverypoint
               select distinct NVL(MC.DISTRIBUTIONPOINT_ID,
                           NVL(U.LASTDISTRIBUTIONPOINT_LINK_ID, -1)) DISTRIBUTIONPOINT_ID,
                       NVL(MC.DELIVERYPOINT_ID,
                           (select DP.DELIVERYPOINT_ID
                              from DISTRIBUTIONPOINT DP
                             where NVL(MC.DISTRIBUTIONPOINT_ID,
                                       U.LASTDISTRIBUTIONPOINT_LINK_ID) =
                                   DP.DISTRIBUTIONPOINT_ID)) DELIVERYPOINT_ID,
                       MC.BUSINESSUNIT_ID
                 from MULTIREADSCANBATCHCONTENTS MC
                 join UNIQUEITEM U
                   on U.UNIQUEITEM_ID = MC.UNIQUEITEM_ID
                where MC.MULTIREADSCANBATCH_ID = GV_MULTIREADSCANBATCH_ID
                  and MC.POOLITEMYN = 'Y'
                  and MC.MULTIREADEXCEPTION_ID is null
                group by MC.DISTRIBUTIONPOINT_ID,
                          U.LASTDISTRIBUTIONPOINT_LINK_ID,
                          MC.DELIVERYPOINT_ID,
                          MC.BUSINESSUNIT_ID) loop
       begin
         LV_DISTRIBUTIONPOINT_ID := X.DISTRIBUTIONPOINT_ID;
         LV_DELIVERYPOINT_ID     := X.DELIVERYPOINT_ID;

         --get occupancy
         select D.OCCUPANCY
           into LV_DEP_OCCUPANCY
           from DEPARTMENT D, DISTRIBUTIONPOINT DP
          where DP.DEPARTMENT_ID = D.DEPARTMENT_ID
            and DP.DISTRIBUTIONPOINT_ID = LV_DISTRIBUTIONPOINT_ID;

         LV_PACKINGNOTEID := 0;
         select PN.PACKINGNOTE_ID
           into LV_PACKINGNOTEID
           from PACKINGNOTE PN
          where PN.PRODUCTIONDATE = TRUNC(sysdate)
            and PN.STATUS_ID in
                (GC_PN_INPROGRESS_STATUSID, GC_PN_PACKINGNOTE_STATUS_ID)
            and PN.DISTRIBUTIONPOINT_ID = LV_DISTRIBUTIONPOINT_ID
            and PN.PNREMARK = 'REWASH';

         CREATE_PNL;
         CREATE_PNLSPECIAL;
       exception
         when NO_DATA_FOUND then
           begin
             if LV_DISTRIBUTIONPOINT_ID > 0 then
               CREATE_PN;
               CREATE_PNL;
               CREATE_PNLSPECIAL;
             end if;
           end;
       end;
     end loop;
   end CREATE_PACKINGNOTE_FOR_REWASH;
   ----------------------------------------------------------------
   -- Begin f_processmultireadrewashcanbatch
   begin
      begin
        gv_main_code_block := 'Process Rewashscan Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items,
               sum(case when m.orpackitemyn='Y' then 1 else 0 end) number_orpack_items,
               sum(case when s.code='30' then 1 else 0 end) number_assigned_items,
               sum(case when s.code='40' then 1 else 0 end) number_ragged_items,
               sum(case when m.unrelatedloan_id is not null then 1 else 0 end) number_loan_items,
               sum(case when s.code='30' and gs_ss_bringincircatinscan = 1 and exists
               ( SELECT 1 FROM DELIVERYSCAN DS
                 JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
                 JOIN UNIQUEITEMNONPOOL UINP on UINP.UNIQUEITEM_ID = UI.UNIQUEITEM_ID
               WHERE UI.STARTRENTFROM = 3 and DS.PACKINGNOTE_ID IS NOT NULL
               and DS.UNIQUEITEM_LINK_ID = m.uniqueitem_id
               and DS.WEAREREMPLOYMENT_LINK_ID = UINP.WEAREREMPLOYMENT_ID )
               then 1 else 0 end) number_assigned_items_deliverd
          into lv_number_pool_items,
               lv_number_nonpool_items,
               lv_number_orpack_items,
               lv_number_assigned_items,
               lv_number_ragged_items,
               lv_number_loan_items,
               lv_number_assigned_items_deliv
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
     Retrieve_main_item_info;
    end if;

     -- bring in circ assigned items
    if gv_result = 0 and lv_number_assigned_items > 0 and (gs_ss_bringincircatinscan = 0 or lv_number_assigned_items_deliv > 0) then
      bring_in_circ_assigned_items;
      if gv_result = gc_result_duplicate_scan_err then
        --try again
        gv_result := 0;
        bring_in_circ_assigned_items;
      end if;
    end if;

    if gv_result = 0 then
    begin  -- exception block
     Retrieve_item_info;

     if gc_ss_scanbyroute='Y' and lv_number_nonpool_items > 0 then
       Rewash_update_unique_item_rte;
     end if;

     Rewash_update_unique_item;

     Create_flags_maxwash_spectreat;

     Create_rewashscans;

     Remove_Flags('RewashScan');

     if gv_prodprocessbuffer_id is not null then
       load_uniqueitem_buffer_info;
       insertupdate_uniqueitembufinfo(4);
       create_prodprocessbufscans(4);
     end if;

     Create_reject_scans(4); -- 4 = transactiontype rewashscan

     if gv_dbSetting = 'PED' then
        writemultireaddebuglog('CREATE PN FOR REWASH');
        CREATE_PACKINGNOTE_FOR_REWASH;
     end if;

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(4, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return gv_result;
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processrewashscanbatch;

  -----------------------------------------------------------------------------------------
  function f_processragscanbatch(fp_reason_id    number,
                                 fp_ragreason_id number) return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;
   lv_number_orpack_items   number := 0;
   lv_number_assigned_items number := 0;
   lv_number_ragged_items   number := 0;
   lv_number_loan_items     number := 0;

   ---------------------------------------------
   procedure retrieve_main_item_info is

   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1 pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    nvl(nvl(u.relatedcustomer_id,
                       (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = u.distributionpoint_id
                           and de1.department_id = di1.department_id)),
                        (select de2.customer_id
                           from distributionpoint di2,
                                department de2
                          where di2.distributionpoint_id = u.lastdistributionpoint_link_id
                            and de2.department_id = di2.department_id)) customer_id,
                    u.distributionpoint_id distributionpoint_id,
                    u.lastdistributionpoint_link_id last_distributionpoint_id,
                    nvl((select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = u.distributionpoint_id),
                      (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = u.lastdistributionpoint_link_id)) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                    = MERGE_SUBQUERY.primaryid,
               m.customer_id               = MERGE_SUBQUERY.customer_id,
               m.distributionpoint_id      = MERGE_SUBQUERY.distributionpoint_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.last_distributionpoint_id,
               m.deliverypoint_id          = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned             = MERGE_SUBQUERY.customerowned,
               m.lastissuedate             = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id           = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize         = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 pool items
   end; -- retrieve_main_item_info

   ---------------------------------------------
   procedure retrieve_item_info is
   begin
    -- find plpc needed for residual value scheme
    begin
    writemultireaddebuglog('Retrieve item info step 2a plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.customer_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id,
               m.scan_id = seq_scan.nextval;
    exception
      when no_data_found then
         null;
    end;

    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.secondaryid    = MERGE_SUBQUERY.secondaryid;
    exception
      when no_data_found then
        null;
    end;
   end; -- retrieve_item_info


   ---------------------------------------------
   procedure rag_update_unique_item_loss is
   begin
    begin
      writemultireaddebuglog('Update unique item loss');
      merge into uniqueitemloss u
      using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
               from multireadscanbatchcontents m, uniqueitemloss ul
              where m.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and ul.uniqueitem_link_id = m.uniqueitem_id
                and ul.lossstatus <= 1 -- loss charged
                and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
                and m.multireadexception_id is null) mergequery
      on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
      when matched then
        update set u.returneddate = trunc(sysdate),
                   u.timestamp = sysdate,
                   u.systemuser_id = gv_systemuser_id;
    exception
      when no_data_found then
        null;
    end;
   end; -- rewash_update_unique_item_loss


   ---------------------------------------------
   procedure create_unique_item_rag is
   begin
    begin
    writemultireaddebuglog('Create uniqueitemrag');
    insert into raggeditem
             (raggeditem_id,
              primaryid,
              secondaryid,
              ragtimestamp,
              ragreason_id,
              garmsequencenumber,
              prevstatus_id,
              prevstay_id,
              weareremployment_link_id,
              distributionpoint_link_id,
              product_link_id,
              sizedefinition_link_id,
              purchasedate,
              lastonstockdate,
              firstissuedate,
              lastissuedate,
              numberofissues,
              enddatefullrent,
              qualitygrade_id,
              washestotal,
              repairstotal,
              rewashtotal,
              daysincirculation,
              daysinstock,
              supplier_id,
              purchaseprice,
              customerowned,
              relatedcustomerlink_id,
              lastweareremployment_link_id,
              reasoncode_id,
              residualvalue,
              lastdistributionpoint_link_id,
              systemuser_id,
              businessunit_id,
              timestamp,
              poolitem,
              losschargeinvoiceline_id,
              wearerinventorycredit_id,
              replacementworkorder_id,
              modification_1_id,
              modification_2_id,
              modification_3_id,
              purchaseorderline_id,
              supplierdelnotenumber,
              finishingmethod_id)
    select mbc.uniqueitem_id,
           mbc.idcode,
           mbc.secondaryid,
           mbc.scantimestamp,
           fp_ragreason_id,
           0,              -- garmsequencenumber
           u.status_id,    -- prevstatus_id
           u.stay_id,      -- prevstay_id
           null,           -- weareremployment_link_id
           mbc.distributionpoint_id,
           u.product_id,             --  product_link_id
           u.sizedefinition_id,      --  sizedefinition_link_id
           uif.purchasedate,
           uif.lastonstockdate,
           uif.firstissuedate,
           uif.lastissuedate,
           uif.numberofissues,
           uif.enddatefullrent,
           uif.qualitygrade_id,
           u.washestotal,
           u.repairstotal,
           u.rewashtotal,
           uif.daysincircprevissue + (trunc(sysdate) - nvl(uif.lastissuedate,trunc(sysdate))), --  daysincirculation
           uif.daysinstockprevious,
           uif.supplier_id,
           uif.purchaseprice,
           mbc.customerowned,        -- customerowned
           mbc.relatedcustomer_id,   -- relatedcustomerlink_id
           null,                     -- lastweareremployment_link_id
           fp_reason_id,             -- reasoncode_id
           0,                        -- residualvalue
           mbc.prev_distributionpoint_id, -- lastdistributionpoint_link_id
           mb.systemuser_id,
           mb.businessunit_id,
           sysdate,
           1,    --    1=pool item
           uif.losschargeinvoiceline_id, --    losschargeinvoiceline_id
           uif.wearerinventorycredit_id, --    wearerinventorycredit_id
           null, --    replacementworkorder_id
           null, --    modification_1_id
           null, --    modification_2_id
           null, --    modification_3_id
           uif.purchaseorderline_id,
           uif.supplierdelnotenumber,
           u.finishingmethod_id
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           uniqueitem                 u,
           uniqueitemfixedinfo        uif
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and u.uniqueitem_id = mbc.uniqueitem_id
       and uif.uniqueitem_id = mbc.uniqueitem_id
       and mbc.multireadexception_id is null;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_unique_item_rag

   ---------------------------------------------
   procedure create_out_of_circ_history is

   begin
    begin
    writemultireaddebuglog('Create Out of Circ History Part 1');
    insert into outofcirculationhistory
            (outofcirculationhistory_id,
            processbusinessunit_id,
            forbusinessunit_id,
            uniqueitem_link_id,
            outofcircdate,
            incircdate,
            reasoncode_id,
            quantity,
            outofcircyear,
            outofcircweek,
            outofcircday,
            weeksinuseprevissue,
            weeksinusethisissue,
            normlifetime,
            enddatefullrent,
            theoreticalpercentage,
            enteredpercentage,
            tobechargedpercentage,
            ragreason_id,
            customer_link_id,
            status,
            weareremployment_link_id,
            distributionpoint_link_id,
            product_link_id,
            workstationcode,
            customerowned,
            customerrelated,
            qualitygrade_id,
            residualvalue,
            currency_id,
            systemuser_id,
            timestamp,
            invoicebusinessunit_id,
            primaryid,
            sizedefinition_link_id,
            invoiceheader_id,
            amount,
            stockroom_id,
            chargetype,
            rowcode,
            locationcode,
            packingnote_id)
    select seq_outofcirculationhistory.nextval,
           x.processbusinessunit_id,
           x.forbusinessunit_id,
           x.uniqueitem_id,   -- uniqueitem_link_id
           x.outofcircdate,
           x.firstissuedate, -- incircdate
           fp_reason_id,
           1, -- quantity
           x.year,   -- outofcircyear
           x.week,   -- outofcircweek
           x.day,    -- outofcircday
           x.weeksinuseprevissue,
           x.weeksinusethisissue,
           x.calculationweeks, -- normlifetime
           x.enddatefullrent,
           x.percentage, -- theoreticalpercentage
           x.percentage, -- enteredpercentage
           x.percentage, -- tobechargedpercentage
           fp_ragreason_id,
           x.customer_id,
           x.status,
           null, -- weareremployment_link_id
           x.distributionpoint_id,
           x.product_id,
           x.workstationcode,
           x.customerowned,
           x.customerrelated,
           null, -- qualitygrade_id
           round(x.percentage / 100 * x.replacement_price,x.pricedecimals), -- residualvalue
           x.currency_id,
           x.systemuser_id,
           sysdate, -- timestamp
           x.invoicebusinessunit_id,
           x.primaryid,
           x.sizedefinition_id,
           null, -- invoiceheader_id
           round(x.percentage / 100 * x.replacement_price,x.amountdecimals), -- amount
           null, -- stockroom_id
           1,    -- chargetype
           null, -- rowcode
           null, -- locationcode
           -1 -- packingnote_id
      from (select
             mb.businessunit_id processbusinessunit_id,
             u.businessunit_id forbusinessunit_id,
             mbc.uniqueitem_id,
             mbc.scantimestamp outofcircdate,
             uif.firstissuedate, -- incircdate,
             getyearofweek(trunc(mbc.scantimestamp)) year,      -- outofcircyear
             getisoweek(trunc(mbc.scantimestamp)) week,         -- outofcircweek
             getabsdaynumber(trunc(mbc.scantimestamp)) day,    -- outofcircday
             ceil(uif.daysincircprevissue/7) weeksinuseprevissue,
             ceil((trunc(sysdate) - nvl(uif.lastissuedate,trunc(sysdate)))/7) weeksinusethisissue,
             rv.calculationweeks, -- normlifetime
             uif.enddatefullrent,
             case when rv.calculationbasis=1 -- 1=weeks in use, 2=washes
               then nvl(get_depreciation_percent(rv.residualvaluescheme_id,ceil((uif.daysincircprevissue + (trunc(sysdate) -  nvl(uif.lastissuedate,trunc(sysdate)) ))/7)),0)
               else nvl(get_depreciation_percent(rv.residualvaluescheme_id,u.washestotal),0)
             end percentage,
             fp_ragreason_id,
             mbc.customer_id,
             case when u.leaseweeks is not null
             then 5 -- Residual value charge for lease
             else case when (r.chargeresidualvalue='N' and rr.chargeresidualvalue = 'N') OR
                             u.customerowned='Y'
                  then 1 -- free of charge
                  else 0 -- charge
                  end
             end status,
             nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id) distributionpoint_id,
             u.product_id,
             w.code workstationcode,
             mbc.customerowned,
             case when mbc.relatedcustomer_id is not null
              then 'Y'
              else 'N'
             end customerrelated,
             pack_price.Replacement_Price(mbc.customer_id, mbc.product_id, mbc.sizedefinition_id, mbc.finishingmethod_id) replacement_price,
             uif.currency_id,
             mb.systemuser_id,
             nvl((select ca.invoicebusinessunit_id
                    from product                    p,
                         productgroup               pg,
                         customeractivities         ca
                   where ca.customer_id = mbc.customer_id
                     and ca.processbusinessunit_id = mb.businessunit_id
                     and ca.activity_id = pg.activity_id
                     and p.product_id = mbc.product_id
                     and pg.productgroup_id = p.productgroup_id),
                 (select c.defaultinvoicebusinessunit_id
                    from customer c
                   where c.customer_id = mbc.customer_id)) invoicebusinessunit_id,
             u.primaryid,
             u.sizedefinition_id,
             c.decimals pricedecimals,
             c.invoiceamountdecimals amountdecimals
        from multireadscanbatch         mb,
             multireadscanbatchcontents mbc,
             workstation                w,
             uniqueitem                 u,
             uniqueitemfixedinfo        uif,
             productlistpercustomer     plpc,
             residualvaluescheme        rv,
             currency                   c,
             reasoncode                 r,
             ragreason                  rr
       where mb.multireadscanbatch_id = gv_multireadscanbatch_id
         and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
         and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
         and u.uniqueitem_id = mbc.uniqueitem_id
         and uif.uniqueitem_id = mbc.uniqueitem_id
         and mbc.multireadexception_id is null
         and u.status_id = gc_status_id_in_circ  -- exclude assigned
         and plpc.productlistpercustomer_id = mbc.plpc_id -- part 1
         and nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id) is not null
         and rv.residualvaluescheme_id = plpc.residualvaluescheme_id
         and w.workstation_id = mb.workstation_id
         and c.currency_id = uif.currency_id
         and r.reasoncode_id = fp_reason_id
         and rr.ragreason_id = fp_ragreason_id
         ) x;
     exception
        when no_data_found then
          null;
     end;

    -- part 2 is where plpc_id is null
    begin
    writemultireaddebuglog('Create Out of Circ History Part 2');
    insert into outofcirculationhistory
            (outofcirculationhistory_id,
            processbusinessunit_id,
            forbusinessunit_id,
            uniqueitem_link_id,
            outofcircdate,
            incircdate,
            reasoncode_id,
            quantity,
            outofcircyear,
            outofcircweek,
            outofcircday,
            weeksinuseprevissue,
            weeksinusethisissue,
            normlifetime,
            enddatefullrent,
            theoreticalpercentage,
            enteredpercentage,
            tobechargedpercentage,
            ragreason_id,
            customer_link_id,
            status,
            weareremployment_link_id,
            distributionpoint_link_id,
            product_link_id,
            workstationcode,
            customerowned,
            customerrelated,
            qualitygrade_id,
            residualvalue,
            currency_id,
            systemuser_id,
            timestamp,
            invoicebusinessunit_id,
            primaryid,
            sizedefinition_link_id,
            invoiceheader_id,
            amount,
            stockroom_id,
            chargetype,
            rowcode,
            locationcode,
            packingnote_id)
    select seq_outofcirculationhistory.nextval,
           mb.businessunit_id, -- processbusinessunit_id,
           u.businessunit_id, -- forbusinessunit_id,
           mbc.uniqueitem_id,  -- uniqueitem_link_id,
           trunc(mbc.scantimestamp), -- outofcircdate,
           uif.firstissuedate, -- incircdate,
           fp_reason_id,
           1, -- quantity
           getyearofweek(trunc(mbc.scantimestamp)),      -- outofcircyear
           getisoweek(trunc(mbc.scantimestamp)),         -- outofcircweek
           getabsdaynumber(trunc(mbc.scantimestamp)),    -- outofcircday
           floor(uif.daysincircprevissue/7),              -- weeksinuseprevissue
           floor((trunc(sysdate) - nvl(uif.lastissuedate,trunc(sysdate)))/7), -- weeksinusethisissue
           0, -- normlifetime
           uif.enddatefullrent,
           0, -- theoreticalpercentage
           0, -- enteredpercentage
           0, -- tobechargedpercentage
           fp_ragreason_id,
           mbc.customer_id,
           4, -- status No residual value charge
           null, -- weareremployment_link_id
           nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id),
           u.product_id,
           w.code, -- workstationcode
           mbc.customerowned,
           case when mbc.relatedcustomer_id is not null
            then 'Y'
            else 'N'
           end,  -- customerrelated
           null, -- qualitygrade_id
           0,    -- residualvalue
           uif.currency_id,
           mb.systemuser_id,
           sysdate, -- timestamp
           mb.businessunit_id, -- invoicebusinessunit_id
           u.primaryid primaryid,
           u.sizedefinition_id,
           null, -- invoiceheader_id
           0,    -- amount
           null, -- stockroom_id
           1,    -- chargetype
           null, -- rowcode
           null, -- locationcode
           -1    -- packingnote_id
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w,
           uniqueitem                 u,
           uniqueitemfixedinfo        uif
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and u.uniqueitem_id = mbc.uniqueitem_id
       and uif.uniqueitem_id = mbc.uniqueitem_id
       and mbc.multireadexception_id is null
       and u.status_id = gc_status_id_in_circ  -- exclude assigned
       and mbc.plpc_id is null                 -- part 2
       and nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id) is not null
       and mbc.customer_id is not null
       and w.workstation_id = mb.workstation_id;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_out_of_circ_history

   ---------------------------------------------
   procedure create_ragscans is
   begin
    -- populate scan_ID in case it was not yet populated by retrieve item info
    begin
    writemultireaddebuglog('Create ragscans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create ragscans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan)
    select mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id),
           mbc.product_id,
           mbc.sizedefinition_id,
           mbc.stay_id,
           mbc.status_id,
           w.code, -- workstation code
           null, -- issue date
           null,  -- route
           fp_reason_id, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.plannedoutstop_id, -- prev stay field misused
           42, -- transaction type rag scan from in circ
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end; -- create_ragscans


   ---------------------------------------------
   procedure update_uniqueitem_link is
   begin
    -- populate scan_ID in case it was not yet populated by retrieve item info
    begin
     writemultireaddebuglog('Update Unique Item link');

     MERGE INTO uniqueitem_link ul
          USING (SELECT mbc.uniqueitem_id
                   FROM multireadscanbatchcontents mbc, multireadscanbatch mb
                  WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                    and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
                    and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                    and mbc.multireadexception_id is null
                    and mbc.uniqueitem_id is not null
                ) MERGE_SUBQUERY
          ON (ul.uniqueitem_link_id = merge_subquery.uniqueitem_id)
          WHEN MATCHED THEN
            UPDATE
               SET ul.raggeditem_id = ul.uniqueitem_id,
                   ul.uniqueitem_id = null,
                   ul.timestamp = sysdate,
                   ul.systemuser_id = gv_systemuser_id;
     exception
        when no_data_found then
          null;
     end;
   end; -- update_uniqueitem_link

   ---------------------------------------------
   procedure delete_unique_items is
   begin
    -- populate scan_ID in case it was not yet populated by retrieve item info
    begin
     writemultireaddebuglog('Delete Unique Items');

     DELETE
       FROM uniqueitem u
      WHERE u.uniqueitem_id in
           (SELECT mbc.uniqueitem_id
               FROM multireadscanbatchcontents mbc, multireadscanbatch mb
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
                and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and mbc.multireadexception_id is null
                and mbc.uniqueitem_id is not null);
     exception
        when no_data_found then
          null;
     end;
   end; -- delete_unique_items


   ----------------------------------------------------------------
   -- Begin f_processmultireadragcanbatch
   begin
      begin
        gv_main_code_block := 'Process Ragcan Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items,
               sum(case when m.orpackitemyn='Y' then 1 else 0 end) number_orpack_items,
               sum(case when s.code='30' then 1 else 0 end) number_assigned_items,
               sum(case when s.code='40' then 1 else 0 end) number_ragged_items,
               sum(case when m.unrelatedloan_id is not null then 1 else 0 end) number_loan_items
          into lv_number_pool_items,
               lv_number_nonpool_items,
               lv_number_orpack_items,
               lv_number_assigned_items,
               lv_number_ragged_items,
               lv_number_loan_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
     Retrieve_main_item_info;
    end if;

   if gv_result = 0 then
    begin  -- exception block
     retrieve_item_info;

     rag_update_unique_item_loss;

     create_unique_item_rag;

     create_out_of_circ_history; -- for items in circ, not for assigned ones

     create_ragscans;

     gv_prodprocessbuffer_id := null; -- to make sure items will not go to another buffer
     load_uniqueitem_buffer_info;
     insertupdate_uniqueitembufinfo(42);
     create_prodprocessbufscans(42);
     delete_uniqueitem_buffer_info; -- afterwards delete bufferinfo

     update_uniqueitem_link;

     delete_unique_items;

     Create_reject_scans(42); -- 42 = transactiontype rag while in circ

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(42, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processragscanbatch;

  -----------------------------------------------------------------------------------------
  function f_processonsiteinventbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;
   lv_transactiontype       number := 0;
   ---------------------------------------------
   procedure retrieve_item_info is

   begin
    if not gv_garmentassistantbatch then
    -- find plpd on in case of linen assistant, needed to update onsite inventory
    begin
      writemultireaddebuglog('Retrieve item info step 1 plpd');
      MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.multireadscanbatch_id,
                      m1.subbatchnumber,
                      m1.uniqueitem_id,
                      plpd.productlistperdistribpoint_id
                 FROM multireadscanbatchcontents m1, productlistperdistribpoint plpd
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                  and m1.uniqueitem_id is not null
                  and m1.distributionpoint_id is not null
                  and m1.multireadexception_id is null
                  and plpd.distributionpoint_id = m1.distributionpoint_id
                  and plpd.product_id = m1.product_id
                  and plpd.sizedefinition_id = m1.sizedefinition_id
                  and plpd.finishingmethod_id = m1.finishingmethod_id
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
        AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.productlistperdistribpoint_id = MERGE_SUBQUERY.productlistperdistribpoint_id;
      exception
        when no_data_found then
           null;
      end;
    end if; -- if not gv_garmentassistantbatch

    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 2 PrimID and secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid,
                    u.primaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su, uniqueitem u
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode         = MERGE_SUBQUERY.primaryid,
               m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;
    commit;

   end; -- retrieve_item_info

   ---------------------------------------------
   procedure onsiteinv_update_unique_item is
   begin
     begin
      if gv_garmentassistantbatch
      then -- do not update distribution point and last distributionpoint
        writemultireaddebuglog('Update_unique item Garment Assistant');
        MERGE INTO uniqueitem u
        USING (SELECT m1.uniqueitem_id,
                      m1.scantimestamp,
                      m1.stay_id,
                      case when u1.stay_id <> gc_stay_id_onsite_inv
                       then m1.scantimestamp
                       else u1.staychangedate
                      end staychangedate
                 FROM multireadscanbatchcontents m1, uniqueitem u1
                WHERE m1.uniqueitem_id = u1.uniqueitem_id
                  and m1.multireadexception_id is null
                  and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              ) MERGE_SUBQUERY
        ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                  u.staychangedate = MERGE_SUBQUERY.staychangedate,
                  u.prevstay_id = MERGE_SUBQUERY.stay_id,
                  u.stay_id = gc_stay_id_onsite_inv,
                  u.systemuser_id = gv_systemuser_id,
                  u.timestamp = sysdate;
      else -- gv_garmentassistantbatch is false, so for linen assistant:
           -- DO update distribution point and last distributionpoint
        writemultireaddebuglog('Update_unique item Linen Assistant');
        MERGE INTO uniqueitem u
        USING (SELECT m1.uniqueitem_id,
                      m1.scantimestamp,
                      m1.stay_id,
                      case when u1.stay_id <> gc_stay_id_onsite_inv
                       then m1.scantimestamp
                       else u1.staychangedate
                      end staychangedate,
                      u1.distributionpoint_id lastdistributionpoint_id,
                      m1.distributionpoint_id,
                      m1.poolitemyn
                 FROM multireadscanbatchcontents m1, uniqueitem u1
                WHERE m1.uniqueitem_id = u1.uniqueitem_id
                  and m1.multireadexception_id is null
                  and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              ) MERGE_SUBQUERY
        ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                  u.staychangedate = MERGE_SUBQUERY.staychangedate,
                  u.prevstay_id = MERGE_SUBQUERY.stay_id,
                  u.stay_id = gc_stay_id_onsite_inv,
                  u.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id, -- link to the new distribution point
                  u.lastdistributionpoint_link_id = MERGE_SUBQUERY.lastdistributionpoint_id,
                  u.systemuser_id = gv_systemuser_id,
                  u.timestamp = sysdate;
    end if; -- if gv_garmentassistantbatch
    --
    -- Update return date when loss charge billing is made based on last scan date
    writemultireaddebuglog('Update unique item loss');
    merge into uniqueitemloss u
    using (select /*+index (ul XIE1UNIQUEITEMLOSS) */ ul.uniqueitemloss_id
             from multireadscanbatchcontents m, uniqueitemloss ul
            where m.multireadscanbatch_id = gv_multireadscanbatch_id
              and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              and ul.uniqueitem_link_id = m.uniqueitem_id
              and ul.lossstatus <= 1 -- loss charged
              and ul.returneddate = to_date('31-12-2099', 'dd-mm-yyyy')
              and ul.losschargetrigger = 1 -- only when loss charge was created triggerd by last scan date
              and m.multireadexception_id is null) mergequery
    on (u.uniqueitemloss_id = mergequery.uniqueitemloss_id)
    when matched then
      update set u.returneddate = trunc(sysdate),
                 u.timestamp = sysdate,
                 u.systemuser_id = gv_systemuser_id;
    exception
      when no_data_found then
        null;
    end;
   end; -- onsiteinv_update_unique_item

   ---------------------------------------------
   procedure create_onsiteinvscans(fp_transactiontype in number) is
   begin
    begin
    writemultireaddebuglog('Create on-site inventory scans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan)
    select seq_scan.nextval,
           mbc.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_onsite_inv,
           gc_status_id_in_circ,
           w.code,
           mbc.lastissuedate,
           null, -- route
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           fp_transactiontype, -- transaction type on-site inventory scan 76 or stockcount scan 74
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

   end; -- create_onsiteinvscans

   ---------------------------------------------
   procedure create_onsiteinvadjustments is
   begin
    begin
    writemultireaddebuglog('Create on-site inventory adjustments');

    MERGE INTO onsiteinventoryadjustment oid
    USING  (select x.productlistperdistribpoint_id,
                   7 origin, -- origin 7 is on-site inventory check
                   x.inventorydate,
                   x.quantity - nvl((select sum(q.quantity)
                                       from onsiteinventoryadjustment q
                                      where q.productlistperdistribpoint_id = x.productlistperdistribpoint_id),0) quantity,
                   null reference
              from (select mbc.productlistperdistribpoint_id,
                           max(trunc(mbc.scantimestamp)) inventorydate, -- max date per department
                           -- mb.timestamp is not used to be more accurate in case tranfer was done at a later date.
                           count(*) quantity
                      from multireadscanbatch         mb,
                           multireadscanbatchcontents mbc,
                           productlistpercustomer     plpc
                     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
                       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
                       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                       and mbc.multireadexception_id is null
                       and plpc.productlistpercustomer_id = mbc.plpc_id
                       and plpc.onsiteinventorycount = 'Y'  -- only when onsite inv check is Y
                       and mbc.productlistperdistribpoint_id is not null
                  group by mbc.productlistperdistribpoint_id) x
            ) MERGE_SUBQUERY
      ON (oid.productlistperdistribpoint_id = MERGE_SUBQUERY.productlistperdistribpoint_id and
          oid.inventorydate = MERGE_SUBQUERY.inventorydate and
          oid.origin = MERGE_SUBQUERY.origin and
          oid.reference is null)
      WHEN MATCHED THEN
        UPDATE
           SET oid.quantity = oid.quantity + MERGE_SUBQUERY.quantity,
               oid.systemuser_id = gv_systemuser_id,
               oid.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
          (onsiteinventoryadjustment_id,
           productlistperdistribpoint_id,
           origin,
           inventorydate,
           quantity,
           reference,
           systemuser_id,
           timestamp,
           invoiceheader_id)
        VALUES
          (seq_onsiteinventoryadjustment.nextval,
           MERGE_SUBQUERY.productlistperdistribpoint_id,
           MERGE_SUBQUERY.origin,
           MERGE_SUBQUERY.inventorydate,
           MERGE_SUBQUERY.quantity,
           MERGE_SUBQUERY.reference,
           gv_systemuser_id,
           sysdate,
           null);
     exception
        when no_data_found then
          null;
     end;
   end; -- create_onsiteinvadjustments


   ----------------------------------------------------------------
   -- Begin f_processonsiteinventbatch
   begin
      if gv_istockcountbatch
        then lv_transactiontype := 74; -- is transactiontype for stockcount scan
        else lv_transactiontype := 76; -- is transactiontype for on-site inventory scan
      end if;
      begin
        gv_main_code_block := 'Process On-site Inventory Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items
          into lv_number_pool_items,
               lv_number_nonpool_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
    begin  -- exception block
     Retrieve_item_info;

     Onsiteinv_update_unique_item;

     Create_onsiteinvscans(lv_transactiontype);

     if (not gv_garmentassistantbatch) and
        ((not gv_istockcountbatch) or (gv_istockcountbatch and gv_ss_stockcntupdateonsiteinv=1)) then
       Create_onsiteinvadjustments;
     end if;

     Create_reject_scans(lv_transactiontype);

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(lv_transactiontype, 'N');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processonsiteinventbatch;

  -----------------------------------------------------------------------------------------
  function f_processonsitelockerscan return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   ---------------------------------------------
   procedure retrieve_item_info is
   begin
     begin
    -- find secondary ID, to store in scan record when available
    writemultireaddebuglog('Retrieve item info step 1 PrimID and secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid,
                    u.primaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su, uniqueitem u
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode         = MERGE_SUBQUERY.primaryid,
               m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;
    commit;
   end retrieve_item_info;

   ---------------------------------------------
   procedure onsitelock_update_unique_item is
   begin
    writemultireaddebuglog('Update_unique item Garment Assistant');
    MERGE INTO uniqueitem u
    USING (SELECT m1.uniqueitem_id,
                  m1.scantimestamp,
                  m1.stay_id,
                  case when u1.stay_id <> gc_stay_id_lockerfed
                   then m1.scantimestamp
                   else u1.staychangedate
                  end staychangedate
               FROM multireadscanbatchcontents m1, uniqueitem u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.staychangedate,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_lockerfed,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
   end onsitelock_update_unique_item;

   ---------------------------------------------
   procedure create_onsitelockerscans is
   begin
    begin
    writemultireaddebuglog('Create on-site locker scans');

    -- populate scan_ID
    begin
    writemultireaddebuglog('Retrieve item info step 2 scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null;
    exception
      when no_data_found then
        null;
    end;

    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan)
    select mbc.scan_id,
           mbc.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           mbc.weareremployment_id,
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_onsite_inv,
           gc_status_id_in_circ,
           w.code,
           mbc.lastissuedate,
           null, -- route
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           110, -- transaction type Placed Into Locker
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;
   end create_onsitelockerscans;

   procedure update_outscans is
   begin
     --update_outscans
     gv_main_code_block := 'Process On-site Lockerscan Batch update_outscans';
     update scan s
     set    s.lockerfeedscan_id =
             (select mbc.scan_id
              from   multireadscanbatch mb
              join   multireadscanbatchcontents mbc
              on     mbc.multireadscanbatch_id = mb.multireadscanbatch_id
              join   uniqueitem u
              on     u.uniqueitem_id = mbc.uniqueitem_id
              where  mb.multireadscanbatch_id = gv_multireadscanbatch_id
              and    (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
              and    s.businessunit_id = mb.businessunit_id
              and    s.primaryid = mbc.idcode
              and    s.scantimestamp = u.lastoutscandate
              and    s.treatmenttype_id is null
              and    s.transactiontype_id = 2)
     where  s.transactiontype_id = 2 --Outscan
     and    exists (select mbc.scan_id
             from   multireadscanbatch mb
             join   multireadscanbatchcontents mbc
             on     mbc.multireadscanbatch_id = mb.multireadscanbatch_id
             join   uniqueitem u
             on     u.uniqueitem_id = mbc.uniqueitem_id
             where  mb.multireadscanbatch_id = gv_multireadscanbatch_id
             and    (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
             and    s.businessunit_id = mb.businessunit_id
             and    s.primaryid = mbc.idcode
             and    s.scantimestamp = u.lastoutscandate
             and    s.treatmenttype_id is null
             and    s.transactiontype_id = 2);
   end update_outscans;

   ----------------------------------------------------------------
   -- Begin f_processonsitelockerscan
   begin
     gv_main_code_block := 'Process On-site Lockerscan Batch';
     --Retrieve_item_info
     Retrieve_item_info;
     --onsitelock_update_unique_item
     onsitelock_update_unique_item;
     --create_onsitelockerscans
     create_onsitelockerscans;
     --update_outscans
     update_outscans;
     --Create_reject_scans 110 placed into locker
     Create_reject_scans(110);
     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(110, 'N');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
   end f_processonsitelockerscan;

 -----------------------------------------------------------------------------------------
  function f_processreceivescanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;

   ---------------------------------------------
   procedure retrieve_main_item_info is

   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = m1.distributionpoint_id
                           and de1.department_id = di1.department_id) customer_id,
                    u.distributionpoint_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = m1.distributionpoint_id) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = nvl(MERGE_SUBQUERY.customer_id,m.customer_id),
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1b non-pool items
   if lv_number_nonpool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1b non-pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = m1.distributionpoint_id
                           and de1.department_id = di1.department_id) customer_id,
                    (select we.DISTRIBUTIONPOINT_ID from uniqueitemnonpool un, weareremployment we where
                    un.uniqueitem_id = u.uniqueitem_id and we.WEAREREMPLOYMENT_ID = un.WEAREREMPLOYMENT_ID)
                    distributionpoint_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = m1.distributionpoint_id) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = nvl(MERGE_SUBQUERY.customer_id,m.customer_id),
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1b non-pool items
   end; -- retrieve_main_item_info

  ----------------------------------------------------------------------------------------------
  function f_validateonsitelockerscan return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   --------------------------
   begin
      gv_main_code_block := 'Validate On-site Locker Scan';
      -- step 1A
      -- Try to find ID Codes in database by PRIMARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1A Find by Primary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT u.primaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    (select de.customer_id
                          from distributionpoint di,
                               department de
                         where di.distributionpoint_id = m1.distributionpoint_id
                           and de.department_id = di.department_id) customer_id,
                    u.distributionpoint_id prev_distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif
              WHERE m1.idcode = u.primaryid
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else case when MERGE_SUBQUERY.lastscandate = m.scantimestamp  -- ABS-39293 HVH
                                                then 3 -- scanned within time interval
                                                else null
                                               end
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_items_found := 0;
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(1); -- primary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;

      -- step 1B
      -- Try to find ID Codes in database by SECONDARY ID
      -- No BU filter is needed because chip numbers are supposed to be overall unique.
      if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
      gv_exit_loop := false;
      WHILE not gv_exit_loop LOOP
      begin
      writemultireaddebuglog('Step 1B Find by Secondary ID');
      MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT su.secondaryid idcode,
                    u.uniqueitem_id,
                    u.businessunit_id,
                    u.product_id,
                    u.sizedefinition_id,
                    u.finishingmethod_id,
                    (select de.customer_id
                          from distributionpoint di,
                               department de
                         where di.distributionpoint_id = m1.distributionpoint_id
                           and de.department_id = di.department_id) customer_id,
                    u.distributionpoint_id prev_distributionpoint_id,
                    u.poolitem,
                    u.status_id,
                    u.stay_id,
                    u.lastscandate,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    m1.scantimestamp,
                    u.lastinscandate,
                    u.lastoutscandate
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, secondaryuniqueitem su
              WHERE m1.idcode = su.secondaryid
                and u.uniqueitem_id = su.uniqueitem_id
                and uif.uniqueitem_id = u.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.subbatchnumber = gv_subbatchnumber
                and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                and m1.multireadexception_id is null
             ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
      AND m.subbatchnumber = gv_subbatchnumber
      AND m.idcode = MERGE_SUBQUERY.idcode)
      WHEN MATCHED THEN
        UPDATE
           SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
               m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
               m.product_id            = MERGE_SUBQUERY.product_id,
               m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
               m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.prev_distributionpoint_id = MERGE_SUBQUERY.prev_distributionpoint_id,
               m.stay_id               = MERGE_SUBQUERY.stay_id,
               m.status_id             = MERGE_SUBQUERY.status_id,
               m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.multireadexception_id = case when MERGE_SUBQUERY.status_id NOT in (gc_status_id_assigned,gc_status_id_in_circ)
                                          then 2 -- not in circ
                                          else case when MERGE_SUBQUERY.lastscandate = m.scantimestamp  -- ABS-39293 HVH
                                                then 3 -- scanned within time interval
                                                else null
                                               end
                                         end,
               m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
               m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
               m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
               m.lastscandate          = MERGE_SUBQUERY.lastscandate;
      gv_items_found := gv_items_found + SQL%ROWCOUNT;
      commit;
      gv_exit_loop := true;
      exception
        when no_data_found then
          gv_exit_loop := true;
        when duplicates_detected then
          mark_duplicates(2); -- secondary range
          gv_exit_loop := false;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          gv_exit_loop := true;
          return gc_result_ora_error;
        end;
      end;
      END LOOP;
      end if;

      -- step 2
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2 Mark those not found');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 1 -- not found in database
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.uniqueitem_id is null
           and m.multireadexception_id is null;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if;

      -- step 3
      if gv_garmentassistantbatch
      then
        -- 3a find customer and weareremployment for personalized garments
        writemultireaddebuglog('Step 3a Load weareremployement for personalized garments');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id,
                      w.customer_id,
                      we.distributionpoint_id,
                      unp.weareremployment_id
                 FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemnonpool unp,
                      wearer w, weareremployment we
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and unp.uniqueitem_id = m1.uniqueitem_id
                  and we.weareremployment_id = unp.weareremployment_id
                  and w.wearer_id = we.wearer_id
                  and m1.poolitemyn = 'N'
                  and m1.multireadexception_id is null
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.customer_id = MERGE_SUBQUERY.customer_id,
                 m.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id,
                 m.weareremployment_id = MERGE_SUBQUERY.weareremployment_id;

        -- 3b find customer and cons.point for pool items
        writemultireaddebuglog('Step 3a Load consumptionpoint for pool item');
        MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT m1.uniqueitem_id,
                      d.customer_id,
                      u.distributionpoint_id
                 FROM multireadscanbatchcontents m1, uniqueitem u, distributionpoint dp, department d
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and u.uniqueitem_id = m1.uniqueitem_id
                  and dp.distributionpoint_id = u.distributionpoint_id
                  and d.department_id = dp.department_id
                  and m1.poolitemyn = 'Y'
                  and m1.multireadexception_id is null
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
        WHEN MATCHED THEN
          UPDATE
             SET m.customer_id = MERGE_SUBQUERY.Customer_id,
                 m.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id;
      else -- not gv_garmentassistantbatch
        begin
          -- Mark all type of merchandize 2 garments with rejection reason if not scanned with garment assistant
          writemultireaddebuglog('Step 3 Reject personalized garments');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 6
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.multireadexception_id is null
             and m.poolitemyn = 'N';
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if gv_garmentassistantbatch

      -- step 4
      -- Mark all items that are scanned meanwhile with rejection reason
      begin
        writemultireaddebuglog('Step 4 Reject items scanned meanwhile');
        update multireadscanbatchcontents m
           set m.multireadexception_id = 15
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and m.subbatchnumber = gv_subbatchnumber
           and m.multireadexception_id is null
           and m.lastscantimestamp > m.scantimestamp;
        commit;
      exception
        when no_data_found then
         null;
        when others then
         begin
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          ROLLBACK;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

      if not gv_garmentassistantbatch
      then -- determine plpc in order to know during processing if onsiteinventorycheck is done
        begin
          writemultireaddebuglog('Step 5 Find Plpc pool items');
          update multireadscanbatchcontents m
             set m.plpc_id= (select min(p.productlistpercustomer_id)
                               from productlistpercustomer p
                              where p.customer_id = m.customer_id
                                and p.product_id = m.product_id
                                and p.sizedefinition_id = m.sizedefinition_id
                                and p.dateactive <= trunc(sysdate)
                                and p.dateinactive >= trunc(sysdate))
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.poolitemyn='Y'
             and m.multireadexception_id is null;
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
      end if; -- if not gv_garmentassistantbatch

      return 0;
   end f_validateonsitelockerscan;

   ---------------------------------------------
   procedure receivescan_update_unique_item is
   begin
     begin
      writemultireaddebuglog('Update Unique item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    m1.distributionpoint_id,
                    m1.lastoutscandate
               FROM multireadscanbatch mb, multireadscanbatchcontents m1, uniqueitem u1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                -- HVH 1/7/2015 added the following condition to prevent that uniqueitem is updated
                -- with wrong values, in case of out-of-sequence processing due to offline scanning.
                and m1.lastscantimestamp <= m1.scantimestamp
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_onsite_inv,
                u.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                u.lastoutscandate = MERGE_SUBQUERY.lastoutscandate,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- receivescan_update_unique_item


   ---------------------------------------------
   procedure Update_delnote_recieved_qty is
   begin
     begin
      writemultireaddebuglog('Update Deliverynote Received Qty');
      MERGE INTO packingnoteline pnl
      USING (SELECT pl.packingnoteline_id,
                    count(*) qty
               FROM multireadscanbatch mb, multireadscanbatchcontents m1,
                    packingnoteline pl, packingnote p
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.multireadexception_id is null
                and p.notenumber = m1.lastdeliverynotenumber
                and pl.packingnote_id = p.packingnote_id
                and pl.product_id = m1.product_id
                and pl.sizedefinition_id = m1.sizedefinition_id
                and pl.finishingmethod_id = m1.finishingmethod_id
              GROUP BY  pl.packingnoteline_id
            ) MERGE_SUBQUERY
      ON (pnl.packingnoteline_id = MERGE_SUBQUERY.packingnoteline_id)
      WHEN MATCHED THEN
        UPDATE
           SET  pnl.receivedqty = pnl.receivedqty + MERGE_SUBQUERY.qty,
                pnl.systemuser_id = gv_systemuser_id,
                pnl.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- Update_delnote_recieved_qty

   ---------------------------------------------
   procedure create_receivescans is
   begin
    begin
    writemultireaddebuglog('Create Receive Scans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Receive Scans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, batchnumber, scandateoffset, qualitytesttype_id, washingprocess_id,
             treatmenttype_id, deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
             dayssincelastscan)
    select mbc.scan_id,
           mbc.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_onsite_inv,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           null, -- route_ID
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           69, -- transaction type receive at customer scan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           null, -- batchnumber,
           0,    -- scandateoffset,
           null, -- qualitytesttype_id,
           null, -- washingprocess_id,
           null, -- treatmenttype_id,
           mbc.lastdeliverynotenumber,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null
       and mbc.uniqueitem_id is not null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end; -- create_receivescans

   ----------------------------------------------------------------
   -- Begin f_processmultireadreceivescanbatch
   begin
      begin
        gv_main_code_block := 'Process Receive Scan Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items
          into lv_number_pool_items,
               lv_number_nonpool_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
     Retrieve_main_item_info;
    end if;

    if gv_result = 0 then
    begin  -- exception block

     Receivescan_update_unique_item;

     if gc_ss_shipmentcheckperdelnote=1 then -- if configured shipmentcheckondelnote then
       Update_delnote_recieved_qty;
     end if;

     Create_receivescans;

     Create_reject_scans(69); -- 69 = receive at customer scan

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(69, 'N');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processreceivescanbatch;



 -----------------------------------------------------------------------------------------
  function f_processsendscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;

   ---------------------------------------------
   procedure retrieve_main_item_info is

   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = m1.distributionpoint_id
                           and de1.department_id = di1.department_id) customer_id,
                    u.distributionpoint_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = m1.distributionpoint_id) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = nvl(MERGE_SUBQUERY.customer_id,m.customer_id),
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 pool items
   if lv_number_nonpool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = m1.distributionpoint_id
                           and de1.department_id = di1.department_id) customer_id,
                    (select we.DISTRIBUTIONPOINT_ID from uniqueitemnonpool un, weareremployment we where
                    un.uniqueitem_id = u.uniqueitem_id and we.WEAREREMPLOYMENT_ID = un.WEAREREMPLOYMENT_ID)
                    distributionpoint_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = m1.distributionpoint_id) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = nvl(MERGE_SUBQUERY.customer_id,m.customer_id),
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1b non-pool items
   end; -- retrieve_main_item_info

   ---------------------------------------------
   procedure create_delivery_variations is
   begin
    begin
    gv_code_block := 'Create delivery variations pool';
    writemultireaddebuglog(gv_code_block);
    MERGE /*+index(d XAK2DELIVERYVARIATIONS)*/ INTO deliveryvariations d
      USING (SELECT nvl(p.distributionpoint_id, m1.distributionpoint_id) distributionpoint_id,
                    m1.product_id,
                    m1.sizedefinition_id,
                    m1.finishingmethod_id,
                    m1.plannedoutdate deliverydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1
               JOIN uniqueitem u on u.uniqueitem_id = m1.uniqueitem_id
               LEFT OUTER JOIN packingnote p on p.notenumber = u.lastdeliverynotenumber
            WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.delayedevenexchange > 0  -- only those with delayed even exchange
                and nvl(p.distributionpoint_id, m1.distributionpoint_id) is not null
                and m1.plpc_id is not null
                and m1.uniqueitem_id is not null
                and m1.plannedoutdate is not null -- delivery date found
                and m1.multireadexception_id is null
                -- HVH 2/7/2015 added the following condition to prevent that del.vars are created
                -- in case of out-of-sequence processing due to offline scanning.
                and m1.lastscantimestamp <= m1.scantimestamp
              GROUP BY nvl(p.distributionpoint_id, m1.distributionpoint_id),
                       m1.product_id,
                       m1.sizedefinition_id,
                       m1.finishingmethod_id,
                       m1.plannedoutdate
            ) MERGE_SUBQUERY
      ON (d.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id
      AND d.product_id = MERGE_SUBQUERY.product_id
      AND d.sizedefinition_id = MERGE_SUBQUERY.sizedefinition_id
      AND d.finishingmethod_id = MERGE_SUBQUERY.finishingmethod_id
      AND d.deliverydate = MERGE_SUBQUERY.deliverydate
      AND d.packingnote_id is null
      AND d.processed = 'N'
      AND d.causenote_id is null
      AND d.updaterentqty = 'N'
      AND d.origin = 1
      AND d.soilcountsubtype = 7
      AND d.weborderline_id is null
      AND d.reference is null
      AND d.adjustmentreason_id is null
      AND d.reasoncode_id is null
      )
      WHEN MATCHED THEN
        UPDATE
           SET d.amount = d.amount + MERGE_SUBQUERY.qty,
               d.systemuser_id = gv_systemuser_id,
               d.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
           (deliveryvariations_id,
            product_id,
            packingnote_id,
            causenote_id,
            deliverydate,
            origin,
            amount,
            finishingmethod_id,
            fixedamount,
            distributionpoint_id,
            sizedefinition_id,
            reference,
            systemuser_id,
            processed,
            timestamp,
            updaterentqty,
            soilcountsubtype,
            processbusinessunit_id,
            internalprocessingbu_id)
        VALUES
          (seq_deliveryvariations.nextval,
           MERGE_SUBQUERY.product_id,
           null, -- packingnote
           null, -- cause note
           MERGE_SUBQUERY.deliverydate,
           1,    -- origin
           MERGE_SUBQUERY.qty,
           MERGE_SUBQUERY.finishingmethod_id,
           'N',  -- fixedamount
           MERGE_SUBQUERY.distributionpoint_id,
           MERGE_SUBQUERY.sizedefinition_id,
           null, -- reference
           gv_systemuser_id,
           'N',  -- processed
           sysdate,
           'N',  -- update rent qty
           7,     -- soil count subtype inscan
           f_getprocessbusinessunit(MERGE_SUBQUERY.distributionpoint_id, MERGE_SUBQUERY.product_id),
           gv_businessunit_id);

    exception
      when no_data_found then
        null;
    end;
   end; -- create_delivery_variations

   ---------------------------------------------
   procedure sendscan_update_unique_item is
   begin
     begin
      writemultireaddebuglog('Update Unique item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    m1.distributionpoint_id,
                    m1.lastoutscandate
               FROM multireadscanbatch mb, multireadscanbatchcontents m1, uniqueitem u1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                -- HVH 1/7/2015 added the following condition to prevent that uniqueitem is updated
                -- with wrong values, in case of out-of-sequence processing due to offline scanning.
                and m1.lastscantimestamp <= m1.scantimestamp
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_sent_to_laundry,
                u.distributionpoint_id = MERGE_SUBQUERY.distributionpoint_id,
                u.lastoutscandate = MERGE_SUBQUERY.lastoutscandate,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- sendscan_update_unique_item

   ---------------------------------------------
   procedure create_sendscans is
   begin
    begin

    writemultireaddebuglog('Create Send Scans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Send Scans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, batchnumber, scandateoffset, qualitytesttype_id, washingprocess_id,
             treatmenttype_id, deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
             dayssincelastscan)
    select mbc.scan_id,
           mbc.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_sent_to_laundry,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           null, -- route_ID
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           68, -- transaction type send to laundry scan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           null, -- batchnumber,
           0,    -- scandateoffset,
           null, -- qualitytesttype_id,
           null, -- washingprocess_id,
           null, -- treatmenttype_id,
           mbc.lastdeliverynotenumber,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null
       and mbc.uniqueitem_id is not null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end; -- create_sendcans

   ----------------------------------------------------------------
   -- Begin f_processmultireadreceivescanbatch
   begin
      begin
        gv_main_code_block := 'Process Send Scan Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items
          into lv_number_pool_items,
               lv_number_nonpool_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
     Retrieve_main_item_info;
    end if;

    if gv_result = 0 then
    begin  -- exception block

     retrieve_item_info_for_delvar;

     if lv_number_pool_items > 0 then
       create_delivery_variations;
     end if;

     Sendscan_update_unique_item;

     Create_sendscans;

     Create_reject_scans(68); -- 68 = send to laundry scan

     delete_uhfbundle(gv_subbatchnumber);

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(68, 'N');
          gv_result := gc_result_duplicate_scan_err;
          return gv_result;
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processsendscanbatch;

  -----------------------------------------------------------------------------------------
  function f_processscanbatchKNT(fp_transactiontype in number) return number is
  -- this function is used by both receive from laundry and send to laundry.
   lv_stay_id number;
   lv_scantransactiontype number;
   ---------------------------------------------
   procedure scan_update_container is

   begin
     begin
      writemultireaddebuglog('Update Container');
      MERGE INTO container c
      USING (SELECT m1.container_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    c1.staychangedate
               FROM multireadscanbatch mb, multireadscanbatchcontknt m1, container c1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.container_id = c1.container_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (c.container_id = MERGE_SUBQUERY.container_id)
      WHEN MATCHED THEN
        UPDATE
           SET  c.prevstay_id = MERGE_SUBQUERY.stay_id,
                c.stay_id = lv_stay_id,
                c.staychangedate = case when MERGE_SUBQUERY.stay_id <> lv_stay_id
                                      then MERGE_SUBQUERY.scantimestamp
                                      else MERGE_SUBQUERY.staychangedate -- leave unchanged
                                   end,
                c.systemuser_id = gv_systemuser_id,
                c.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- scan_update_container

   ---------------------------------------------
   procedure create_container_scans is

   begin
    -- populate scan_ID
    begin
    writemultireaddebuglog('Create Container scans - populate scanID');

    UPDATE multireadscanbatchcontknt m
       set m.containerscan_id = seq_containerscan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.container_id is not null
       and m.containerscan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Container scans');
    insert into containerscan
            (containerscan_id,
             scantimestamp,
             businessunit_id,
             primaryid,
             secondaryid,
             distributionpoint_link_id,
             containertype_id,
             stay_id,
             prevstay_id,
             transactiontype_id,
             scanstation,
             customerowned,
             year,
             week,
             dayno,
             container_id,
             tareweight,
             systemuser_id,
             timestamp)
    select mbc.containerscan_id,
           mbc.scantimestamp,
           mb.businessunit_id,
           mbc.idcode,
           mbc.secondaryid,
           mbc.distributionpoint_id,
           mbc.containertype_id,
           lv_stay_id,
           mbc.stay_id,
           lv_scantransactiontype,
           w.code,
           case when mbc.ownercustomer_id is not null
            then 'Y'
            else 'N'
           end,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.container_id,
           mbc.tareweight,
           mbc.systemuser_id,
           sysdate
      from multireadscanbatch            mb,
           multireadscanbatchcontknt     mbc,
           workstation                   w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.containerscan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when no_data_found then
          null;
     end;
   end; -- create_container_scans

   ----------------------------------------------------------------
   -- Begin f_processmultireadscanbatch
   begin
    begin
     case fp_transactiontype
      when gc_transtype_receive then
         gv_main_code_block := 'Process Receive Scan Batch Containers';
         lv_stay_id := gc_stay_id_knt_receive;
         lv_scantransactiontype := 548; -- receive from laundry
      when gc_transtype_send then
         gv_main_code_block := 'Process Send Scan Batch Containers';
         lv_stay_id := gc_stay_id_knt_send;
         lv_scantransactiontype := 549; -- send to laundry
      else
         gv_main_code_block := 'Process Scan Batch Containers';
     end case;

     Scan_update_container;

     Create_container_scans;

     Create_reject_scans_knt(lv_scantransactiontype);

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processscanbatchKNT;

 -----------------------------------------------------------------------------------------
  function f_processlaundrybufscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message

   -- Begin f_processlaundrybufscanbatch
   begin
    gv_main_code_block := 'Process Laundry Buffer Scan Batch';
    begin  -- exception block
     load_uniqueitem_buffer_info;

     insertupdate_uniqueitembufinfo(19);

     create_prodprocessbufscans(19);

     Create_reject_scans(19); -- 19 = laundry process buffer scan

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
   end f_processlaundrybufscanbatch;

-----------------------------------------------------------------------------------------
  function f_processsoilingdscanbatch return number is
    -- output result:
    -- 0 = okay
    -- 3 = ORA message
   lv_number_pool_items     number := 0;
   lv_number_nonpool_items  number := 0;

   ---------------------------------------------
   procedure retrieve_main_item_info is

   begin
   if lv_number_pool_items > 0 then
    begin
    writemultireaddebuglog('Retrieve main item info step 1a pool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    (select de1.customer_id
                          from distributionpoint di1,
                               department de1
                         where di1.distributionpoint_id = m1.distributionpoint_id
                           and de1.department_id = di1.department_id) customer_id,
--                    u.distributionpoint_id,
                    (select dp.deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = m1.distributionpoint_id) deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u, uniqueitemfixedinfo uif, product p
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'Y'
                and m1.uniqueitem_id is not null
                -- and m1.multireadexception_id is null    --removed so that for rejected scans distrib is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = nvl(MERGE_SUBQUERY.customer_id,m.customer_id),
--             m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end if; -- step 1 pool items
   end; -- retrieve_main_item_info

   ---------------------------------------------
   procedure soil_in_gd_upd_unique_item is
   begin
     begin
      writemultireaddebuglog('Update Unique item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    m1.stay_id,
                    m1.distributionpoint_id,
                    m1.lastoutscandate
               FROM multireadscanbatch mb, multireadscanbatchcontents m1, uniqueitem u1
              WHERE mb.multireadscanbatch_id = gv_multireadscanbatch_id
                and m1.multireadscanbatch_id = mb.multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                -- HVH 1/7/2015 added the following condition to prevent that uniqueitem is updated
                -- with wrong values, in case of out-of-sequence processing due to offline scanning.
                and m1.lastscantimestamp <= m1.scantimestamp
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_soil_in_gd,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- soil_in_gd_upd_unique_item



   ---------------------------------------------
   procedure create_soil_in_gd_scans is
   begin
    begin
    writemultireaddebuglog('Create Soil in GD Scans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create Soil in GD Scans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, batchnumber, scandateoffset, qualitytesttype_id, washingprocess_id,
             treatmenttype_id, deliverynotenumber, dayssincelastinscan, dayssincelastoutscan,
             dayssincelastscan)
    select mbc.scan_id,
           mbc.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           mbc.distributionpoint_id,
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_soil_in_gd,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           null, -- route_ID
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           73, -- transaction type soil in GD scan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           null, -- batchnumber,
           0,    -- scandateoffset,
           null, -- qualitytesttype_id,
           null, -- washingprocess_id,
           null, -- treatmenttype_id,
           mbc.lastdeliverynotenumber,
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate)
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.multireadexception_id is null
       and mbc.uniqueitem_id is not null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end; -- create_soil_in_gd_scans

   ----------------------------------------------------------------
   -- Begin f_processsoilingdscanbatch
   begin
      begin
        gv_main_code_block := 'Process Soil in GD Scan Batch';
        -- count number of items
        writemultireaddebuglog('Select Contents');
        select sum(case when m.poolitemyn='Y' then 1 else 0 end) number_pool_items,
               sum(case when m.poolitemyn='N' then 1 else 0 end) number_nonpool_items
          into lv_number_pool_items,
               lv_number_nonpool_items
          from multireadscanbatchcontents m, status s
         where m.multireadscanbatch_id = gv_multireadscanbatch_id
           and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
           and m.multireadexception_id is null
           and s.status_id = m.status_id;
      exception
        when no_data_found then
          null;
        when others then
         begin
          gv_result := gc_result_ora_error;
          gv_last_error_number  := SQLCODE;
          gv_last_error_message := SQLERRM;
          writemultireaderrorlog;
          return gc_result_ora_error;
        end;
      end;

    if gv_result = 0 then
     Retrieve_main_item_info;
    end if;

    if gv_result = 0 then
    begin  -- exception block

     Soil_in_gd_upd_unique_item;

     create_soil_in_gd_scans;

     Create_reject_scans(73); -- 73 = soil in GD scan

     commit; -- overall commit on updates and inserts.
     return 0;
    exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(73, 'N');
          gv_result := gc_result_duplicate_scan_err;
          return(gv_result);
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processsoilingdscanbatch;

  function f_processcleanreturnbatch return number is

   ---------------------------------------------
   procedure retrieve_main_item_info is

   begin
    begin
    writemultireaddebuglog('Retrieve main item info step 1b nonpool');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    u.uniqueitem_id,
                    u.primaryid,
                    w.customer_id,
                    we.weareremployment_id,
                    we.distributionpoint_id,
                    case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select g.deliverypoint_id
                                    from garmentdispenser g
                                   where g.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id,
                    u.customerowned,
                    uif.lastissuedate,
                    uif.qualitygrade_id,
                    p.typeofmerchandise
               FROM multireadscanbatchcontents m1, uniqueitem u,
                    uniqueitemfixedinfo uif, product p, uniqueitemnonpool unp,
                    weareremployment we, wearer w
              WHERE m1.uniqueitem_id = u.uniqueitem_id
                and m1.uniqueitem_id = uif.uniqueitem_id
                and m1.uniqueitem_id = unp.uniqueitem_id
                and we.weareremployment_id = unp.weareremployment_id
                and w.wearer_id = we.wearer_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.poolitemyn = 'N'
                and m1.uniqueitem_id is not null
                --and m1.multireadexception_id is null   --removed so that for rejected scans wearer is known
                and p.product_id = u.product_id
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.idcode                = MERGE_SUBQUERY.primaryid,
               m.customer_id           = MERGE_SUBQUERY.customer_id,
               m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
               m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
               m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
               m.customerowned         = MERGE_SUBQUERY.customerowned,
               m.lastissuedate         = MERGE_SUBQUERY.lastissuedate,
               m.qualitygrade_id       = MERGE_SUBQUERY.qualitygrade_id,
               m.typeofmerchandize     = MERGE_SUBQUERY.typeofmerchandise;
    exception
      when no_data_found then
        null;
    end;
   end; -- retrieve_main_item_info

   ---------------------------------------------
   procedure retrieve_item_info is

   begin
    -- find plpc
    begin
    writemultireaddebuglog('Retrieve item info step 2a plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    nvl( -- first try active plpc
                    nvl( -- first try exact match size
                    (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     , -- then try size *
                     (select p.productlistpercustomer_id
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id
                        and p.dateactive <= trunc(sysdate)
                        and p.dateinactive >= trunc(sysdate))
                     ), -- then try all plpc
                    nvl( -- first try exact match size
                    (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = m1.sizedefinition_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     , -- then try size *
                     (select max(p.productlistpercustomer_id)
                       from productlistpercustomer p
                      where p.customer_id = m1.customer_id
                        and p.product_id = m1.product_id
                        and p.sizedefinition_id = gv_size_star_id
                        and p.finishingmethod_id = m1.finishingmethod_id)
                     )
                     ) productlistpercustomer_id
               FROM multireadscanbatchcontents m1
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.customer_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.plpc_id = MERGE_SUBQUERY.productlistpercustomer_id,
               m.scan_id = seq_scan.nextval;
    exception
      when no_data_found then
         null;
    end;
    -- load delayed even exchange and related dee delivery scheme
    begin
    writemultireaddebuglog('Retrieve item info step 2b plpc');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    m1.uniqueitem_id,
                    p.delayedevenexchange,
                    p.deedeliveryscheme_id
               FROM multireadscanbatchcontents m1, productlistpercustomer p
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.productlistpercustomer_id = m1.plpc_id
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.delayedevenexchange = MERGE_SUBQUERY.delayedevenexchange,
               m.deedeliveryscheme_id = MERGE_SUBQUERY.deedeliveryscheme_id;
    exception
      when no_data_found then
        null;
    end;

    -- find secondary ID, to store in scan record when available
    begin
    writemultireaddebuglog('Retrieve item info step 3 secID');
    MERGE /*+index(m XIE2MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
      USING (SELECT m1.multireadscanbatch_id,
                    m1.subbatchnumber,
                    su.uniqueitem_id,
                    su.secondaryid
               FROM multireadscanbatchcontents m1, secondaryuniqueitem su
              WHERE m1.uniqueitem_id = su.uniqueitem_id
                and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
            ) MERGE_SUBQUERY
      ON (m.multireadscanbatch_id = MERGE_SUBQUERY.multireadscanbatch_id
      AND m.subbatchnumber = MERGE_SUBQUERY.subbatchnumber
      AND m.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET m.secondaryid    = MERGE_SUBQUERY.secondaryid;
      exception
        when no_data_found then
          null;
      end;
   end; -- retrieve_item_info

   ---------------------------------------------
   procedure Cleanreturn_update_unique_item is
   begin
     begin
      writemultireaddebuglog('Update_unique item');
      MERGE INTO uniqueitem u
      USING (SELECT m1.uniqueitem_id,
                    m1.scantimestamp,
                    case when m1.poolitemyn='Y' and m1.secondaryid is null
                      then m.businessunit_id -- update BU upon inscan only for pool items without secID
                      else m1.businessunit_id -- original BU
                    end businessunit_id,
                    m1.stay_id,
                    m1.status_id,
                    case when u1.status_id <> gc_status_id_in_circ
                     then m1.scantimestamp
                     else u1.statuschangedate
                    end statuschangedate,
                    u1.lastdistributionpoint_link_id,
                    m1.plannedoutdate,
                    u1.planneddeliverydate,
                    m1.distributionpoint_id,
                    m1.poolitemyn
               FROM multireadscanbatch m, multireadscanbatchcontents m1, uniqueitem u1
              WHERE m1.uniqueitem_id = u1.uniqueitem_id
                and m1.multireadexception_id is null
                and m1.multireadscanbatch_id = m.multireadscanbatch_id
                and m.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
            ) MERGE_SUBQUERY
      ON (u.uniqueitem_id = MERGE_SUBQUERY.uniqueitem_id)
      WHEN MATCHED THEN
        UPDATE
           SET  u.lastdistributionpoint_link_id =
                             case when MERGE_SUBQUERY.poolitemyn = 'Y'
                               then nvl(MERGE_SUBQUERY.distributionpoint_id,lastdistributionpoint_link_id)
                               else null
                             end,
                u.distributionpoint_id = null,   -- disconnect from previous user
                u.prevstay_id = MERGE_SUBQUERY.stay_id,
                u.stay_id = gc_stay_id_inscan_cleanreturn,
                u.staychangedate = MERGE_SUBQUERY.scantimestamp,
                u.lastscandate = MERGE_SUBQUERY.scantimestamp,
                u.systemuser_id = gv_systemuser_id,
                u.timestamp = sysdate;
    exception
      when no_data_found then
        null;
    end;
   end; -- Cleanreturn_update_unique_item

   ---------------------------------------------
   procedure decrease_onsite_inventory is
   begin
    begin
    writemultireaddebuglog('Decrease onsite inventory');
    MERGE INTO onsiteinventoryadjustment o
      USING ( SELECT /*+ index(m1 XIE1MULTIREADSCANCONTENTBATCH) index(p XAK2PRODUCTLISTPERDISTRIBPOINT) index(plpc XPKPRODUCTLISTPERCUSTOMER) */
                    p.productlistperdistribpoint_id,
                    5 origin, trunc(sysdate) inventorydate,
                    count(1) qty
               FROM multireadscanbatchcontents m1, productlistperdistribpoint p,
                    productlistpercustomer plpc, customer c
              WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                and (m1.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                and p.distributionpoint_id = m1.distributionpoint_id
                and p.product_id = m1.product_id
                and p.sizedefinition_id = m1.sizedefinition_id
                and p.finishingmethod_id = m1.finishingmethod_id
                and plpc.productlistpercustomer_id = m1.plpc_id
                and plpc.soilcountmethod <> 0
                and c.customer_id = plpc.customer_id
                and c.allocationmethod = 0 -- Only decrease onsite inventory upon inscan when customer is NOT setup for allocation
                and m1.uniqueitem_id is not null
                and m1.multireadexception_id is null
              GROUP BY p.productlistperdistribpoint_id
            ) MERGE_SUBQUERY
      ON (o.productlistperdistribpoint_id = MERGE_SUBQUERY.productlistperdistribpoint_id
      AND o.origin                        = MERGE_SUBQUERY.origin
      AND o.inventorydate                 = MERGE_SUBQUERY.inventorydate
      AND o.reference is null)
      WHEN MATCHED THEN
        UPDATE
           SET o.quantity = o.quantity - MERGE_SUBQUERY.qty,
               o.systemuser_id = gv_systemuser_id,
               o.timestamp = sysdate
      WHEN NOT MATCHED THEN
        INSERT
          (onsiteinventoryadjustment_id,
           productlistperdistribpoint_id,
           origin,
           inventorydate,
           quantity,
           reference,
           systemuser_id,
           timestamp,
           invoiceheader_id)
        VALUES
          (seq_onsiteinventoryadjustment.nextval,
           MERGE_SUBQUERY.productlistperdistribpoint_id,
           MERGE_SUBQUERY.origin,
           MERGE_SUBQUERY.inventorydate,
           MERGE_SUBQUERY.qty * -1,
           null, -- reference
           gv_systemuser_id,
           sysdate,
           null);
    exception
      when no_data_found then
        null;
    end;
   end; --decrease_onsite_inventory


   ---------------------------------------------
   procedure create_scans is
   begin
    -- populate scan_ID in case it was not yet populated by retrieve item info
    begin
    writemultireaddebuglog('Create inscans - populate scanID');
    UPDATE multireadscanbatchcontents m
       set m.scan_id = seq_scan.nextval
     where m.multireadscanbatch_id = gv_multireadscanbatch_id
       and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and m.multireadexception_id is null
       and m.uniqueitem_id is not null
       and m.scan_id is null;
    exception
      when no_data_found then
        null;
    end;

    begin
    writemultireaddebuglog('Create inscans');
    insert into scan
            (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id,
             weareremployment_link_id, distributionpoint_link_id, product_link_id,
             sizedefinition_link_id, stay_id, status_id, scanstation, issuedate, route_id,
             reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id,
             timestamp, prevstay_id, transactiontype_id, dayslate, uniqueitem_link_id,
             secondaryid, scandateoffset, dayssincelastinscan, dayssincelastoutscan, dayssincelastscan,
             batchnumber )
    select mbc.scan_id,
           mb.businessunit_id,
           mbc.scantimestamp,
           mbc.idcode,
           mbc.customer_id,
           case when mbc.poolitemyn = 'N'
            then mbc.weareremployment_id
            else null -- weareremploymentid is null for pool items
           end,  -- weareremploymentid
           nvl(mbc.distributionpoint_id,mbc.prev_distributionpoint_id) distributionpoint_id, -- ABS-44277
           mbc.product_id,
           mbc.sizedefinition_id,
           gc_stay_id_inscan_cleanreturn,
           gc_status_id_in_circ,
           w.code, -- workstation code
           mbc.lastissuedate,
           mbc.lastinroute_id,
           null, -- reasoncode
           mbc.customerowned,
           getyearofweek(trunc(mbc.scantimestamp)),
           getisoweek(trunc(mbc.scantimestamp)),
           getabsdaynumber(trunc(mbc.scantimestamp)),
           mbc.qualitygrade_id,
           mb.systemuser_id,
           sysdate,
           mbc.stay_id, -- prev stay
           55, -- transaction type Clean Return Scan
           0, -- days late
           mbc.uniqueitem_id,
           mbc.secondaryid,
           gv_pickupdate - trunc(mbc.scantimestamp), -- scandateoffset
           trunc(mbc.scantimestamp) - trunc(mbc.lastinscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastoutscandate),
           trunc(mbc.scantimestamp) - trunc(mbc.lastscandate),
           mbc.uniqueitembatchnumber
      from multireadscanbatch         mb,
           multireadscanbatchcontents mbc,
           workstation                w
     where mb.multireadscanbatch_id = gv_multireadscanbatch_id
       and mbc.multireadscanbatch_id = mb.multireadscanbatch_id
       and (mbc.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
       and mbc.scan_id is not null
       and mbc.multireadexception_id is null
       and w.workstation_id = mb.workstation_id;
     exception
        when dup_val_on_index then
          raise gc_duplicate_exception;
        when no_data_found then
          null;
     end;

     create_scanflags;
   end create_scans; -- create_scans

   procedure create_correctionticket is
     lv_packingnoteid packingnote.packingnote_id%type;
     lv_businessunit_id businessunit.businessunit_id%type;
     lv_businessunit_code businessunit.code%type;
     lv_plantdepartmentid plantdepartment.plantdepartment_id%type;
     lv_deliverypoint_id deliverypoint.deliverypoint_id%type;

     procedure get_extra_info is
     begin
       --get_extra_info
       select mb.businessunit_id,
              bu.code,
              (select min(pd.plantdepartment_id)
                 from plantdepartment pd
                where pd.plant_id = bu.plant_id)
         into lv_businessunit_id,
              lv_businessunit_code,
              lv_plantdepartmentid
         from multireadscanbatch mb
         join businessunit bu
           on bu.businessunit_id = mb.businessunit_id
        where mb.multireadscanbatch_id = gv_multireadscanbatch_id;
     end get_extra_info;

     procedure create_packingnote is
        lv_transportarticleid transportarticle.transportarticle_id%type;
        lv_notenumber packingnote.notenumber%type;
     begin
         writemultireaddebuglog('create_packingnote');
         --create_packingnote
         --get defaulttransportarticle
         select ta.transportarticle_id
           into lv_transportarticleid
           from transportarticle ta
          where ta.defaulttransportarticle = 'Y';
         --get packingnote number

         for x in (select mbc.distributionpoint_id, mbc.businessunit_id from multireadscanbatchcontents mbc
               where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                 and mbc.multireadexception_id is null
                 group by mbc.distributionpoint_id, mbc.businessunit_id) loop
            begin
             select pn.notenumber, pn.packingnote_id into lv_notenumber, lv_packingnoteid
               from packingnote pn
              where pn.distributionpoint_id = x.distributionpoint_id
                and pn.processbusinessunit_id = x.businessunit_id
                and pn.deliverydate = trunc(sysdate)
                and pn.origin = 3
                and pn.status_id = gc_pn_inprogress_statusid;
            exception
              when no_data_found then

              writemultireaddebuglog('Deliverynote for businessunit ' ||
                                lv_businessunit_code);
              execute immediate 'select SEQ_DELIVERYNOTE_' ||
                             lv_businessunit_code || '.nextval from dual'
                  into lv_notenumber;

             select dp.deliverypoint_id into lv_deliverypoint_id
                       from distributionpoint dp
                      where dp.distributionpoint_id = x.distributionpoint_id;

         --insert into packingnote
         insert into packingnote
           (packingnote_id, notenumber, productiondate, deliverydate, status_id,
            remark, distributionpoint_id, deliverypoint_id, plantdepartment_id, transportarticle_id,
            systemuser_id, processbusinessunit_id, route_id, timestamp, cleanreturn,
            sequencenumber, deadline, occupancy, invoicebusinessunit_id, routecontrol_id,
            originaldeliverydate,  origin, stopnumber, daynumber, correctednotenumber,
            creationtimestamp, referencenumber, returndateloan, stop_id, consignmentnote_id,
            straightevenreturn, numberofgarmentsinlocker, numberoflockers, bulkpackingnote_id, freeofchargereason_id,
            week, year, weighingticket_id, totalamount, totalamountexcludingvat,
            pricescalculated, showoninvoiceappendix, deliveryremark, exported, finishedpacking,
            picklistprinted, invoicestatus, numberofcolli, emailstatus, emailmaybesent,
            processedtimestamp, processedsystemuser_id, signed, internalprocessingbu_id, creationsystemuser_id,
            salesnote_id, parceltracecode, calculatetransportcosts, pdfarchived, correctionfornote_id,
            enddateforuse, correctconsignmentnote, pnremark, loadsequencenr,
            deliverysignature_id)
         values
           (seq_packingnote.nextval, lv_notenumber, trunc(sysdate), trunc(sysdate) + 1, gc_pn_inprogress_statusid,
            null, x.distributionpoint_id,
            lv_deliverypoint_id, lv_plantdepartmentid, lv_transportarticleid,
            gv_systemuser_id, lv_businessunit_id, null, sysdate, 'N',
            1, null, 100, lv_businessunit_id, null,
            trunc(sysdate), 3 /* Origin correction ticket */, null, getabsdaynumber(trunc(sysdate)), 0,
            sysdate, null, null, null, null,
            'N', 0, 0, null, null,
            getisoweek(trunc(sysdate)), getyearofweek(trunc(sysdate)), null, 0, 0,
            'N', 'Y', 'N', 'N', 0, 'N', 0, 1, 0, 'N',
            null, 0, 'N', null, gv_systemuser_id,
            null, null, 'N', 'N', null,
            trunc(sysdate), 0, null, 0,
            null)
            returning packingnote_id into lv_packingnoteid;
            end;

         end loop;
     end create_packingnote;

     procedure get_create_packingnoteline is
     begin
       --3) get_create_packingnoteline
       writemultireaddebuglog('get_create_packingnoteline');
       merge into packingnoteline pnl
       using (select lv_packingnoteid packingnote_id,
                     mbc.product_id,
                     mbc.sizedefinition_id sizedefinition_id,
                     mbc.finishingmethod_id finishingmethod_id,
                     max(p.packingsequence) packingsequence,
                     count(1) quantity
                from multireadscanbatchcontents mbc
                join product p
                  on p.product_id = mbc.product_id
               where mbc.multireadscanbatch_id = gv_multireadscanbatch_id
                 and mbc.multireadexception_id is null
               group by mbc.product_id,
                        mbc.sizedefinition_id,
                        mbc.finishingmethod_id) merge_subquery
       on (pnl.packingnote_id = merge_subquery.packingnote_id and pnl.product_id = merge_subquery.product_id and pnl.sizedefinition_id = merge_subquery.sizedefinition_id and pnl.finishingmethod_id = merge_subquery.finishingmethod_id)
       when matched then
         update
            set pnl.deliveredamount = pnl.deliveredamount -
                                      merge_subquery.quantity,
                pnl.systemuser_id   = gv_systemuser_id,
                pnl.timestamp       = sysdate
       when not matched then
         insert
           (packingnoteline_id, product_id, packingsequence, finishingmethod_id, price,
            discount, packingnote_id, sizedefinition_id, systemuser_id, location,
            timestamp, remarkforpackinginstructions, customcode, customdescription, replacementqty,
            updaterentqty, adjustmentreason_id, origin, putuptype, freeofchargereason_id,
            nochargefirstissue, nochargeactiveseason, deliveredcogqty, auxiliarystatus, standardamount,
            variationamount, deliveredamount, tobedeliveredamount, amount, taxgroupcode,
            bundleqty, nochargefirstissuecog, scannedbundles, pricecog, nodeliveryamount,
            creationtimestamp, creationsystemuser_id, autoreplacementqty)
         values
           (seq_packingnoteline.nextval, merge_subquery.product_id, merge_subquery.packingsequence, merge_subquery.finishingmethod_id, null,
            0, merge_subquery.packingnote_id, merge_subquery.sizedefinition_id, gv_systemuser_id, null,
            sysdate, null, null, null, 0,
            0, null, 1, 1, null,
            0, 0, 0, null, 0,
            0, -merge_subquery.quantity, 0, 0,
            null,
            0,
            0,
            0,
            null,
            0,
            sysdate,
            gv_systemuser_id,
            0);
     end get_create_packingnoteline;

   begin
     --create_deliverynote
     get_extra_info;
     --2) get_create_packingnote
     create_packingnote;
     --3) get_create_packingnoteline
     get_create_packingnoteline;
   end create_correctionticket;

   ----------------------------------------------------------------
   -- Begin f_processcleanreturnbatch
   begin
     gv_main_code_block := 'Process Clean Return Batch';

     if gv_result = 0 then
      Retrieve_main_item_info;
     end if;

     if gv_result = 0 then
      begin  -- exception block
       Retrieve_item_info;
       Cleanreturn_update_unique_item;

       if gs_ss_recordonsiteinventory = 'Y' then
         decrease_onsite_inventory;
       end if;
       create_scans;
       create_correctionticket;

       if gv_prodprocessbuffer_id is not null then
         load_uniqueitem_buffer_info;
         insertupdate_uniqueitembufinfo(1);
         create_prodprocessbufscans(1);
       end if;

       Create_reject_scans(1); -- 1 = transactiontype inscan

       commit; -- overall commit on updates and inserts.
       return 0;
      exception
      when gc_duplicate_exception then
        begin
          rollback;
          mark_duplicate_scans(1, 'Y');
          gv_result := gc_result_duplicate_scan_err;
          return gv_result;
        end;
      when others then
       begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;
    end;
    else return(gv_result);
    end if;
   end f_processcleanreturnbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadinscanbatch(fp_multireadscanbatch_id number,
                                    fp_subbatchnumber        number,
                                    fp_action                number,
                                    fp_pickupdate            date default trunc(sysdate),
                                    fp_exchangecart_id       in number default null)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;

      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);
      gv_pickupdate := fp_pickupdate;

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and gv_prod_inscan_YN= 'Y' and gv_items_in_batch <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateinscanbatch('Y');
      end if;

      if gv_result = 0 and gv_knt_inscan_YN= 'Y' and gv_items_in_batch_knt <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatescanbatchKNT(gc_transtype_inscan);
      end if;

      -- do processing in case of action=process or action=both
      if gv_result = 0 and gv_prod_inscan_YN= 'Y' and gv_items_in_batch <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processinscanbatch('Y', 1, fp_exchangecart_id);
          if gv_result = gc_result_duplicate_scan_err then
            --try again
            gv_result := 0;
            gv_result := f_processinscanbatch('Y', 1, fp_exchangecart_id);
          end if;
      end if;

      if gv_result = 0 and gv_knt_inscan_YN= 'Y' and gv_items_in_batch_knt <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processinscanbatchKNT;
      end if;

      return(gv_result);
  end f_domultireadinscanbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireaddisinfecscanbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;

      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatescanbatchKNT(gc_transtype_disinfect);
      end if;

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processdisinfectscanbatchKNT;
      end if;

      return(gv_result);
  end f_domultireaddisinfecscanbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadcleanreturnbatch(fp_multireadscanbatch_id in number,
                                         fp_subbatchnumber        in number,
                                         fp_action                in number,
                                         fp_pickupdate            in date default trunc(sysdate),
                                         fp_exchangecart_id       in number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
  begin
    -- f_domultireadcleanreturnbatch, derived from f_domultireadinscanbatch!
    gv_result := 0;

    initialize_batch(fp_multireadscanbatch_id, fp_subbatchnumber);
    gv_pickupdate := fp_pickupdate;

    -- do validation in case of action=validate or action=both
    if gv_result = 0 and gv_items_in_batch <> 0 and (fp_action = 1 or fp_action = 3) then
      gv_result := f_validateinscanbatch('Y');
    end if;

    if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 1 or fp_action = 3) then
      gv_result := f_validatescanbatchknt(gc_transtype_inscan);
    end if;

    -- do processing in case of action=process or action=both
    if gv_result = 0 and gv_items_in_batch <> 0 and (fp_action = 2 or fp_action = 3) then
      gv_result := f_processinscanbatch('Y', 55, fp_exchangecart_id);
      if gv_result = gc_result_duplicate_scan_err then
         --try again
         gv_result := 0;
         gv_result := f_processinscanbatch('Y', 55, fp_exchangecart_id);
      end if;
    end if;

    if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 2 or fp_action = 3) then
      gv_result := f_processinscanbatchknt;
    end if;

    return(gv_result);
  end f_domultireadcleanreturnbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadoutscanbatch(fp_multireadscanbatch_id number,
                                     fp_subbatchnumber        number,
                                     fp_action                number,
                                     fp_customer_id           number default null)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateoutscanbatch(fp_customer_id);
      end if;
      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processoutscanbatch;
          if gv_result = gc_result_duplicate_scan_err then
            --try again
            gv_result := 0;
            gv_result := f_processoutscanbatch;
          end if;
      end if;
      return(gv_result);
  end f_domultireadoutscanbatch;


  -----------------------------------------------------------------------------------------
  function f_docompletebundleoutscan(fp_multireadscanbatch_id number)
    return number is
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
  begin   -- f_docompletebundleoutscan
    gv_result := 0;
    -- ABS 21481
    gv_multireadscanbatch_id := fp_multireadscanbatch_id;

  select B.PLANT_ID
      into gv_plant_id
      from MULTIREADSCANBATCH M, BUSINESSUNIT B, WORKSTATION W, PLANT PT
     where M.MULTIREADSCANBATCH_ID = gv_multireadscanbatch_id
       and B.BUSINESSUNIT_ID = M.BUSINESSUNIT_ID
       and W.WORKSTATION_ID = M.WORKSTATION_ID
       and B.PLANT_ID = PT.PLANT_ID;
    read_systemsettings;

    if gs_ss_receivescanusvirtbundle <> 1 then
      begin
        -- delete uniquebundles once they are outscanned even if setting is set to 0
        delete_uhfbundle(0);
      end;
    end if;

    return(gv_result);
  end f_docompletebundleoutscan;

  -----------------------------------------------------------------------------------------
  function f_docompletebundlereceivescan(fp_multireadscanbatch_id number)
    return number is
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
  begin   -- f_docompletebundlereceivescan
    gv_result := 0;
    -- ABS 21481
    gv_multireadscanbatch_id := fp_multireadscanbatch_id;

    -- delete uniquebundles once they are received
    delete_uhfbundle(0);

    return(gv_result);
  end f_docompletebundlereceivescan;

  -----------------------------------------------------------------------------------------
/* Todo 24060:  Special processing for system setting uhfpoolitemsstartupphase
   if No then qty delivered = qty scanned  (done in above part)
   if Yes then it depends on system setting uhfpoolitemsstartupcalc
      0 = always ordered quantity, even if scanned quantity is higher or lower, unless tobedelivered = 0
      1 = if scanned qty is higher than ordered qty then scanned qty else ordered qty
      2 = if scanned qty is higher than ordered qty then scanned qty else ordered qty, except when
           ordered qty = 0 then delivered qty will be 0 too.
      3 = always ordered quantity, even if scanned quantity is higher or lower
*/
  function f_douhfstartupphaseprocessing(fp_multireadscanbatch_id number, fp_plant_id number)
    return number is
    -- output result:
    -- 0 = okay
    -- <> 0 = ORA error
    lc_ss_uhfpoolitemstartupcalc number;

  begin
    gv_multireadscanbatch_id := fp_multireadscanbatch_id;
    gv_subbatchnumber := 0;
    gv_plant_id := fp_plant_id;
    gv_main_code_block := 'UHF Startup Phase Processing';
    gv_code_block := 'Read system setting';
    lc_ss_uhfpoolitemstartupcalc := 2; -- default
    gv_result := 0;
     begin
      select s.value
        into lc_ss_uhfpoolitemstartupcalc
        from systemsetting s
       where s.name = 'UHFPOOLITEMSTARTUPCALC'
         and s.plant_id = fp_plant_id;
      select s.value
        into gc_ss_debuglevel
        from systemsetting s
       where s.name = 'MULTIREAD_DEBUG_LEVEL'
         and s.plant_id = fp_plant_id;
    exception
      when no_data_found then
        lc_ss_uhfpoolitemstartupcalc := 2;
    end;
    writemultireaddebuglog('Start');
    begin
    gv_isbulkshipmentnote := 'N';
      select decode(p.origin,14,'Y','N')  -- origin 14 is considered a bulk multiread shipment note
        into gv_isbulkshipmentnote
        from multireadscanbatch mb,
             packingnote p
       where p.packingnote_id = mb.packingnote_id
         and mb.multireadscanbatch_id = gv_multireadscanbatch_id;
    exception
      when no_data_found then
       begin
         gv_isbulkshipmentnote := 'N';
       end;
    end;


    begin
     if lc_ss_uhfpoolitemstartupcalc = 0 then
        writemultireaddebuglog('Update Packingnoteline Calc=0');
        UPDATE packingnoteline p
           set p.deliveredamount = p.tobedeliveredamount,
               p.timestamp = sysdate
         where p.packingnoteline_id in (select pl.packingnoteline_id
                                          from packingnoteline pl,
                                               multireadscanbatch b,
                                               product pr
                                         where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                           and pl.packingnote_id = b.packingnote_id
                                           and pr.product_id = pl.product_id
                                           and pr.uniquepoolitem='Y'
                                           and pl.tobedeliveredamount <> 0);
    end if; -- lc_ss_uhfpoolitemstartuppcalc = 0
     if lc_ss_uhfpoolitemstartupcalc = 1 then
        writemultireaddebuglog('Update Packingnoteline Calc=1');
        UPDATE packingnoteline p
           set p.deliveredamount = p.tobedeliveredamount,
               p.timestamp = sysdate
         where p.packingnoteline_id in (select pl.packingnoteline_id
                                          from packingnoteline pl,
                                               multireadscanbatch b,
                                               product pr
                                         where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                           and pl.packingnote_id = b.packingnote_id
                                           and pr.product_id = pl.product_id
                                           and pr.uniquepoolitem='Y'
                                           and pl.deliveredamount < pl.tobedeliveredamount
                                           );
    end if; -- lc_ss_uhfpoolitemstartuppcalc = 1
     if lc_ss_uhfpoolitemstartupcalc = 2 then
        writemultireaddebuglog('Update Packingnoteline Calc=2');
        UPDATE packingnoteline p
           set p.deliveredamount = p.tobedeliveredamount,
               p.timestamp = sysdate
         where p.packingnoteline_id in (select pl.packingnoteline_id
                                          from packingnoteline pl,
                                               multireadscanbatch b,
                                               product pr
                                         where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                           and pl.packingnote_id = b.packingnote_id
                                           and pr.product_id = pl.product_id
                                           and pr.uniquepoolitem='Y'
                                           and (pl.deliveredamount < pl.tobedeliveredamount
                                            or pl.tobedeliveredamount = 0)
                                           );
    end if; -- lc_ss_uhfpoolitemstartuppcalc = 2
    if lc_ss_uhfpoolitemstartupcalc = 3 then
        writemultireaddebuglog('Update Packingnoteline Calc=3');
        UPDATE packingnoteline p
           set p.deliveredamount = p.tobedeliveredamount
         where p.packingnoteline_id in (select pl.packingnoteline_id
                                          from packingnoteline pl,
                                               multireadscanbatch b,
                                               product pr
                                         where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                           and pl.packingnote_id = b.packingnote_id
                                           and pr.product_id = pl.product_id
                                           and pr.uniquepoolitem='Y');
    end if; -- lc_ss_uhfpoolitemstartuppcalc = 3

    -- same processing for child notes of the bulk note
    if gv_isbulkshipmentnote = 'Y' then
      if lc_ss_uhfpoolitemstartupcalc = 0 then
          writemultireaddebuglog('Update Packingnoteline Calc=0');
          UPDATE packingnoteline p
             set p.deliveredamount = p.tobedeliveredamount,
                 p.timestamp = sysdate
           where p.packingnoteline_id in (select pl.packingnoteline_id
                                            from packingnoteline pl,
                                                 packingnote pn,
                                                 multireadscanbatch b,
                                                 product pr
                                           where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                             and pn.bulkpackingnote_id = b.packingnote_id
                                             and pl.packingnote_id = pn.packingnote_id
                                             and pr.product_id = pl.product_id
                                             and pr.uniquepoolitem='Y'
                                             and pl.tobedeliveredamount <> 0);
      end if; -- lc_ss_uhfpoolitemstartuppcalc = 0
      if lc_ss_uhfpoolitemstartupcalc = 1 then
          writemultireaddebuglog('Update Packingnoteline Calc=1');
          UPDATE packingnoteline p
             set p.deliveredamount = p.tobedeliveredamount,
                 p.timestamp = sysdate
           where p.packingnoteline_id in (select pl.packingnoteline_id
                                            from packingnoteline pl,
                                                 packingnote pn,
                                                 multireadscanbatch b,
                                                 product pr
                                           where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                             and pn.bulkpackingnote_id = b.packingnote_id
                                             and pl.packingnote_id = pn.packingnote_id
                                             and pr.product_id = pl.product_id
                                             and pr.uniquepoolitem='Y'
                                             and pl.deliveredamount < pl.tobedeliveredamount
                                             );
      end if; -- lc_ss_uhfpoolitemstartuppcalc = 1
      if lc_ss_uhfpoolitemstartupcalc = 2 then
          writemultireaddebuglog('Update Packingnoteline Calc=2');
          UPDATE packingnoteline p
             set p.deliveredamount = p.tobedeliveredamount,
                 p.timestamp = sysdate
           where p.packingnoteline_id in (select pl.packingnoteline_id
                                            from packingnoteline pl,
                                                 packingnote pn,
                                                 multireadscanbatch b,
                                                 product pr
                                           where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                             and pn.bulkpackingnote_id = b.packingnote_id
                                             and pl.packingnote_id = pn.packingnote_id
                                             and pr.product_id = pl.product_id
                                             and pr.uniquepoolitem='Y'
                                             and (pl.deliveredamount < pl.tobedeliveredamount
                                              or pl.tobedeliveredamount = 0)
                                             );
      end if; -- lc_ss_uhfpoolitemstartuppcalc = 2
      if lc_ss_uhfpoolitemstartupcalc = 3 then
          writemultireaddebuglog('Update Packingnoteline Calc=3');
          UPDATE packingnoteline p
             set p.deliveredamount = p.tobedeliveredamount,
                 p.timestamp = sysdate
           where p.packingnoteline_id in (select pl.packingnoteline_id
                                            from packingnoteline pl,
                                                 packingnote pn,
                                                 multireadscanbatch b,
                                                 product pr
                                           where b.multireadscanbatch_id = gv_multireadscanbatch_id
                                             and pn.bulkpackingnote_id = b.packingnote_id
                                             and pl.packingnote_id = pn.packingnote_id
                                             and pr.product_id = pl.product_id
                                             and pr.uniquepoolitem='Y');
      end if; -- lc_ss_uhfpoolitemstartuppcalc = 3
    end if; -- gv_isbulknote = 'Y' then


    commit;
    return(gv_result);
    exception
      when others then
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
        return(gv_result);
    end;
  end f_douhfstartupphaseprocessing;

  -----------------------------------------------------------------------------------------
  function f_domultireadoutscanpoolbatch(fp_multireadscanbatch_id number,
                                         fp_subbatchnumber        number,
                                         fp_action                number,
                                         fp_trackonly             varchar2 default 'N',
                                         fp_exchangecart_id       number default null)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      gv_outscantrackonly := fp_trackonly;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and gv_items_in_batch <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateoutscanpoolbatch;
      end if;

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateoutscanbatchKNT;
      end if;

      -- container processing before item processing in order to link items to pncontainer
      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processoutscanbatchKNT;
      end if;

      -- do processing in case of action=process or action=both
      if gv_result = 0 and gv_items_in_batch <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processoutscanpoolbatch(fp_exchangecart_id);
          if gv_result = gc_result_duplicate_scan_err then
            --try again
            gv_result := 0;
            gv_result := f_processoutscanpoolbatch(fp_exchangecart_id);
          end if;
      end if;

      return(gv_result);
  end f_domultireadoutscanpoolbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadscanandcountbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number,
                                          fp_consumptionpoint_id   number,
                                          fp_route_id              number,
                                          fp_planneddeliverydate   date,
                                          fp_trackonly             varchar2 default 'N',
                                          fp_batchnumber           varchar2 default null)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      gv_outscantrackonly := fp_trackonly;
      gv_consumptionpoint_id := fp_consumptionpoint_id;
      gv_route_id := fp_route_id;
      gv_planneddeliverydate := fp_planneddeliverydate;
      gv_batchnumber := fp_batchnumber;

      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and gv_items_in_batch <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatescanandcountbatch;
      end if;

      -- do processing in case of action=process or action=both
      if gv_result = 0 and gv_items_in_batch <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processscanandcountbatch;
          if gv_result = gc_result_duplicate_scan_err then
             --try again
             gv_result := 0;
             gv_result := f_processscanandcountbatch;
          end if;
      end if;

      return(gv_result);
  end f_domultireadscanandcountbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadstackcheck(fp_multireadscanbatch_id number,
                                   fp_subbatchnumber        number,
                                   fp_stacksize             number,
                                   fp_findpack_YN           varchar2)
    return number is
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      gv_stacksize := fp_stacksize;
      gv_findpack_YN := fp_findpack_YN;

      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      if gv_result = 0
        then gv_result := f_validatestack;
      end if;

      return(gv_result);
  end f_domultireadstackcheck;


  -----------------------------------------------------------------------------------------
  function f_domultireadstackprocess(fp_multireadscanbatch_id number,
                                     fp_stacksize number,
                                     fpo_virtualbundle_id out number,
                                     fp_result number)
    return number is
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,0);

      gv_main_code_block := 'Stack Process';
      if gv_result = 0
        then
          gv_result := f_processstack(fp_stacksize,fp_result,fpo_virtualbundle_id);
      end if;

      return(gv_result);
  end f_domultireadstackprocess;

  -----------------------------------------------------------------------------------------
  function f_domultireadrewashscanbatch(fp_multireadscanbatch_id number,
                                        fp_subbatchnumber        number,
                                        fp_action                number,
                                        fp_reason_id             number default null)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadrewashscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validaterewashscanbatch;
      end if;
      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processrewashscanbatch(fp_reason_id);
        if gv_result = gc_result_duplicate_scan_err then
           --try again
           gv_result := 0;
           gv_result := f_processrewashscanbatch(fp_reason_id);
        end if;
      end if;
      return(gv_result);
  end f_domultireadrewashscanbatch;


  -----------------------------------------------------------------------------------------
  function f_domultireadragscanbatch(fp_multireadscanbatch_id number,
                                     fp_subbatchnumber        number,
                                     fp_action                number,
                                     fp_reason_id             number,
                                     fp_ragreason_id          number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadragscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateragscanbatch;
      end if;
      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processragscanbatch(fp_reason_id,fp_ragreason_id);
          if gv_result = gc_result_duplicate_scan_err then
            --try again
            gv_result := 0;
            gv_result := f_processragscanbatch(fp_reason_id,fp_ragreason_id);
          end if;
      end if;
      return(gv_result);
  end f_domultireadragscanbatch;


  -----------------------------------------------------------------------------------------
  function f_domultireadonsiteinventscan(fp_multireadscanbatch_id number,
                                         fp_garmentassistantbatch_yn varchar2 default 'N',
                                         fp_istockcount_yn           varchar2 default 'N')
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadragscanbatch
      gv_result := 0;
      if fp_garmentassistantbatch_yn = 'Y'
       then gv_garmentassistantbatch := true;
       else gv_garmentassistantbatch := false;
      end if;
      if fp_istockcount_yn = 'Y'
       then gv_istockcountbatch := true;
       else gv_istockcountbatch := false;
      end if;

      initialize_batch(fp_multireadscanbatch_id,1);

      gv_result := f_validateonsiteinventbatch;

      if gv_result = 0
        then gv_result := f_processonsiteinventbatch;
        if gv_result = gc_result_duplicate_scan_err then
          --try again
          gv_result := 0;
          gv_result := f_processonsiteinventbatch;
        end if;
      end if;

      return(gv_result);
  end f_domultireadonsiteinventscan;

  -----------------------------------------------------------------------------------------
  function f_domultireadonsitelockerscan(fp_multireadscanbatch_id number)
    return number is
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
    begin   -- f_domultireadragscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,1);

      gv_result := f_validateonsitelockerscan;

      if gv_result = 0
        then gv_result := f_processonsitelockerscan;
        if gv_result = gc_result_duplicate_scan_err then
          --try again
          gv_result := 0;
          gv_result := f_processonsitelockerscan;
        end if;
      end if;

      return(gv_result);
  end f_domultireadonsitelockerscan;


  -----------------------------------------------------------------------------------------
  function f_domultireadreceivescanbatch(fp_multireadscanbatch_id number,
                                         fp_subbatchnumber        number,
                                         fp_action                number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatereceivescanbatch;
      end if;

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatescanbatchKNT(gc_transtype_receive);
      end if;

      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processreceivescanbatch;
        if gv_result = gc_result_duplicate_scan_err then
           --try again
           gv_result := 0;
           gv_result := f_processreceivescanbatch;
        end if;
      end if;

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processscanbatchKNT(gc_transtype_receive);
      end if;

      return(gv_result);
  end f_domultireadreceivescanbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadsendscanbatch(fp_multireadscanbatch_id number,
                                      fp_subbatchnumber        number,
                                      fp_action                number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatesendscanbatch;
      end if;

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatescanbatchKNT(gc_transtype_send);
      end if;

      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processsendscanbatch;
        if gv_result = gc_result_duplicate_scan_err then
          --try again
          gv_result := 0;
          gv_result := f_processsendscanbatch;
        end if;
      end if;

      if gv_result = 0 and gv_items_in_batch_knt <> 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processscanbatchKNT(gc_transtype_send);
      end if;

      return(gv_result);
  end f_domultireadsendscanbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadsoilingdscanbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateSoilInGDscanbatch;
      end if;

      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processSoilInGDscanbatch;
        if gv_result = gc_result_duplicate_scan_err then
          --try again
          gv_result := 0;
          gv_result := f_processSoilInGDscanbatch;
        end if;
      end if;

      return(gv_result);
  end f_domultireadsoilingdscanbatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadlaundbufscanbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
    lv_nr_of_items_not_inscanned number;

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      if gv_prodprocessbuffer_id is not null
       then
        -- do validation in case of action=validate or action=both
        -- first same validations as inscan
        if gv_result = 0 and (fp_action = 1 or fp_action=3)
          then gv_result := f_validateinscanbatch('N');
        end if;

        if gv_result = 0 and (fp_action = 2 or fp_action=3) then
          begin
            select count(*)
              into lv_nr_of_items_not_inscanned
              from multireadscanbatchcontents m
             where m.multireadscanbatch_id = gv_multireadscanbatch_id
               and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
               and m.multireadexception_id is null
               and m.stay_id not in (select s.stay_id from stay s where s.staytype=1 and (s.staynr between 30 and 39 or s.staynr = 44)); -- laundry stays
          exception
            when no_data_found then
              lv_nr_of_items_not_inscanned := 0;
          end;

          if lv_nr_of_items_not_inscanned > 0 then
              if gv_result = 0 then
                -- set all items that are already inscanned to dummy exception to prevent inscanning them again in next step
                begin
                  UPDATE multireadscanbatchcontents m
                     set m.multireadexception_id = -1 -- dummy value
                   where m.multireadscanbatch_id = gv_multireadscanbatch_id
                     and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                     and m.multireadexception_id is null
                     and m.stay_id in (select s.stay_id from stay s where s.staytype=1 and (s.staynr between 30 and 39 or s.staynr = 44)); -- laundry stays
                  commit;
                exception
                  when no_data_found then
                    null;
                end;
              end if;

              -- do processing in case of action=process or action=both
              if gv_result = 0 then
                gv_result := f_processinscanbatch('N', 1, null);
                if gv_result = gc_result_duplicate_scan_err then
                   --try again
                   gv_result := 0;
                   gv_result := f_processinscanbatch('N', 1, null);
                end if;
              end if;

              if gv_result = 0 then
                -- reset exception for  all items that were already inscanned
                begin
                  UPDATE multireadscanbatchcontents m
                     set m.multireadexception_id = null
                   where m.multireadscanbatch_id = gv_multireadscanbatch_id
                     and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                     and m.multireadexception_id  = -1;
                  commit;
                exception
                  when no_data_found then
                    null;
                end;
              end if;
          end if;  -- if lv_nr_of_items_not_inscanned > 0

          if gv_result = 0 then
            gv_result := f_processlaundrybufscanbatch;
          end if;
        end if;  -- gv_result = 0 and (fp_action = 2 or fp_action=3)

       else  --  gv_prodprocessbuffer_id is null
         gv_code_block := 'No production process buffer defined for workstation ' || gv_workstation_code || ' batch ' || to_char(gv_multireadscanbatch_id);
         writemultireaderrorlog;
         gv_result := gc_result_no_prodprocbuffer;
      end if; --gv_prodprocessbuffer_id is not null

      return(gv_result);
  end f_domultireadlaundbufscanbatch;


  -----------------------------------------------------------------------------------------
  function f_domultireadunattended(fp_multireadscanbatch_id number,
                                   fp_subbatchnumber        number)
    return number is
    -- This function always does validate and process in the same call.
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
    lv_transactiontype number;
    lv_knt_transactiontype number;
    lv_workstation_code workstation.code%type;

   function f_checkalreadyinscannedforunattended (fp_multireadscanbatch_id number,
                                                 fp_subbatchnumber  number) return number is
     -- output result:
     -- 0 = okay
     -- 3 = ORA message

     --------------------------
   begin
     gv_exit_loop := false;
     while not gv_exit_loop loop
       begin
         writemultireaddebuglog('f_checkalreadyinscannedforunattended Step 1 Find by Primary ID');
         merge into MULTIREADSCANBATCHCONTENTS M
         using (select M1.IDCODE, U.UNIQUEITEM_ID
                  from MULTIREADSCANBATCHCONTENTS M1, UNIQUEITEM U
                 where M1.IDCODE = U.PRIMARYID
                   and M1.MULTIREADSCANBATCH_ID = fp_multireadscanbatch_id
                   and M1.SUBBATCHNUMBER = fp_subbatchnumber
                   and U.STAY_ID = (select s.stay_id from stay s where s.staytype =  1 and s.staynr = 30)
                   and M1.MULTIREADEXCEPTION_ID is null) MERGE_SUBQUERY
         on (M.MULTIREADSCANBATCH_ID = fp_multireadscanbatch_id and M.SUBBATCHNUMBER = fp_subbatchnumber and M.IDCODE = MERGE_SUBQUERY.IDCODE)
         when matched then
           update set M.MULTIREADEXCEPTION_ID = 13,
                      M.UNIQUEITEM_ID = MERGE_SUBQUERY.UNIQUEITEM_ID;
         commit;
         gv_exit_loop := true;
       exception
         when NO_DATA_FOUND then
            gv_exit_loop := true;
         when DUPLICATES_DETECTED then
           mark_duplicates(1);
           gv_exit_loop := false;
         when others then
           begin
             gv_last_error_number  := sqlcode;
             gv_last_error_message := sqlerrm;
             rollback;
             writemultireaderrorlog;
             gv_exit_loop := true;
             return GC_RESULT_ORA_ERROR;
           end;
       end;
     end loop;
 begin
      select 'Y'
        into gv_secondary_id_range_exists
        from UNIQUEIDCONFIGURATION U, MULTIREADSCANBATCH M
       where U.BUSINESSUNIT_ID = M.BUSINESSUNIT_ID
         and U.PACKAGETYPE = 1 -- products
         and U.TYPE = 2 -- chip
         and U.PRIMARYID = 'N'
         and M.MULTIREADSCANBATCH_ID = fp_multireadscanbatch_id
         and rownum < 2;
    exception
      when no_data_found then
        gv_secondary_id_range_exists := 'N';
    end;

     if gv_secondary_id_range_exists = 'Y' then
       gv_exit_loop := false;
       while not gv_exit_loop loop
         begin
           writemultireaddebuglog('f_checkalreadyinscannedforunattended Step 2 Find by Secondary ID');
           merge into MULTIREADSCANBATCHCONTENTS M
           using (select M1.IDCODE, U.UNIQUEITEM_ID
                    from MULTIREADSCANBATCHCONTENTS M1,
                         UNIQUEITEM                 U,
                         SECONDARYUNIQUEITEM        SU
                   where M1.IDCODE = SU.SECONDARYID
                     and U.UNIQUEITEM_ID = SU.UNIQUEITEM_ID
                     and M1.MULTIREADSCANBATCH_ID = fp_multireadscanbatch_id
                     and M1.SUBBATCHNUMBER = fp_subbatchnumber
                     and U.STAY_ID = (select S.STAY_ID from STAY S where S.STAYTYPE =  1 and S.STAYNR = 30)
                     and M1.MULTIREADEXCEPTION_ID is null) MERGE_SUBQUERY
           on (M.MULTIREADSCANBATCH_ID = fp_multireadscanbatch_id and M.SUBBATCHNUMBER = fp_subbatchnumber and M.IDCODE = MERGE_SUBQUERY.IDCODE)
           when matched then
             update set M.MULTIREADEXCEPTION_ID = 13,
                        M.UNIQUEITEM_ID = MERGE_SUBQUERY.UNIQUEITEM_ID;
           commit;
           gv_exit_loop := true;
         exception
           when NO_DATA_FOUND then
             gv_exit_loop := true;
           when DUPLICATES_DETECTED then
             mark_duplicates(2); -- secondary range
             gv_exit_loop := false;
           when others then
             begin
               gv_last_error_number  := sqlcode;
               gv_last_error_message := sqlerrm;
               rollback;
               writemultireaderrorlog;
               gv_exit_loop := true;
               return GC_RESULT_ORA_ERROR;
             end;
         end;
       end loop;
     end if;

     return 0;
   end f_checkalreadyinscannedforunattended;


   begin   -- f_domultireadunattended
      gv_multireadscanbatch_id := fp_multireadscanbatch_id;
      gv_subbatchnumber := fp_subbatchnumber;
      gv_result := 0;
      gv_main_code_block := 'f_domultireadunattended';
      gv_code_block := 'Determine Transactiontype';

      -- determine transactiontype
      begin
      lv_transactiontype := 0;
      select nvl(w.unattendedscantransacttype_id,0),
             nvl(unattendedkntscantranstype_id,0),
             w.code,
             b.plant_id,
             mb.systemuser_id
        into lv_transactiontype,
             lv_knt_transactiontype,
             lv_workstation_code,
             gv_plant_id,
             gv_systemuser_id
        from multireadscanbatch mb,
             workstation w,
             businessunit b
       where w.workstation_id = mb.workstation_id
         and mb.multireadscanbatch_id = fp_multireadscanbatch_id
         and b.businessunit_id = mb.businessunit_id;
      exception
        when no_data_found then
         begin
           lv_transactiontype := -1;
           lv_knt_transactiontype := -1;
           lv_workstation_code := '<unknown>';
           gv_plant_id := null;
           gv_systemuser_id := 1;
         end;
      end;

      if lv_transactiontype = 39 then
        gv_result := f_checkalreadyinscannedforunattended (fp_multireadscanbatch_id, fp_subbatchnumber);
        if gv_result <> 0 then
          return gv_result;
        end if;
        lv_transactiontype := 1;
      end if;

      if lv_transactiontype <> 0 and lv_transactiontype <> 1 and lv_transactiontype <> 4 and lv_transactiontype <> 19 and lv_transactiontype <> 73 then
        gv_last_error_number := -99;
        gv_last_error_message := 'No valid transaction type defined for workstation ' || lv_workstation_code || ' type ' || lv_transactiontype;
        writemultireaderrorlog;
      end if;

      if lv_knt_transactiontype <> 0 and lv_knt_transactiontype <> 511 and lv_knt_transactiontype <> 520 then
        gv_last_error_number := -99;
        gv_last_error_message := 'No valid container transaction type defined for workstation ' || lv_workstation_code || ' type ' || lv_transactiontype;
        writemultireaderrorlog;
      end if;

      if lv_transactiontype = 1
         then gv_prod_inscan_YN := 'Y';
         else gv_prod_inscan_YN := 'N';
      end if;
      if lv_knt_transactiontype = 511
         then gv_knt_inscan_YN := 'Y';
         else gv_knt_inscan_YN := 'N';
      end if;

      if lv_transactiontype = 1 or lv_knt_transactiontype = 511 -- inscan
        then gv_result := f_domultireadinscanbatch(fp_multireadscanbatch_id,fp_subbatchnumber,3, trunc(sysdate), null);
      end if;

      if lv_transactiontype = 4 -- rewash
        then gv_result := f_domultireadrewashscanbatch(fp_multireadscanbatch_id,fp_subbatchnumber,3, null);
      end if;

      if lv_transactiontype = 19 -- laundry process scan
        then gv_result := f_domultireadlaundbufscanbatch(fp_multireadscanbatch_id,fp_subbatchnumber,3);
      end if;

      if lv_transactiontype = 73 -- soiled in garment dispenser
        then gv_result := f_domultireadsoilingdscanbatch(fp_multireadscanbatch_id,fp_subbatchnumber,3);
      end if;

      if lv_knt_transactiontype = 520 -- disinfection
        then gv_result := f_domultireaddisinfecscanbatch(fp_multireadscanbatch_id,fp_subbatchnumber,3);
      end if;

      return(gv_result);
  end f_domultireadunattended;

  function f_domultireadcleanroombatch(fp_multireadscanbatch_id in number,
                                       fp_subbatchnumber        in number,
                                       fp_cleanroombatch_id     in number)
  return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error

     function f_validatecleanroombatch return number is
      -- output result:
      -- 0 = okay
      -- 3 = ORA message
     --------------------------
     begin
        gv_main_code_block := 'Validate Cleanroom Batch';

        -- step 1A
        -- Try to find ID Codes in database by PRIMARY ID
        -- No BU filter is needed because chip numbers are supposed to be overall unique.
        gv_exit_loop := false;
        WHILE not gv_exit_loop LOOP
        begin
        writemultireaddebuglog('Step 1A Find by Primary ID');
        MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/
        INTO multireadscanbatchcontents m
        USING (SELECT u.primaryid idcode,
                      u.uniqueitem_id,
                      u.businessunit_id,
                      u.relatedcustomer_id,
                      u.product_id,
                      u.sizedefinition_id,
                      u.finishingmethod_id,
                      coalesce(we.distributionpoint_id, u.distributionpoint_id,u.lastdistributionpoint_link_id) distributionpoint_id,
                      u.poolitem,
                      u.status_id,
                      u.stay_id,
                      u.lastscandate,
                      u.unrelatedloan_id,
                      u.uhfbundle_id,
                      m1.scantimestamp,
                      u.lastinscandate,
                      u.lastoutscandate,
                      nvl(m1.uniqueitembatchnumber, u.batchnumber) uniqueitembatchnumber,
                      ( select max(crb.cleanroombatchnumber)
                      from cleanroombatch crb
                      join cleanroombatchcustomer crbc on crbc.cleanroombatch_id = crb.cleanroombatch_id
                      join cleanroombatchcountcontent cbcount
                          on cbcount.cleanroombatchcustomer_id = crbc.cleanroombatchcustomer_id
                      where crb.cleanroombatch_id = fp_cleanroombatch_id
                      and   cbcount.product_link_id = u.product_id
                      and   cbcount.finishingmethod_id = u.finishingmethod_id
                      and ((we.distributionpoint_id = crbc.distributionpoint_link_id)
                        or exists
                       (select dp.distributionpoint_id
                        from customer c
                        join department t on t.customer_id = c.customer_id
                        join distributionpoint dp on dp.department_id = t.department_id
                        where c.othercustomer_id = u.relatedcustomer_id
                        and   c.customerrelated > 2
                        and  dp.distributionpoint_id = crbc.distributionpoint_link_id)
                       )) cleanroombatchnumber,
                      un.weareremployment_id,
                      w.customer_id,
                      case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select gd.deliverypoint_id
                                    from garmentdispenser gd
                                   where gd.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id
                 FROM multireadscanbatchcontents m1
                 join uniqueitem u on u.primaryid =  m1.idcode
                 left outer join (uniqueitemnonpool un
                 join weareremployment we on we.weareremployment_id = un.weareremployment_id
                 join wearer w on w.wearer_id = we.wearer_id)
                 on un.uniqueitem_id = u.uniqueitem_id
                WHERE m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.multireadexception_id is null
              ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
                 m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
                 m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
                 m.product_id            = MERGE_SUBQUERY.product_id,
                 m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
                 m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
                 m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                 m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
                 m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
                 m.customer_id           = MERGE_SUBQUERY.customer_id,
                 m.stay_id               = MERGE_SUBQUERY.stay_id,
                 m.status_id             = MERGE_SUBQUERY.status_id,
                 m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
                 m.unrelatedloan_id      = MERGE_SUBQUERY.Unrelatedloan_id,
                 m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
                 m.multireadexception_id = case when fp_cleanroombatch_id is not null then
                                               case
                                                 when MERGE_SUBQUERY.status_id not in (gc_status_id_assigned,gc_status_id_in_circ)
                                                    then 2 -- not in circ
                                                 when MERGE_SUBQUERY.cleanroombatchnumber is null
                                                    then 29
                                                 else null  --ok
                                               end
                                           else null --ok
                                           end,
                 m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
                 m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
                 m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
                 m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
                 m.lastscandate          = MERGE_SUBQUERY.lastscandate,
                 m.uniqueitembatchnumber = MERGE_SUBQUERY.uniqueitembatchnumber;
        gv_items_found := SQL%ROWCOUNT;
        commit;
        gv_exit_loop := true;
        exception
          when no_data_found then
            gv_items_found := 0;
            gv_exit_loop := true;
          when duplicates_detected then
            mark_duplicates(1); -- primary range
            gv_exit_loop := false;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            gv_exit_loop := true;
            return gc_result_ora_error;
          end;
        end;
        END LOOP;

        -- step 1B
        -- Try to find ID Codes in database by SECONDARY ID
        -- No BU filter is needed because chip numbers are supposed to be overall unique.
        if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
        gv_exit_loop := false;
        WHILE not gv_exit_loop LOOP
        begin
        writemultireaddebuglog('Step 1B Find by Secondary ID');
        MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/
        INTO multireadscanbatchcontents m
        USING (SELECT su.secondaryid idcode,
                      u.uniqueitem_id,
                      u.businessunit_id,
                      u.relatedcustomer_id,
                      u.product_id,
                      u.sizedefinition_id,
                      u.finishingmethod_id,
                      coalesce(we.distributionpoint_id, u.distributionpoint_id,u.lastdistributionpoint_link_id) distributionpoint_id,
                      u.poolitem,
                      u.status_id,
                      u.stay_id,
                      u.lastscandate,
                      u.unrelatedloan_id,
                      u.uhfbundle_id,
                      m1.scantimestamp,
                      u.lastinscandate,
                      u.lastoutscandate,
                      u.batchnumber,
                    ( select max(crb.cleanroombatchnumber)
                      from cleanroombatch crb
                      join cleanroombatchcustomer crbc on crbc.cleanroombatch_id = crb.cleanroombatch_id
                      join cleanroombatchcountcontent cbcount
                          on cbcount.cleanroombatchcustomer_id = crbc.cleanroombatchcustomer_id
                      where crb.cleanroombatch_id = fp_cleanroombatch_id
                      and   cbcount.product_link_id = u.product_id
                      and   cbcount.finishingmethod_id = u.finishingmethod_id
                      and ((we.distributionpoint_id = crbc.distributionpoint_link_id)
                        or exists
                       (select dp.distributionpoint_id
                        from customer c
                        join department t on t.customer_id = c.customer_id
                        join distributionpoint dp on dp.department_id = t.department_id
                        where c.othercustomer_id = u.relatedcustomer_id
                        and   c.customerrelated > 2
                        and  dp.distributionpoint_id = crbc.distributionpoint_link_id)
                       )) cleanroombatchnumber,
                      un.weareremployment_id,
                      w.customer_id,
                      case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select gd.deliverypoint_id
                                    from garmentdispenser gd
                                   where gd.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id
                 FROM multireadscanbatchcontents m1
                 join secondaryuniqueitem su on su.secondaryid = m1.idcode
                 join uniqueitem u on u.uniqueitem_id = su.uniqueitem_id
                 left outer join (uniqueitemnonpool un
                 join weareremployment we on we.weareremployment_id = un.weareremployment_id
                 join wearer w on w.wearer_id = we.wearer_id) on un.uniqueitem_id = u.uniqueitem_id
         WHERE  m1.multireadscanbatch_id = gv_multireadscanbatch_id
                  and m1.subbatchnumber = gv_subbatchnumber
                  and m1.uniqueitem_id is null -- only for those items that are not yet found in previous step
                  and m1.multireadexception_id is null
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m.uniqueitem_id         = MERGE_SUBQUERY.uniqueitem_id,
                 m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
                 m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
                 m.product_id            = MERGE_SUBQUERY.product_id,
                 m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_id,
                 m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
                 m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                 m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
                 m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
                 m.customer_id           = MERGE_SUBQUERY.customer_id,
                 m.stay_id               = MERGE_SUBQUERY.stay_id,
                 m.status_id             = MERGE_SUBQUERY.status_id,
                 m.lastscantimestamp     = MERGE_SUBQUERY.lastscandate,
                 m.unrelatedloan_id      = MERGE_SUBQUERY.unrelatedloan_id,
                 m.uhfbundle_id          = MERGE_SUBQUERY.uhfbundle_id,
                 m.multireadexception_id = case when fp_cleanroombatch_id is not null then
                                               case
                                                 when MERGE_SUBQUERY.status_id not in (gc_status_id_assigned,gc_status_id_in_circ)
                                                    then 2 -- not in circ
                                                 when MERGE_SUBQUERY.cleanroombatchnumber is null
                                                    then 29
                                                 else null  --ok
                                               end
                                           else null --ok
                                           end,
                 m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
                 m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
                 m.lastinscandate        = MERGE_SUBQUERY.lastinscandate,
                 m.lastoutscandate       = MERGE_SUBQUERY.lastoutscandate,
                 m.lastscandate          = MERGE_SUBQUERY.lastscandate,
                 m.uniqueitembatchnumber = MERGE_SUBQUERY.batchnumber;
        gv_items_found := gv_items_found + SQL%ROWCOUNT;
        commit;
        gv_exit_loop := true;
        exception
          when no_data_found then
            gv_exit_loop := true;
          when duplicates_detected then
            mark_duplicates(2); -- secondary range
            gv_exit_loop := false;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            gv_exit_loop := true;
            return gc_result_ora_error;
          end;
        end;
        END LOOP;
        end if;

        -- step 2A
        -- Try to find ID Codes in table for ragged items search on PRIMARY ID
        -- No BU filter is needed because chip numbers are supposed to be overall unique.
        if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2A Find Rag by Primary ID');
        MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT r.primaryid idcode,
                      r.raggeditem_id,
                      r.businessunit_id,
                      r.relatedcustomerlink_id relatedcustomer_id,
                      r.product_link_id,
                      r.sizedefinition_link_id,
                      r.finishingmethod_id,
                      coalesce(we.distributionpoint_id, r.distributionpoint_link_id, r.lastdistributionpoint_link_id) distributionpoint_id,
                      r.poolitem,
                      r.ragtimestamp,
                      r.secondaryid,
                      case
                       when rr.allowreissue ='Y' and r.poolitem = 1 and r.weareremployment_link_id is null then
                        'Y'
                       when rr.allowreissue ='Y' and r.poolitem = 2 and r.weareremployment_link_id is not null then
                       (select 'Y'
                         from weareremployment we,
                              wearer w,
                              customer c,
                              wearerinventory wi
                        where we.weareremployment_id = r.weareremployment_link_id
                          and w.wearer_id = we.wearer_id
                          and c.customer_id = w.customer_id
                          and wi.weareremployment_id = r.weareremployment_link_id
                          and wi.product_id = r.product_link_id
                          and wi.sizedefinition_id = r.sizedefinition_link_id
                          and c.dateinactive >= trunc(sysdate)
                          and c.active = 'Y'
                          and w.dateinactive >= trunc(sysdate)
                          and wi.dateinactive >= trunc(sysdate))
                       else
                        'N'
                       end possible_to_reissue,
                    ( select max(crb.cleanroombatchnumber)
                      from cleanroombatch crb
                      join cleanroombatchcustomer crbc on crbc.cleanroombatch_id = crb.cleanroombatch_id
                      join cleanroombatchcountcontent cbcount
                          on cbcount.cleanroombatchcustomer_id = crbc.cleanroombatchcustomer_id
                      where crb.cleanroombatch_id = fp_cleanroombatch_id
                      and   cbcount.product_link_id = r.product_link_id
                      and   cbcount.finishingmethod_id = r.finishingmethod_id
                      and ((we.distributionpoint_id = crbc.distributionpoint_link_id)
                        or exists
                       (select dp.distributionpoint_id
                        from customer c
                        join department t on t.customer_id = c.customer_id
                        join distributionpoint dp on dp.department_id = t.department_id
                        where c.othercustomer_id = r.relatedcustomerlink_id
                        and   c.customerrelated > 2
                        and  dp.distributionpoint_id = crbc.distributionpoint_link_id)
                       )) cleanroombatchnumber,
                      we.weareremployment_id,
                      w.customer_id,
                      case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select gd.deliverypoint_id
                                    from garmentdispenser gd
                                   where gd.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id
                 FROM (SELECT ri.primaryid,
                              max(ri.ragtimestamp) ragtimestamp -- most recent ragged item
                         FROM multireadscanbatchcontents m1, raggeditem ri, ragreason rr
                        WHERE m1.idcode = ri.primaryid
                          and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                          and m1.subbatchnumber = gv_subbatchnumber
                          and m1.uniqueitem_id is null -- only for those items that are not yet found in previous steps
                        group by ri.primaryid) X
                      join raggeditem r on (r.primaryid = x.primaryid and r.ragtimestamp = x.ragtimestamp)
                      join ragreason rr on rr.ragreason_id = r.ragreason_id
                      left outer join (weareremployment we
                                       join wearer w on w.wearer_id = we.wearer_id )
                      on we.weareremployment_id = r.weareremployment_link_id
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m.uniqueitem_id         = MERGE_SUBQUERY.raggeditem_id,
                 m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
                 m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
                 m.product_id            = MERGE_SUBQUERY.product_link_id,
                 m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_link_id,
                 m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
                 m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                 m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
                 m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
                 m.customer_id           = MERGE_SUBQUERY.customer_id,
                 m.status_id             = gc_status_id_ragged,
                 m.stay_id               = gc_stay_id_at_customer,
                 m.lastscantimestamp     = MERGE_SUBQUERY.ragtimestamp,
                 m.multireadexception_id = case when gc_ss_reissueraggeditem='Y'
                                                 and MERGE_SUBQUERY.possible_to_reissue='Y'
                                            then
                                              case when (MERGE_SUBQUERY.cleanroombatchnumber is null
                                                     and fp_cleanroombatch_id is not null)
                                              then
                                                29
                                              else
                                                null
                                              end
                                            else 4 -- ragged
                                           end,
                 m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
                 m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N'),
                 m.secondaryid           = MERGE_SUBQUERY.secondaryid;
        gv_items_found := gv_items_found + SQL%ROWCOUNT;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
        end if;

        -- step 2B
        -- Try to find ID Codes in table for ragged items search on SECONDARY ID
        -- No BU filter is needed because chip numbers are supposed to be overall unique.
        if gv_secondary_id_range_exists='Y' and (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2B Find Rag by Secondary ID');
        MERGE /*+index(m XIE1MULTIREADSCANCONTENTBATCH)*/ INTO multireadscanbatchcontents m
        USING (SELECT r.secondaryid idcode,
                      r.raggeditem_id,
                      r.businessunit_id,
                      r.relatedcustomerlink_id relatedcustomer_id,
                      r.product_link_id,
                      r.sizedefinition_link_id,
                      r.finishingmethod_id,
                      coalesce(we.distributionpoint_id, r.distributionpoint_link_id, r.lastdistributionpoint_link_id) distributionpoint_id,
                      r.poolitem,
                      r.ragtimestamp,
                      case
                       when rr.allowreissue ='Y' and r.poolitem = 1 and r.weareremployment_link_id is null then
                        'Y'
                       when rr.allowreissue ='Y' and r.poolitem = 2 and r.weareremployment_link_id is not null then
                       (select 'Y'
                         from weareremployment we,
                              wearer w,
                              customer c,
                              wearerinventory wi
                        where we.weareremployment_id = r.weareremployment_link_id
                          and w.wearer_id = we.wearer_id
                          and c.customer_id = w.customer_id
                          and wi.weareremployment_id = r.weareremployment_link_id
                          and wi.product_id = r.product_link_id
                          and wi.sizedefinition_id = r.sizedefinition_link_id
                          and c.dateinactive >= trunc(sysdate)
                          and c.active = 'Y'
                          and w.dateinactive >= trunc(sysdate)
                          and wi.dateinactive >= trunc(sysdate))
                       else
                        'N'
                       end possible_to_reissue,
                    ( select max(crb.cleanroombatchnumber)
                      from cleanroombatch crb
                      join cleanroombatchcustomer crbc on crbc.cleanroombatch_id = crb.cleanroombatch_id
                      join cleanroombatchcountcontent cbcount
                          on cbcount.cleanroombatchcustomer_id = crbc.cleanroombatchcustomer_id
                      where crb.cleanroombatch_id = fp_cleanroombatch_id
                      and   cbcount.product_link_id = r.product_link_id
                      and   cbcount.finishingmethod_id = r.finishingmethod_id
                      and ((we.distributionpoint_id = crbc.distributionpoint_link_id)
                        or exists
                       (select dp.distributionpoint_id
                        from customer c
                        join department t on t.customer_id = c.customer_id
                        join distributionpoint dp on dp.department_id = t.department_id
                        where c.othercustomer_id = r.relatedcustomerlink_id
                        and   c.customerrelated > 2
                        and  dp.distributionpoint_id = crbc.distributionpoint_link_id)
                       )) cleanroombatchnumber,
                      we.weareremployment_id,
                      w.customer_id,
                      case when we.deliverypoint_id is not null
                      then we.deliverypoint_id
                      else
                          case when we.locker_id is not null
                            then (select l.deliverypoint_id
                                    from locker l
                                   where l.locker_id = we.locker_id)
                            else (select gd.deliverypoint_id
                                    from garmentdispenser gd
                                   where gd.garmentdispenser_id = we.garmentdispenser_id)
                          end
                    end deliverypoint_id
                 FROM (SELECT ri.secondaryid,
                              max(ri.ragtimestamp) ragtimestamp -- most recent ragged item
                         FROM multireadscanbatchcontents m1, raggeditem ri, ragreason rr
                        WHERE m1.idcode = ri.secondaryid
                          and m1.multireadscanbatch_id = gv_multireadscanbatch_id
                          and m1.subbatchnumber = gv_subbatchnumber
                          and m1.uniqueitem_id is null -- only for those items that are not yet found in previous steps
                        group by ri.secondaryid) X
                      join raggeditem r on (r.secondaryid = x.secondaryid and r.ragtimestamp = x.ragtimestamp)
                      join ragreason rr on rr.ragreason_id = r.ragreason_id
                      left outer join (weareremployment we
                                       join wearer w on w.wearer_id = we.wearer_id )
                      on we.weareremployment_id = r.weareremployment_link_id
               ) MERGE_SUBQUERY
        ON (m.multireadscanbatch_id = gv_multireadscanbatch_id
        AND m.subbatchnumber = gv_subbatchnumber
        AND m.idcode = MERGE_SUBQUERY.idcode)
        WHEN MATCHED THEN
          UPDATE
             SET m.uniqueitem_id         = MERGE_SUBQUERY.raggeditem_id,
                 m.businessunit_id       = MERGE_SUBQUERY.businessunit_id,
                 m.relatedcustomer_id    = MERGE_SUBQUERY.relatedcustomer_id,
                 m.product_id            = MERGE_SUBQUERY.product_link_id,
                 m.sizedefinition_id     = MERGE_SUBQUERY.sizedefinition_link_id,
                 m.finishingmethod_id    = MERGE_SUBQUERY.finishingmethod_id,
                 m.distributionpoint_id  = MERGE_SUBQUERY.distributionpoint_id,
                 m.weareremployment_id   = MERGE_SUBQUERY.weareremployment_id,
                 m.deliverypoint_id      = MERGE_SUBQUERY.deliverypoint_id,
                 m.customer_id           = MERGE_SUBQUERY.customer_id,
                 m.status_id             = gc_status_id_ragged, --ragged
                 m.stay_id               = gc_stay_id_at_customer,
                 m.lastscantimestamp     = MERGE_SUBQUERY.ragtimestamp,
                 m.multireadexception_id = case when gc_ss_reissueraggeditem='Y'
                                                 and MERGE_SUBQUERY.possible_to_reissue='Y'
                                           then
                                              case when (MERGE_SUBQUERY.cleanroombatchnumber is null
                                                     and fp_cleanroombatch_id is not null)
                                              then
                                                29
                                              else
                                                null
                                              end
                                            else 4 -- ragged
                                           end,
                 m.poolitemyn            = decode(MERGE_SUBQUERY.poolitem,2,'N','Y'),
                 m.orpackitemyn          = decode(MERGE_SUBQUERY.poolitem,3,'Y','N');
        gv_items_found := gv_items_found + SQL%ROWCOUNT;
        commit;
        exception
          when no_data_found then
            null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;
        end if;

        -- step 3
        -- Mark all other items as not found in database
        if (gv_items_in_batch > gv_items_found) then
          begin
          writemultireaddebuglog('Step 3 Mark those not found');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 1 -- not found in database
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.uniqueitem_id is null
             and m.multireadexception_id is null;
          commit;
          exception
            when no_data_found then
              null;
            when others then
             begin
              gv_last_error_number  := SQLCODE;
              gv_last_error_message := SQLERRM;
              ROLLBACK;
              writemultireaderrorlog;
              return gc_result_ora_error;
            end;
          end;
        end if;

        -- step 4
        -- Mark all items that are scanned meanwhile with rejection reason
        begin
          writemultireaddebuglog('Step 4 Reject items scanned meanwhile');
          update multireadscanbatchcontents m
             set m.multireadexception_id = 15
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and m.subbatchnumber = gv_subbatchnumber
             and m.multireadexception_id is null
             and m.lastscantimestamp > m.scantimestamp;
          commit;
        exception
          when no_data_found then
           null;
          when others then
           begin
            gv_last_error_number  := SQLCODE;
            gv_last_error_message := SQLERRM;
            ROLLBACK;
            writemultireaderrorlog;
            return gc_result_ora_error;
          end;
        end;

        return 0;
     end f_validatecleanroombatch;

    begin
      --f_domultireadcleanroombatch
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);
      -- do validation in case of action=validate or action=both
      if gv_result = 0 and gv_items_in_batch <> 0 then
        begin
          gv_result := f_validatecleanroombatch;
          Create_reject_scans(100); -- 100 = transactiontype Flag Scan
        end;
      end if;
      commit; -- overall commit on updates and inserts.
      --return result
      return(gv_result);
    end f_domultireadcleanroombatch;

  -----------------------------------------------------------------------------------------
  function f_domultireadinscanrejectbatch(fp_multireadscanbatch_id number,
                                          fp_subbatchnumber        number,
                                          fp_action                number,
                                          fp_pickupdate            date default trunc(sysdate))
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
    lv_nr_of_items_not_inscanned number;

    begin   -- f_domultireadinscanbatch
      gv_result := 0;
      gv_pickupdate := fp_pickupdate;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      -- first same validations as inscan
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validateinscanbatch('R');
      end if;

      if gv_result = 0 and (fp_action = 2 or fp_action=3) then
        begin
          select count(*)
            into lv_nr_of_items_not_inscanned
            from multireadscanbatchcontents m
           where m.multireadscanbatch_id = gv_multireadscanbatch_id
             and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
             and m.multireadexception_id is null
             and m.stay_id not in (select s.stay_id from stay s where s.staytype=1 and (s.staynr between 30 and 39 or s.staynr = 44)); -- laundry stays
        exception
          when no_data_found then
            lv_nr_of_items_not_inscanned := 0;
        end;

        if lv_nr_of_items_not_inscanned > 0 then
            if gv_result = 0 then
              -- set all items that are already inscanned to dummy exception to prevent inscanning them again in next step
              begin
                UPDATE multireadscanbatchcontents m
                   set m.multireadexception_id = -1 -- dummy value
                 where m.multireadscanbatch_id = gv_multireadscanbatch_id
                   and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                   and m.multireadexception_id is null
                   and m.stay_id in (select s.stay_id from stay s where s.staytype=1 and (s.staynr between 30 and 39 or s.staynr = 44)); -- laundry stays
                commit;
              exception
                when no_data_found then
                  null;
              end;
            end if;

            -- do processing in case of action=process or action=both
            if gv_result = 0 then
              gv_result := f_processinscanbatch('N', 1, null);
              if gv_result = gc_result_duplicate_scan_err then
                 --try again
                 gv_result := 0;
                 gv_result := f_processinscanbatch('N', 1, null);
              end if;
            end if;

            if gv_result = 0 then
              -- reset exception for  all items that were already inscanned
              begin
                UPDATE multireadscanbatchcontents m
                   set m.multireadexception_id = null
                 where m.multireadscanbatch_id = gv_multireadscanbatch_id
                   and (m.subbatchnumber = gv_subbatchnumber or gv_subbatchnumber = 0)
                   and m.multireadexception_id  = -1;
                commit;
              exception
                when no_data_found then
                  null;
              end;
            end if;
        end if;  -- if lv_nr_of_items_not_inscanned > 0

        if gv_result = 0 then
          gv_result := f_processinscanrejectbatch;
        end if;
      end if;  -- gv_result = 0 and (fp_action = 2 or fp_action=3)

      return(gv_result);
  end f_domultireadinscanrejectbatch;

  function f_domultireadcleanreturnbatch(fp_multireadscanbatch_id in number,
                                             fp_subbatchnumber        in number,
                                             fp_action                in number)
    return number is
    -- input parameter action  1=validate only 2=process only 3=validate and process
    -- output result:
    -- 0 = okay
    -- 1 = batch not found
    -- 2 = empty batch
    -- 3 = ORA error
  begin
      gv_result := 0;
      initialize_batch(fp_multireadscanbatch_id,fp_subbatchnumber);

      -- do validation in case of action=validate or action=both
      if gv_result = 0 and (fp_action = 1 or fp_action=3)
        then gv_result := f_validatecleanreturnbatch;
      end if;
      -- do processing in case of action=process or action=both
      if gv_result = 0 and (fp_action = 2 or fp_action=3)
        then gv_result := f_processcleanreturnbatch;
        if gv_result = gc_result_duplicate_scan_err then
           --try again
           gv_result := 0;
           gv_result := f_processcleanreturnbatch;
        end if;
      end if;
      return(gv_result);
  end f_domultireadcleanreturnbatch;

function f_dostackcheck_secondws(fp_multireadscanbatch_id number,
                                 fp_subbatchnumber        number,
                                 fp_stacksize             number,
                                 fp_findpack_yn           varchar2)
  return number is
  -- output result:
  -- 0 = okay
  -- 1 = batch not found
  -- 2 = empty batch
  -- 3 = ora error
  -- 100 = already scanned at first scan station
  lv_bundlecount number;
begin

   with batchcontent as
     (select mrsbc.multireadscanbatch_id,
             mrsbc.idcode,
            (select ws.code from workstation ws where ws.workstation_id = mb.workstation_id) wsCode,
             mb.businessunit_id
        from multireadscanbatchcontents mrsbc
        join multireadscanbatch mb
          on mrsbc.multireadscanbatch_id = mb.multireadscanbatch_id
       where mb.multireadscanbatch_id = fp_multireadscanbatch_id)
   select count(distinct ub.uhfbundle_id)
          into lv_bundlecount
   from batchcontent, uniqueitem ui
   left outer join secondaryuniqueitem sui
    on sui.uniqueitem_id = ui.uniqueitem_id, uhfbundle ub
    where ub.uhfbundle_id = ui.uhfbundle_id
   and ( case when ui.primaryid = batchcontent.idcode then 1
         when sui.secondaryid = batchcontent.idcode then 2
          else 0
          end) > 0
   and ub.businessunit_id = batchcontent.businessunit_id
   and ub.workstation <> batchcontent.wsCode
   and trunc(ub.creationdate) = trunc(sysdate)
   and ub.deliverystatus <> 2;

    if lv_bundlecount = 1 then
      return 100;
      else
        return f_domultireadstackcheck(fp_multireadscanbatch_id,
                                       fp_subbatchnumber,
                                       fp_stacksize,
                                      fp_findpack_yn);
    end if;
  exception
    when others then
      begin
        gv_result := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        writemultireaderrorlog;
      end;
end f_dostackcheck_secondws;


function f_getprocessbusinessunit(distributionpointid number, productid number)
  return number is
       lv_processbusinessunit_id businessunit.businessunit_id%type;
   begin
     if(gv_internalcalcactive = 'Y') then
       begin
         select ca.processbusinessunit_id
         into lv_processbusinessunit_id
         from customeractivities ca join department dt on ca.customer_id = dt.customer_id
            join distributionpoint dp on dt.department_id = dp.department_id
            join productgroup pg on ca.activity_id = pg.activity_id
            join product p on p.productgroup_id = pg.productgroup_id
         where dp.distributionpoint_id = distributionpointid
         and p.product_id = productid
         and ((ca.allowallinternalbu = 'N' and ca.internalprocessingbu_id = gv_businessunit_id)
              or (ca.allowallinternalbu = 'Y' and
               gv_businessunit_id in (select ibua.internalprocessingbu_id
                         from internalbuactivities ibua
                        where ibua.businessunit_id = ca.processbusinessunit_id
                          and ibua.activity_id = ca.activity_id)));
       exception
         when no_data_found then
           lv_processbusinessunit_id := gv_businessunit_id;
       end;
      else
        lv_processbusinessunit_id := gv_businessunit_id;
     end if;
    return lv_processbusinessunit_id;
end f_getprocessbusinessunit;
---------------------------- f_outscanforvirtualbundle


function f_outscanforvirtualbundle( fp_packingnoteid  number,
                                    fp_businessunitid number,
                                    fp_systemuserid   number,
                                    fp_workstationid  number,
                                    fp_internalcalc   varchar2)
  return number is

  multireadScanbatchid MultiReadScanBatch.Multireadscanbatch_Id%type;
  function f_create_multireadscanbatch_virtual_bundle(fp_businessunitid in number,
                                                   fp_workstationid  in number,
                                                   fp_packingnoteid  in number,
                                                   fp_systemuserid   in number,
                                                   fp_internalcalc   in varchar2,
                                                   fp_multireadScanbatchid in number) return number is

begin
  begin
    writemultireaddebuglog('create_multiread_for_virtual_bundle for packingnoteid: ' ||
                           fp_packingnoteid);

    insert into MultiReadScanBatch
      (MULTIREADSCANBATCH_ID,
       BUSINESSUNIT_ID,
       WORKSTATION_ID,
       PACKINGNOTE_ID,
       SYSTEMUSER_ID,
       TIMESTAMP,
       STACKCHECKPRODUCT_ID,
       STACKCHECKSIZE_ID,
       STACKCHECKSTACKSIZE,
       STACKCHECKPACK,
       STACKCHECKPRODUCTIDENTIFIED,
       MIXEDPRODUCTSALLOWED,
       ITEMSPARTLYTAGGED,
       RELATEDCUSTOMER_ID,
       INTERNALCALCACTIVE)
    values
      (fp_multireadScanbatchid,
       fp_businessunitid,
       fp_workstationid,
       fp_packingnoteid,
       fp_systemuserid,
       systimestamp,
       null,
       null,
       0,
       'N',
       'N',
       'N',
       'N',
       null,
       fp_internalcalc);
       return 0;
  exception
    when others then
      begin
        gv_result             := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;

  end;
end f_create_multireadscanbatch_virtual_bundle;


function f_create_multireadscanbatchcontent_virtual_bundle(fp_packingnoteid  in number,
                                                   fp_systemuserid   in number,
                                                   fp_multireadScanbatchid in number) return number is

begin
  begin
    writemultireaddebuglog('create_multiread_for_virtual_bundle for multireadScanbatchid ' || fp_multireadScanbatchid ||' , packingnoteid: ' ||
                           fp_packingnoteid);


 delete from MULTIREADSCANBATCHCONTENTS MBSC
  where MBSC.IDCODEREAD in
        (select UI.PRIMARYID
           from UHFBUNDLE UB
           join UNIQUEITEM UI
             on UI.UHFBUNDLE_ID = UB.UHFBUNDLE_ID
           join PACKINGNOTE PN
             on PN.PACKINGNOTE_ID = UB.PACKINGNOTE_ID
          where PN.PACKINGNOTE_ID = fp_packingnoteid);

    insert into multireadscanbatchcontents
  (MULTIREADSCANBATCH_ID,
   SUBBATCHNUMBER,
   IDCODE,
   UNIQUEITEM_ID,
   MULTIREADEXCEPTION_ID,
   CUSTOMER_ID,
   PRODUCT_ID,
   SIZEDEFINITION_ID,
   POOLITEMYN,
   ORPACKITEMYN,
   STAY_ID,
   STATUS_ID,
   LASTSCANTIMESTAMP,
   FINISHINGMETHOD_ID,
   PLPC_ID,
   CUSTOMEROWNED,
   QUALITYGRADE_ID,
   LASTINROUTE_ID,
   UNRELATEDLOAN_ID,
   TYPEOFMERCHANDIZE,
   SECONDARYID,
   LASTISSUEDATE,
   SCAN_ID,
   WEAREREMPLOYMENT_ID,
   DISTRIBUTIONPOINT_ID,
   DELIVERYPOINT_ID,
   LASTINDATE,
   PLANNEDOUTDATE,
   PLANNEDOUTROUTE_ID,
   DELAYEDEVENEXCHANGE,
   DEEDELIVERYSCHEME_ID,
   PACKINGNOTELINE_ID,
   LASTINROUTESTOP_ID,
   RELATEDCUSTOMER_ID,
   PREV_PLPC_ID,
   PREV_DISTRIBUTIONPOINT_ID,
   PREV_FINISHINGMETHOD_ID,
   PACKINGSEQUENCE,
   SCANTIMESTAMP,
   SYSTEMUSER_ID,
   UHFBUNDLE_ID,
   LASTINSTOP_ID,
   LASTOUTSTOP_ID,
   PLANNEDOUTSTOP_ID,
   DELIVERYSCANTIMESTAMP,
   BUSINESSUNIT_ID,
   PRODUCTLISTPERDISTRIBPOINT_ID,
   LASTDELIVERYNOTENUMBER,
   PROCESSEDYN,
   PARTOFPACKYN,
   LASTINSCANDATE,
   LASTOUTSCANDATE,
   LASTSCANDATE,
   CHILDPACKINGNOTELINE_ID,
   VIRTUALYN,
   BUNDLEADDEDYN,
   PRODUCTIONPROCESSBUFFER_ID,
   UNIQUEITEMBATCHNUMBER,
   PRODUCTIONPROCESSSCAN_ID,
   CLEANROOMBATCHNUMBER,
   PACKINGNOTE_ID,
   TIMEFRAMEINITIAL,
   TIMEFRAMEFINAL,
   IDCODEREAD)

  SELECT distinct

   fp_multireadScanbatchid, --     MULTIREADSCANBATCH_ID,
   1, --     SUBBATCHNUMBER,
   ui.primaryid, --     IDCODE,
   ui.UNIQUEITEM_ID, --     UNIQUEITEM_ID,
   null, --     MULTIREADEXCEPTION_ID,
   DEP.CUSTOMER_ID,--     CUSTOMER_ID,
   ui.product_id, --     PRODUCT_ID,
   ui.sizedefinition_id, --     SIZEDEFINITION_ID,
   'Y', --     POOLITEMYN,
   'N', --     ORPACKITEMYN,
   1, --     STAY_ID,
   ui.status_id, --     STATUS_ID,
   systimestamp, --     LASTSCANTIMESTAMP,
   ui.finishingmethod_id, --     FINISHINGMETHOD_ID,
   null, --     PLPC_ID,
   'N', --     CUSTOMEROWNED,
   null, --     QUALITYGRADE_ID,
   null, --     LASTINROUTE_ID,
   null, --     UNRELATEDLOAN_ID,
   0, --     TYPEOFMERCHANDIZE,
   null, --     SECONDARYID,
   null, --     LASTISSUEDATE,
   null, --     SCAN_ID,
   null, --     WEAREREMPLOYMENT_ID,
   DiP.Distributionpoint_Id,--     DISTRIBUTIONPOINT_ID,
   null, --     DELIVERYPOINT_ID,
   null, --     LASTINDATE,
   null, --     PLANNEDOUTDATE,
   null, --     PLANNEDOUTROUTE_ID,
   null, --     DELAYEDEVENEXCHANGE,
   null, --     DEEDELIVERYSCHEME_ID,
   pnl.packingnoteline_id, --     PACKINGNOTELINE_ID,
   null, --     LASTINROUTESTOP_ID,
   null,--c.customer_id, --     RELATEDCUSTOMER_ID,
   null, --     PREV_PLPC_ID,
   null, --     PREV_DISTRIBUTIONPOINT_ID,
   null, --     PREV_FINISHINGMETHOD_ID,
   null, --     PACKINGSEQUENCE,
   systimestamp, --     SCANTIMESTAMP,
   fp_systemuserid, --     SYSTEMUSER_ID,
   ui.uhfbundle_id, --     UHFBUNDLE_ID,
   null, --     LASTINSTOP_ID,
   null, --     LASTOUTSTOP_ID,
   null, --     PLANNEDOUTSTOP_ID,
   null, --     DELIVERYSCANTIMESTAMP,
   pn.processbusinessunit_id, --     BUSINESSUNIT_ID,
   null, --     PRODUCTLISTPERDISTRIBPOINT_ID,
   null, --     LASTDELIVERYNOTENUMBER,
   'N', --     PROCESSEDYN,
   'N', --     PARTOFPACKYN,
   null, --     LASTINSCANDATE,
   null, --     LASTOUTSCANDATE,
   systimestamp, --     LASTSCANDATE,
   null, --     CHILDPACKINGNOTELINE_ID,
   null, --     VIRTUALYN,
   null, --     BUNDLEADDEDYN,
   null, --     PRODUCTIONPROCESSBUFFER_ID,
   null, --     UNIQUEITEMBATCHNUMBER,
   null, --     PRODUCTIONPROCESSSCAN_ID,
   null, --     CLEANROOMBATCHNUMBER,
   null, --     PACKINGNOTE_ID,
   0, --     TIMEFRAMEINITIAL,
   0, --     TIMEFRAMEFINAL,
   ui.primaryid --  IDCODEREAD

    from uhfbundle ub
    join uniqueitem ui
      on ui.uhfbundle_id = ub.uhfbundle_id
    join packingnote pn
      on pn.packingnote_id = ub.packingnote_id
    left outer join packingnoteline pnl on pnl.packingnote_id=pn.packingnote_id
      and pnl.product_id = ui.product_id
      and pnl.sizedefinition_id = ui.sizedefinition_id
      and pnl.finishingmethod_id=ui.finishingmethod_id,
      DISTRIBUTIONPOINT DiP,
   DEPARTMENT DEP, CUSTOMER C
   where pn.packingnote_id = fp_packingnoteid
     and pn.deliverypoint_id = dip.deliverypoint_id
     and PN.DISTRIBUTIONPOINT_ID = DiP.DISTRIBUTIONPOINT_ID
     AND DiP.DEPARTMENT_ID = DEP.DEPARTMENT_ID
     AND DEP.CUSTOMER_ID = C.CUSTOMER_ID;

     return 0;
  exception
    when others then
      begin
        gv_result             := gc_result_ora_error;
        gv_last_error_number  := SQLCODE;
        gv_last_error_message := SQLERRM;
        ROLLBACK;
        writemultireaderrorlog;
        return(gv_result);
      end;

  end;
end f_create_multireadscanbatchcontent_virtual_bundle;

begin
  select seq_MultiReadScanBatch.nextval
    into multireadScanbatchid
    from dual;
    --Step 1
    gv_result := f_create_multireadscanbatch_virtual_bundle( fp_businessunitid,
                                                             fp_workstationid,
                                                             fp_packingnoteid,
                                                             fp_systemuserid,
                                                             fp_internalcalc,
                                                             multireadScanbatchid);
    if gv_result = 0 then
    --Step 2
    gv_result := f_create_multireadscanbatchcontent_virtual_bundle( fp_packingnoteid,
                                                                    fp_systemuserid,
                                                                    multireadScanbatchid);


     commit;
      if gv_result = 0 then
      --Step 3
      gv_result := f_domultireadoutscanpoolbatch(multireadScanbatchid,
                                         1,
                                         3, --validate and process
                                         'N',--gv_ss_uhfoutscantrackingonly, --fp_trackonly
                                         null); --fp_exchangecart_id

      end if;
    end if;
    commit;
  return gv_result;
end f_outscanforvirtualbundle;
----------------------------
----------------------------
end pack_multiread;
/
create or replace PACKAGE PACK_PACKINGNOTE is

procedure CFbStoreOrCreate (
        FPnPACKINGNOTE_ID                         in out PACKINGNOTE.PACKINGNOTE_ID%type,
        FPnNOTENUMBER                             in out PACKINGNOTE.NOTENUMBER%type,
        FPdtPRODUCTIONDATE                        in out PACKINGNOTE.PRODUCTIONDATE%type,
        FPdtDELIVERYDATE                          in out PACKINGNOTE.DELIVERYDATE%type,
        FPsREMARK                                 in out PACKINGNOTE.REMARK%type,
        FPnSTATUS_ID                              in out PACKINGNOTE.STATUS_ID%type,
        FPnDISTRIBUTIONPOINT_ID                   in out PACKINGNOTE.DISTRIBUTIONPOINT_ID%type,
        FPnDELIVERYPOINT_ID                       in out PACKINGNOTE.DELIVERYPOINT_ID%type,
        FPnPROCESSBUSINESSUNIT_ID                 in out PACKINGNOTE.PROCESSBUSINESSUNIT_ID%type,
        FPnINVOICEBUSINESSUNIT_ID                 in out PACKINGNOTE.INVOICEBUSINESSUNIT_ID%type,
        FPnEMPLOYEE_ID                            in out PACKINGNOTE.EMPLOYEE_ID%type,
        FPnPLANTDEPARTMENT_ID                     in out PACKINGNOTE.PLANTDEPARTMENT_ID%type,
        FPnTRANSPORTARTICLE_ID                    in out PACKINGNOTE.TRANSPORTARTICLE_ID%type,
        FPsCLEANRETURN                            in out PACKINGNOTE.cleanreturn%type,
        FPnSEQUENCENUMBER                         in out PACKINGNOTE.sequencenumber%type,
        FPdtDEADLINE                              in out PACKINGNOTE.deadline%TYPE,
        FPnOccupancy                              in out PACKINGNOTE.occupancy%TYPE,
        FPnSYSTEMUSER_ID                          in out PACKINGNOTE.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out PACKINGNOTE.TIMESTAMP%type,
        FPnOrigin                                 in out PACKINGNOTE.ORIGIN%type,
        FPdtOriginalDelDate                       in out PACKINGNOTE.ORIGINALDELIVERYDATE%type);

end PACK_PACKINGNOTE;





/
create or replace PACKAGE BODY PACK_PACKINGNOTE is

procedure CFbStoreOrCreate (
        FPnPACKINGNOTE_ID                         in out PACKINGNOTE.PACKINGNOTE_ID%type,
        FPnNOTENUMBER                             in out PACKINGNOTE.NOTENUMBER%type,
        FPdtPRODUCTIONDATE                        in out PACKINGNOTE.PRODUCTIONDATE%type,
        FPdtDELIVERYDATE                          in out PACKINGNOTE.DELIVERYDATE%type,
        FPsREMARK                                 in out PACKINGNOTE.REMARK%type,
        FPnSTATUS_ID                              in out PACKINGNOTE.STATUS_ID%type,
        FPnDISTRIBUTIONPOINT_ID                   in out PACKINGNOTE.DISTRIBUTIONPOINT_ID%type,
        FPnDELIVERYPOINT_ID                       in out PACKINGNOTE.DELIVERYPOINT_ID%type,
        FPnPROCESSBUSINESSUNIT_ID                 in out PACKINGNOTE.PROCESSBUSINESSUNIT_ID%type,
        FPnINVOICEBUSINESSUNIT_ID                 in out PACKINGNOTE.INVOICEBUSINESSUNIT_ID%type,
        FPnEMPLOYEE_ID                            in out PACKINGNOTE.EMPLOYEE_ID%type,
        FPnPLANTDEPARTMENT_ID                     in out PACKINGNOTE.PLANTDEPARTMENT_ID%type,
        FPnTRANSPORTARTICLE_ID                    in out PACKINGNOTE.TRANSPORTARTICLE_ID%type,
        FPsCLEANRETURN                            in out PACKINGNOTE.cleanreturn%type,
        FPnSEQUENCENUMBER                         in out PACKINGNOTE.sequencenumber%type,
        FPdtDEADLINE                              in out PACKINGNOTE.deadline%TYPE,
        FPnOccupancy                              in out PACKINGNOTE.occupancy%TYPE,
        FPnSYSTEMUSER_ID                          in out PACKINGNOTE.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out PACKINGNOTE.TIMESTAMP%type,
        FPnORIGIN                                 in out PACKINGNOTE.ORIGIN%type,
        FPdtOriginalDelDate                       in out PACKINGNOTE.ORIGINALDELIVERYDATE%type
) is
		StatusCode				status.code%type;
begin
  begin
    insert into PACKINGNOTE(
   	    PACKINGNOTE_ID,
       	EMPLOYEE_ID,
        NOTENUMBER,
   	    PRODUCTIONDATE,
       	DELIVERYDATE,
        STATUS_ID,
   	    REMARK,
       	DISTRIBUTIONPOINT_ID,
        DELIVERYPOINT_ID,
   	    PROCESSBUSINESSUNIT_ID,
        INVOICEBUSINESSUNIT_ID,
   	    PLANTDEPARTMENT_ID,
       	TRANSPORTARTICLE_ID,
        CLEANRETURN,
        SEQUENCENUMBER,
        DEADLINE,
        OCCUPANCY,
        SYSTEMUSER_ID,
       	TIMESTAMP,
        ORIGIN,
        ORIGINALDELIVERYDATE,
        ENDDATEFORUSE,
				DAYNUMBER,
				CORRECTEDNOTENUMBER,
        STRAIGHTEVENRETURN, Numberofgarmentsinlocker, Numberoflockers
   	)
    values (
   	    SEQ_PACKINGNOTE.nextval,
       	FPnEMPLOYEE_ID,
        FPnNOTENUMBER,
   	    FPdtPRODUCTIONDATE,
       	FPdtDELIVERYDATE,
        FPnSTATUS_ID,
   	    FPsREMARK,
       	FPnDISTRIBUTIONPOINT_ID,
        FPnDELIVERYPOINT_ID,
   	    FPnPROCESSBUSINESSUNIT_ID,
        FPnINVOICEBUSINESSUNIT_ID,
   	    FPnPLANTDEPARTMENT_ID,
       	FPnTRANSPORTARTICLE_ID,
        FPsCLEANRETURN,
        FPnSEQUENCENUMBER,
        FPdtDEADLINE,
        FPnOccupancy,
        FPnSYSTEMUSER_ID,
       	FPdtTIMESTAMP,
        FPnORIGIN,
        FPdtOriginalDelDate,
        FPdtDELIVERYDATE,
				pack_utilities.getdaynumber(FPdtDELIVERYDATE),
				FPnNOTENUMBER,
        'N', 0, 0
   	)	returning PACKINGNOTE_ID into FPnPACKINGNOTE_ID;
  exception
  	when dup_val_on_index then
	    update PACKINGNOTE
    	set
        	EMPLOYEE_ID = FPnEMPLOYEE_ID,
	        NOTENUMBER = FPnNOTENUMBER,
    	    PRODUCTIONDATE = FPdtPRODUCTIONDATE,
        	DELIVERYDATE = FPdtDELIVERYDATE,
	        STATUS_ID = FPnSTATUS_ID,
    	    REMARK = FPsREMARK,
        	DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID,
	        DELIVERYPOINT_ID = FPnDELIVERYPOINT_ID,
    	    PROCESSBUSINESSUNIT_ID = FPnPROCESSBUSINESSUNIT_ID,
	        INVOICEBUSINESSUNIT_ID = FPnINVOICEBUSINESSUNIT_ID,
    	    PLANTDEPARTMENT_ID = FPnPLANTDEPARTMENT_ID,
        	TRANSPORTARTICLE_ID = FPnTRANSPORTARTICLE_ID,
	        CLEANRETURN = FPsCLEANRETURN,
    	    SEQUENCENUMBER = FPnSEQUENCENUMBER,
        	DEADLINE = FPdtDEADLINE,
	        OCCUPANCY = FPnOccupancy,
	        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
	       	TIMESTAMP = FPdtTIMESTAMP,
          ORIGIN = FPnORIGIN,
          ORIGINALDELIVERYDATE = FPdtOriginalDelDate,
          ENDDATEFORUSE = FPdtDELIVERYDATE,
					DAYNUMBER = pack_utilities.getdaynumber(FPdtDELIVERYDATE),
					CORRECTEDNOTENUMBER = FPnNOTENUMBER
    	where NOTENUMBER = FPnNOTENUMBER
			returning PACKINGNOTE_ID into FPnPACKINGNOTE_ID;
		-- if status is 'A' or 'I' then delete packingnote lines
		select CODE into StatusCode from STATUS where STATUS_ID = FPnSTATUS_ID;
		if upper(StatusCode) = 'A' or upper(StatusCode) = 'I' then
			delete from PACKINGNOTELINE where PACKINGNOTE_ID = FPnPACKINGNOTE_ID;
		end if;

  end;
end;

end PACK_PACKINGNOTE;





/
create or replace PACKAGE PACK_PACKINGNOTELINE is
procedure CFbStoreOrCreate (
        FPnPACKINGNOTELINE_ID                     in out PACKINGNOTELINE.PACKINGNOTELINE_ID%type,
        FPnPACKINGSEQUENCE                        in out PACKINGNOTELINE.PACKINGSEQUENCE%type,
        FPnSTANDARDAMOUNT                         in out PACKINGNOTELINE.STANDARDAMOUNT%type,
        FPnVARIATIONAMOUNT                        in out PACKINGNOTELINE.VARIATIONAMOUNT%type,
        FPnDELIVEREDAMOUNT                        in out PACKINGNOTELINE.DELIVEREDAMOUNT%type,
        FPnPRICE                                  in out PACKINGNOTELINE.PRICE%type,
        FPnDISCOUNT                               in out PACKINGNOTELINE.DISCOUNT%type,
        FPnPACKINGNOTE_ID                         in out PACKINGNOTELINE.PACKINGNOTE_ID%type,
        FPnPRODUCT_ID                             in out PACKINGNOTELINE.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out PACKINGNOTELINE.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out PACKINGNOTELINE.FINISHINGMETHOD_ID%type,
		    FPsLOCATION                               in out PACKINGNOTELINE.LOCATION%TYPE,
		    FPsRemforpackinginstructions              in out PACKINGNOTELINE.remarkforpackinginstructions%type,
        FPnSYSTEMUSER_ID                          in out PACKINGNOTELINE.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out PACKINGNOTELINE.TIMESTAMP%type,
        FPnTOBEDELIVEREDAMOUNT                    in out PACKINGNOTELINE.TOBEDELIVEREDAMOUNT%type,
        FPnDISTRIBUTIONPOINT_ID                   in out PACKINGNOTE.DISTRIBUTIONPOINT_ID%type,
        FPdtDELIVERYDATE                          in out PACKINGNOTE.DELIVERYDATE%type);

end PACK_PACKINGNOTELINE;






/
create or replace PACKAGE BODY PACK_PACKINGNOTELINE is

procedure CFbStoreOrCreate (
        FPnPACKINGNOTELINE_ID                     in out PACKINGNOTELINE.PACKINGNOTELINE_ID%type,
        FPnPACKINGSEQUENCE                        in out PACKINGNOTELINE.PACKINGSEQUENCE%type,
        FPnSTANDARDAMOUNT                         in out PACKINGNOTELINE.STANDARDAMOUNT%type,
        FPnVARIATIONAMOUNT                        in out PACKINGNOTELINE.VARIATIONAMOUNT%type,
        FPnDELIVEREDAMOUNT                        in out PACKINGNOTELINE.DELIVEREDAMOUNT%type,
        FPnPRICE                                  in out PACKINGNOTELINE.PRICE%type,
        FPnDISCOUNT                               in out PACKINGNOTELINE.DISCOUNT%type,
        FPnPACKINGNOTE_ID                         in out PACKINGNOTELINE.PACKINGNOTE_ID%type,
        FPnPRODUCT_ID                             in out PACKINGNOTELINE.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out PACKINGNOTELINE.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out PACKINGNOTELINE.FINISHINGMETHOD_ID%type,
		    FPsLOCATION                               in out PACKINGNOTELINE.LOCATION%TYPE,
		    FPsRemforpackinginstructions              in out PACKINGNOTELINE.remarkforpackinginstructions%type,
        FPnSYSTEMUSER_ID                          in out PACKINGNOTELINE.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out PACKINGNOTELINE.TIMESTAMP%type,
        FPnTOBEDELIVEREDAMOUNT                    in out PACKINGNOTELINE.TOBEDELIVEREDAMOUNT%type,
        FPnDISTRIBUTIONPOINT_ID                   in out PACKINGNOTE.DISTRIBUTIONPOINT_ID%type,
        FPdtDELIVERYDATE                          in out PACKINGNOTE.DELIVERYDATE%type
) is
	sCustomCode					packingnoteline.customcode%type;
  sCustomDescription	packingnoteline.customdescription%type;
begin
	-- get CUSTOMCODE, CUSTOMDESCRIPTION from PRODUCTLISTPERCUSTOMER
	begin
		select a.customcode, a.customdescription
    	into sCustomCode, sCustomDescription
			from productlistpercustomer a, department b, distributionpoint c
	  	where a.product_id = FPnPRODUCT_ID
		    and a.sizedefinition_id = FPnSIZEDEFINITION_ID
  		  and a.finishingmethod_id = FPnFINISHINGMETHOD_ID
  			and a.customer_id = b.customer_id
		  	and b.department_id = c.department_id
  		  and c.distributionpoint_id = FPnDISTRIBUTIONPOINT_ID
    		and FPdtDELIVERYDATE between a.dateactive and a.dateinactive;
	exception
  	when others then sCustomCode:=null; sCustomDescription:=null;
  end;

  begin
    insert into PACKINGNOTELINE(
   	    PACKINGNOTELINE_ID,
       	PRODUCT_ID,
        PACKINGSEQUENCE,
   	    STANDARDAMOUNT,
       	VARIATIONAMOUNT,
        FINISHINGMETHOD_ID,
   	    DELIVEREDAMOUNT,
       	PRICE,
        DISCOUNT,
   	    PACKINGNOTE_ID,
       	SIZEDEFINITION_ID,
		    LOCATION,
		    remarkforpackinginstructions,
        SYSTEMUSER_ID,
   	    TIMESTAMP,
        TOBEDELIVEREDAMOUNT,
        CUSTOMCODE,
        CUSTOMDESCRIPTION,
        REPLACEMENTQTY,
        AUTOREPLACEMENTQTY,
        updaterentqty,
        ORIGIN,
				PUTUPTYPE,
				NOCHARGEFIRSTISSUE, NOCHARGEACTIVESEASON, DELIVEREDCOGQTY
    )
   	values (
       	SEQ_PACKINGNOTELINE.nextval,
        FPnPRODUCT_ID,
   	    FPnPACKINGSEQUENCE,
       	FPnSTANDARDAMOUNT,
        FPnVARIATIONAMOUNT,
   	    FPnFINISHINGMETHOD_ID,
       	FPnDELIVEREDAMOUNT,
        FPnPRICE,
   	    FPnDISCOUNT,
       	FPnPACKINGNOTE_ID,
        FPnSIZEDEFINITION_ID,
		    FPsLOCATION,
		    FPsRemforpackinginstructions,
   	    FPnSYSTEMUSER_ID,
       	FPdtTIMESTAMP,
        FPnTOBEDELIVEREDAMOUNT,
        sCustomCode,
        sCustomDescription,
        0,
        0,
        0,
        1,
				0,
				0, 0, 0
    );
	-- not needed
	FPnPACKINGNOTELINE_ID := -1;
  exception
  	when dup_val_on_index then
	    update PACKINGNOTELINE
    	set
        	PACKINGSEQUENCE = FPnPACKINGSEQUENCE,
	        STANDARDAMOUNT = FPnSTANDARDAMOUNT,
    	    VARIATIONAMOUNT = FPnVARIATIONAMOUNT,
        	DELIVEREDAMOUNT = FPnDELIVEREDAMOUNT,
	        PRICE = FPnPRICE,
    	    DISCOUNT = FPnDISCOUNT,
			    LOCATION = FPsLOCATION,
			    remarkforpackinginstructions = FPsRemforpackinginstructions,
        	SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
	        TIMESTAMP = FPdtTIMESTAMP,
          TOBEDELIVEREDAMOUNT = FPnTOBEDELIVEREDAMOUNT,
          CUSTOMCODE = sCustomCode,
          CUSTOMDESCRIPTION = sCustomDescription
    	where PACKINGNOTE_ID = FPnPACKINGNOTE_ID
			and PRODUCT_ID = FPnPRODUCT_ID
			and SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID
    	    and FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID;
		-- not needed
		FPnPACKINGNOTELINE_ID := -1;
  end;
end;

end PACK_PACKINGNOTELINE;






/
create or replace package pack_posexport is

  -- Author  : PVD
  -- Created : 06-03-2007
  -- Purpose : Export into posexport table

  /*
  -- Create table
  create table POSEXPORT
  (
  TRANSACTIONDATE DATE not null,
  TRANSACTION     NUMBER not null,
  PLANTCODE       VARCHAR2(6) not null,
  ROUTENUMBER     NUMBER not null,
  CUSTOMERNUMBER  NUMBER not null,
  PRODUCTCODE     VARCHAR2(12),
  WEARERNUMBER    NUMBER,
  QUANTITY        NUMBER not null,
  PRICE           NUMBER(15,2) not null,
  AMOUNT          NUMBER(15,2) not null
  );
  -- Create index
  create index INDX_POSEXPORT on POSEXPORT (TRANSACTIONDATE, TRANSACTION, PLANTCODE, ROUTENUMBER, CUSTOMERNUMBER);
  */
  function posexport(fromdate date, todate date) return boolean;

end pack_posexport;
/
create or replace package body pack_posexport is
  --internal declarations
  utlfiledir       systemsetting.value%type := null;
  exportfilename   varchar2(32) := 'POS_EXPORT.CSV';
  exportfilehandle utl_file.file_type;

  procedure open_exportfile is
  begin
    --create and open the file that will contain the export
    if utlfiledir is null then
      begin
        select nvl(max(s.value), '/')
        into   utlfiledir
        from   systemsetting s
        where  s.name = 'DATABASELOGDIR'
        and    s.plant_id = (select max(plant_id) from plant);
      end;
    end if;
    if utl_file.is_open(exportfilehandle) = false then
      begin
        exportfilehandle := utl_file.fopen(utlfiledir, exportfilename, 'w');
      end;
    end if;
  exception
    when others then
      begin
        --messages for user in output mode
        dbms_output.put_line('Error during open_exportfile.');
        dbms_output.put_line('      file directory ' || utlfiledir);
        dbms_output.put_line('      file name      ' || exportfilename);
        dbms_output.put_line(substr(sqlerrm, 1, 200));
      end;
  end open_exportfile;

  procedure close_exportfile is
  begin
    --close the export file
    if utl_file.is_open(exportfilehandle) = true then
      begin
        utl_file.fclose(exportfilehandle);
      end;
    end if;
  exception
    when others then
      begin
        --messages for user in output mode
        dbms_output.put_line('Error during close_exportfile.');
        dbms_output.put_line('      file directory ' || utlfiledir);
        dbms_output.put_line('      file name      ' || exportfilename);
        dbms_output.put_line(substr(sqlerrm, 1, 200));
      end;
  end close_exportfile;

  procedure dump_to_csv(p_query varchar2) is
    l_thecursor   integer default dbms_sql.open_cursor;
    l_columnvalue varchar2(4000);
    l_status      integer;
    l_colcnt      number := 0;
    l_separator   varchar2(1);
    l_desctbl     dbms_sql.desc_tab;
  begin
    --initialize, create export file, open/describe cursor
    dbms_sql.parse(l_thecursor, p_query, dbms_sql.native);
    dbms_sql.describe_columns(l_thecursor, l_colcnt, l_desctbl);
    --gather columns to be exported in sql statement
    for i in 1 .. l_colcnt loop
      begin
        dbms_sql.define_column(l_thecursor, i, l_columnvalue, 4000);
        l_separator := ';';
      end;
    end loop;
    --start the cursor with sql statement for export
    l_status := dbms_sql.execute(l_thecursor);
    --loop through all records for export
    while (dbms_sql.fetch_rows(l_thecursor) > 0) loop
      begin
        l_separator := '';
        for i in 1 .. l_colcnt loop
          begin
            dbms_sql.column_value(l_thecursor, i, l_columnvalue);
            utl_file.put(exportfilehandle, l_separator || to_char(l_columnvalue));
            l_separator := ';';
          end;
        end loop;
        utl_file.put(exportfilehandle, l_separator);
        utl_file.new_line(exportfilehandle);
      end;
    end loop;
    --finalize close cursor and file
    dbms_sql.close_cursor(l_thecursor);
  exception
    when utl_file.invalid_path then
      raise_application_error(-20100, 'Invalid Path');
    when utl_file.invalid_mode then
      raise_application_error(-20101, 'Invalid Mode');
    when utl_file.invalid_operation then
      raise_application_error(-20102, 'Invalid Operation');
    when utl_file.invalid_filehandle then
      raise_application_error(-20103, 'Invalid FileHandle');
    when utl_file.write_error then
      raise_application_error(-20104, 'Write Error');
    when utl_file.read_error then
      raise_application_error(-20105, 'Read Error');
    when utl_file.internal_error then
      raise_application_error(-20106, 'Internal Error');
    when others then
      begin
        dbms_output.put_line('Error during export ' || exportfilename || ' in : ' || utlfiledir);
        dbms_output.put_line('Export line: ' || substr(p_query, 0, 200));
        dbms_output.put_line('Status : ' || to_char(l_status));
        raise;
      end;
  end dump_to_csv;

  procedure newlost_account(fromdate date, todate date) is
    lprice customerrentprice.price%type;
  begin
    -- select customers that qualify
    for x in (select 1 transactionno, c.customer_id, c.customernumber, c.dateactive transactiondate,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, t.code plantcode
              from   customer c, businessunit u, plant t
              where  c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    c.dateactive between fromdate and todate
              union
              select 2 transactionno, c.customer_id, c.customernumber, c.dateinactive transactiondate,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, t.code plantcode
              from   customer c, businessunit u, plant t
              where  c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    c.dateinactive between fromdate and todate) loop
      begin
        -- first look for nongarments
        for y in (select p.code productcode, p.product_id,
                         nvl((select sum(q.quantity)
                              from   rentalqtyadjustment q
                              where  q.productlistperdistribpoint_id =
                                     l.productlistperdistribpoint_id), 0) quantity
                  from   productlistperdistribpoint l, product p, distributionpoint t, department d
                  where  l.distributionpoint_id = t.distributionpoint_id
                  and    t.department_id = d.department_id
                  and    d.customer_id = x.customer_id
                  and    l.product_id = p.product_id
                  and    p.typeofmerchandise <> 2) loop
          begin
            begin
              --determine the price
              select nvl(max(cr.price), 0)
              into   lprice
              from   productlistpercustomer a, customerrentprice cr
              where  a.customer_id = x.customer_id
              and    a.product_id = y.product_id
              and    a.productlistpercustomer_id = cr.productlistpercustomer_id
              and    cr.typeofrent = 1
              and    cr.startdate =
                     (select max(crb.startdate)
                       from   customerrentprice crb
                       where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                       and    crb.typeofrent = cr.typeofrent
                       and    crb.startdate <= todate);
            exception
              when no_data_found then
                lprice := 0;
            end;
            --insert new account record
            insert into posexport
              (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
               wearernumber, quantity, price, amount)
            values
              (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
               y.productcode, null, y.quantity, lprice, y.quantity * lprice);
          end;
        end loop; --y end non garments loop
        -- second look for garments
        for z in (select p.code productcode, p.product_id, i.changesperweek quantity, w.wearernumber,
                         t.code plantcode, i.wearerinventory_id
                  from   wearerinventory i, weareremployment e, wearer w, product p, customer c,
                         businessunit u, plant t
                  where  i.weareremployment_id = e.weareremployment_id
                  and    e.wearer_id = w.wearer_id
                  and    w.customer_id = x.customer_id
                  and    i.product_id = p.product_id
                  and    w.customer_id = c.customer_id
                  and    c.defaultbusinessunit_id = u.businessunit_id
                  and    u.plant_id = t.plant_id
                  and    p.typeofmerchandise = 2) loop
          begin
            -- begin
            --determine the price
            -----TNE 19/11/2007
            -- HVH 05/11/2007 first look at wearerinventory price
            -- PVD 03/06/2008 must not be max price, for no_data_found will not work
            select wip.price
            into   lprice
            from   wearerinvprice wip
            where  wip.wearerinventory_id = z.wearerinventory_id
            and    wip.startdate = (select max(wip.startdate)
                                    from   wearerinvprice wip
                                    where  wip.wearerinventory_id = z.wearerinventory_id
                                    and    wip.startdate <= todate);
          exception
            when no_data_found then
              begin
                -- End HVH
                -----
                select nvl(max(cr.price), 0)
                into   lprice
                from   productlistpercustomer a, customerrentprice cr
                where  a.customer_id = x.customer_id
                and    a.product_id = z.product_id
                and    a.productlistpercustomer_id = cr.productlistpercustomer_id
                and    cr.typeofrent = 2
                and    cr.startdate =
                       (select max(crb.startdate)
                         from   customerrentprice crb
                         where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                         and    crb.typeofrent = cr.typeofrent
                         and    crb.startdate <= todate);
              exception
                when no_data_found then
                  lprice := 0;
              end;
          end; -- HVH 19/11/2007
          --insert lost account record
          insert into posexport
            (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
             wearernumber, quantity, price, amount)
          values
            (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
             z.productcode, z.wearernumber, z.quantity, lprice, z.quantity * lprice);
        end loop; --z end garments loop
      end;
    end loop; --x
  end newlost_account;

  procedure newlost_customerproduct(fromdate date, todate date) is
    lprice customerrentprice.price%type;
  begin
    --select the PLPC lines that qualify for export, NON GARMENTS ONLY
    for x in (select 3 transactionno, l.dateactive transactiondate,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customernumber, c.customer_id,
                     p.code productcode, p.product_id,
                     nvl((select sum(q.quantity)
                          from   rentalqtyadjustment q, productlistperdistribpoint pd,
                                 distributionpoint t, department d
                          where  q.productlistperdistribpoint_id = pd.productlistperdistribpoint_id
                          and    pd.product_id = l.product_id
                          and    pd.distributionpoint_id = t.distributionpoint_id
                          and    t.department_id = d.department_id
                          and    d.customer_id = l.customer_id), 0) quantity, t.code plantcode
              from   productlistpercustomer l, customer c, product p, businessunit u, plant t
              where  l.customer_id = c.customer_id
              and    l.product_id = p.product_id
              and    p.typeofmerchandise <> 2
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    l.dateactive between fromdate and todate
              union
              select 4 transactionno, l.dateinactive transactiondate,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customernumber, c.customer_id,
                     p.code productcode, p.product_id,
                     nvl((select sum(q.quantity)
                          from   rentalqtyadjustment q, productlistperdistribpoint pd,
                                 distributionpoint t, department d
                          where  q.productlistperdistribpoint_id = pd.productlistperdistribpoint_id
                          and    pd.product_id = l.product_id
                          and    pd.distributionpoint_id = t.distributionpoint_id
                          and    t.department_id = d.department_id
                          and    d.customer_id = l.customer_id), 0) quantity, t.code plantcode
              from   productlistpercustomer l, customer c, product p, businessunit u, plant t
              where  l.customer_id = c.customer_id
              and    l.product_id = p.product_id
              and    p.typeofmerchandise <> 2
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    l.dateinactive between fromdate and todate) loop
      begin
        begin
          --determine the price
          select nvl(max(cr.price), 0)
          into   lprice
          from   productlistpercustomer a, customerrentprice cr
          where  a.customer_id = x.customer_id
          and    a.product_id = x.product_id
          and    a.productlistpercustomer_id = cr.productlistpercustomer_id
          and    cr.typeofrent = 1
          and    cr.startdate = (select max(crb.startdate)
                                 from   customerrentprice crb
                                 where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                                 and    crb.typeofrent = cr.typeofrent
                                 and    crb.startdate <= todate);
        exception
          when no_data_found then
            lprice := 0;
        end;
        --insert new/lost customer product record NON GARMENTS ONLY
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, null, x.quantity, lprice, x.quantity * lprice);
      end;
    end loop; --x
  end newlost_customerproduct;

  procedure changed_customerproduct(fromdate date, todate date) is
    lprice customerrentprice.price%type;
  begin
    --select the changed rentalqtyadjustment lines for export. NON GARMENTS ONLY
    for x in (select q.adjustmentdate transactiondate, 5 transactionno,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customernumber,
                     p.code productcode, q.quantity, c.customer_id, p.product_id, pt.code plantcode
              from   rentalqtyadjustment q, productlistperdistribpoint pd, customer c, department d,
                     product p, distributionpoint t, businessunit u, plant pt
              where  q.productlistperdistribpoint_id = pd.productlistperdistribpoint_id
              and    pd.distributionpoint_id = t.distributionpoint_id
              and    t.department_id = d.department_id
              and    d.customer_id = c.customer_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = pt.plant_id
              and    pd.product_id = p.product_id
              and    p.typeofmerchandise <> 2
              and    q.adjustmentdate between fromdate and todate
              and    not exists (select l.productlistpercustomer_id
                      from   productlistpercustomer l
                      where  l.customer_id = c.customer_id
                      and    l.product_id = p.product_id
                      and    (l.dateactive between fromdate and todate or
                            l.dateinactive between fromdate and todate))) loop
      begin
        begin
          --determine the price
          select nvl(max(cr.price), 0)
          into   lprice
          from   productlistpercustomer a, customerrentprice cr
          where  a.customer_id = x.customer_id
          and    a.product_id = x.product_id
          and    a.productlistpercustomer_id = cr.productlistpercustomer_id
          and    cr.typeofrent = 1
          and    cr.startdate = (select max(crb.startdate)
                                 from   customerrentprice crb
                                 where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                                 and    crb.typeofrent = cr.typeofrent
                                 and    crb.startdate <= todate);
        exception
          when no_data_found then
            lprice := 0;
        end;
        --insert changed rentalqtyadjustment
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, null, x.quantity, lprice, x.quantity * lprice);
      end;
    end loop; --x end
  end changed_customerproduct;

  procedure newstopped_wearers(fromdate date, todate date) is
    lprice customerrentprice.price%type;
  begin
    --select the wearers that are new or stopped
    for x in (select w.dateactive transactiondate, 6 transactionno,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customer_id, c.customernumber,
                     p.product_id, p.code productcode, i.changesperweek quantity, w.wearernumber,
                     t.code plantcode, i.wearerinventory_id
              from   wearer w, customer c, weareremployment e, wearerinventory i, product p,
                     businessunit u, plant t
              where  w.customer_id = c.customer_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    w.dateactive between fromdate and todate
              and    w.wearer_id = e.wearer_id
              and    e.weareremployment_id = i.weareremployment_id
              and    i.product_id = p.product_id
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    p.typeofmerchandise = 2
              union
              select w.dateinactive transactiondate, 7 transactionno,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customer_id, c.customernumber,
                     p.product_id, p.code productcode, i.changesperweek quantity, w.wearernumber,
                     t.code plantcode, i.wearerinventory_id
              from   wearer w, customer c, weareremployment e, wearerinventory i, product p,
                     businessunit u, plant t
              where  w.customer_id = c.customer_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    w.dateinactive between fromdate and todate
              and    w.wearer_id = e.wearer_id
              and    e.weareremployment_id = i.weareremployment_id
              and    i.product_id = p.product_id
              and    p.typeofmerchandise = 2) loop
      begin
        begin
          --determine the price
          -- HVH 05/11/2007 first look at wearerinventory price
          -- PVD 03/06/2008 must not be max price, for no_data_found will not work
          select wip.price
          into   lprice
          from   wearerinvprice wip
          where  wip.wearerinventory_id = x.wearerinventory_id
          and    wip.startdate = (select max(wip.startdate)
                                  from   wearerinvprice wip
                                  where  wip.wearerinventory_id = x.wearerinventory_id
                                  and    wip.startdate <= todate);
        exception
          when no_data_found then
            begin
              -- End HVH
              select nvl(max(cr.price), 0)
              into   lprice
              from   productlistpercustomer a, customerrentprice cr
              where  a.customer_id = x.customer_id
              and    a.product_id = x.product_id
              and    a.productlistpercustomer_id = cr.productlistpercustomer_id
              and    cr.typeofrent = 2
              and    cr.startdate =
                     (select max(crb.startdate)
                       from   customerrentprice crb
                       where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                       and    crb.typeofrent = cr.typeofrent
                       and    crb.startdate <= todate);
            exception
              when no_data_found then
                lprice := 0;
            end;
        end;
        --insert new/stopped wearers
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, x.wearernumber, x.quantity, lprice, x.quantity * lprice);
      end;
    end loop; --x end
  end newstopped_wearers;

  procedure changed_wearers(fromdate date, todate date) is
    lprice customerrentprice.price%type;
  begin
    --select the wearers inv. lines that are new or stopped, stopped are with neg. amount
    for x in (select i.dateactive transactiondate, 8 transactionno,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customer_id, c.customernumber,
                     p.product_id, p.code productcode, i.changesperweek quantity, w.wearernumber,
                     t.code plantcode, i.wearerinventory_id
              from   wearer w, customer c, weareremployment e, wearerinventory i, product p,
                     businessunit u, plant t
              where  w.customer_id = c.customer_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    w.dateactive not between fromdate and todate
              and    w.dateinactive not between fromdate and todate
              and    i.dateactive between fromdate and todate
              and    w.wearer_id = e.wearer_id
              and    e.weareremployment_id = i.weareremployment_id
              and    i.product_id = p.product_id
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    p.typeofmerchandise = 2
              union
              select i.dateinactive transactiondate, 8 transactionno,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customer_id, c.customernumber,
                     p.product_id, p.code productcode, -1 * i.changesperweek quantity, w.wearernumber,
                     t.code plantcode, i.wearerinventory_id
              from   wearer w, customer c, weareremployment e, wearerinventory i, product p,
                     businessunit u, plant t
              where  w.customer_id = c.customer_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    w.dateactive not between fromdate and todate
              and    w.dateinactive not between fromdate and todate
              and    i.dateinactive between fromdate and todate
              and    w.wearer_id = e.wearer_id
              and    e.weareremployment_id = i.weareremployment_id
              and    i.product_id = p.product_id
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    p.typeofmerchandise = 2) loop
      begin
        begin
          --determine the price
          -- HVH 05/11/2007 first look at wearerinventory price
          -- PVD 03/06/2008 must not be max price, for no_data_found will not work
          select wip.price
          into   lprice
          from   wearerinvprice wip
          where  wip.wearerinventory_id = x.wearerinventory_id
          and    wip.startdate = (select max(wip.startdate)
                                  from   wearerinvprice wip
                                  where  wip.wearerinventory_id = x.wearerinventory_id
                                  and    wip.startdate <= todate);
        exception
          when no_data_found then
            begin
              -- End HVH
              select nvl(max(cr.price), 0)
              into   lprice
              from   productlistpercustomer a, customerrentprice cr
              where  a.customer_id = x.customer_id
              and    a.product_id = x.product_id
              and    a.productlistpercustomer_id = cr.productlistpercustomer_id
              and    cr.typeofrent = 2
              and    cr.startdate =
                     (select max(crb.startdate)
                       from   customerrentprice crb
                       where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                       and    crb.typeofrent = cr.typeofrent
                       and    crb.startdate <= todate);
            exception
              when no_data_found then
                lprice := 0;
            end;
        end;
        --insert changed wearers
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, x.wearernumber, x.quantity, lprice, x.quantity * lprice);
      end;
    end loop; --x
  end changed_wearers;

  procedure changed_sqsetsincirc(fromdate date, todate date) is
    lprice customerrentprice.price%type;
  begin
    --checking sqset in circulation, minimum of 2 SQ's needed and 1 in selection range
    for x in (select trunc(i.timestamp) transactiondate, 8 transactionno, t.code plantcode,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customernumber,
                     p.code productcode, c.customer_id, p.product_id, w.wearernumber,
                     sa.changesperweek - sb.changesperweek quantity, i.wearerinventory_id
              from   statusquoheader ha, statusquoheader hb, sqsetincirculation sa,
                     sqsetincirculation sb, customer c, wearer w, weareremployment e,
                     wearerinventory i, businessunit u, plant t, product p
              where  ha.statusquotype = 2
              and    ha.statusquodate between fromdate and todate
              and    ha.statusquoheader_id = sa.statusquoheader_id
              and    hb.statusquotype = 2
              and    hb.statusquodate = (select max(v.statusquodate)
                                         from   statusquoheader v
                                         where  v.statusquotype = 2
                                         and    v.statusquodate < fromdate)
              and    hb.statusquoheader_id = sb.statusquoheader_id
              and    sa.customer_link_id = sb.customer_link_id
              and    sa.weareremployment_link_id = sb.weareremployment_link_id
              and    sa.product_link_id = sb.product_link_id
              and    sa.changesperweek <> sb.changesperweek
              and    sa.customer_link_id = c.customer_id
              and    c.customer_id = w.customer_id
              and    w.wearer_id = e.wearer_id
              and    e.weareremployment_id = sa.weareremployment_link_id
              and    e.weareremployment_id = i.weareremployment_id
              and    i.product_id = sa.product_link_id
              and    i.product_id = p.product_id
              and    c.dateactive not between fromdate and todate
              and    c.dateinactive not between fromdate and todate
              and    w.dateactive not between fromdate and todate
              and    w.dateinactive not between fromdate and todate
              and    i.dateactive not between fromdate and todate
              and    i.dateinactive not between fromdate and todate
              and    trunc(i.timestamp) between fromdate and todate -- HVH Added 18/9/2007
              and    p.typeofmerchandise = 2
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id) loop
      begin
        begin
          --determine the price
          -- HVH 05/11/2007 first look at wearerinventory price
          -- PVD 03/06/2008 must not be max price, for no_data_found will not work
          select wip.price
          into   lprice
          from   wearerinvprice wip
          where  wip.wearerinventory_id = x.wearerinventory_id
          and    wip.startdate = (select max(wip.startdate)
                                  from   wearerinvprice wip
                                  where  wip.wearerinventory_id = x.wearerinventory_id
                                  and    wip.startdate <= todate);
        exception
          when no_data_found then
            begin
              -- End HVH
              select nvl(max(cr.price), 0)
              into   lprice
              from   productlistpercustomer a, customerrentprice cr
              where  a.customer_id = x.customer_id
              and    a.product_id = x.product_id
              and    a.productlistpercustomer_id = cr.productlistpercustomer_id
              and    cr.typeofrent = 2
              and    cr.startdate =
                     (select max(crb.startdate)
                       from   customerrentprice crb
                       where  crb.productlistpercustomer_id = cr.productlistpercustomer_id
                       and    crb.typeofrent = cr.typeofrent
                       and    crb.startdate <= todate);
            exception
              when no_data_found then
                lprice := 0;
            end;
        end;
        --insert changes in sqset in circulation
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, x.wearernumber, x.quantity, lprice, x.quantity * lprice);
      end;
    end loop; --x
  end changed_sqsetsincirc;

  procedure price_changes(fromdate date, todate date) is
    lquantity number;
    loldprice customerrentprice.price%type;
  begin
    --get the price changes NON GARMENTS
    for x in (select cr.startdate transactiondate, 9 transactionno, t.code plantcode,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customernumber,
                     p.code productcode, cr.price, p.product_id, c.customer_id,
                     l.productlistpercustomer_id
              from   productlistpercustomer l, customerrentprice cr, product p, customer c,
                     businessunit u, plant t
              where  l.productlistpercustomer_id = cr.productlistpercustomer_id
              and    cr.startdate between fromdate and todate
              and    cr.startdate <> l.dateactive
              and    cr.startdate > l.dateactive
              and    cr.startdate <= l.dateinactive
              and    cr.typeofrent = 1
              and    l.customer_id = c.customer_id
              and    l.product_id = p.product_id
              and    p.typeofmerchandise <> 2
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id) loop
      begin
        begin
          --determine the non garment quantity from rentalqtyadjustment
          select nvl(sum(q.quantity), 0)
          into   lquantity
          from   rentalqtyadjustment q, productlistperdistribpoint pd, distributionpoint tp,
                 department d
          where  q.productlistperdistribpoint_id = pd.productlistperdistribpoint_id
          and    q.adjustmentdate < x.transactiondate
          and    pd.product_id = x.product_id
          and    pd.distributionpoint_id = tp.distributionpoint_id
          and    tp.department_id = d.department_id
          and    d.customer_id = x.customer_id;
        exception
          when no_data_found then
            lquantity := 0;
        end;
        begin
          --determine the 'old' price
          select nvl(max(r.price), 0)
          into   loldprice
          from   customerrentprice r
          where  r.productlistpercustomer_id = x.productlistpercustomer_id
          and    r.typeofrent = 1
          and    r.startdate = (select max(rb.startdate)
                                from   customerrentprice rb
                                where  rb.productlistpercustomer_id = r.productlistpercustomer_id
                                and    rb.typeofrent = 1
                                and    rb.startdate < x.transactiondate);
        exception
          when no_data_found then
            loldprice := 0;
        end;
        --insert price changes NON GARMENTS ONLY
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, null, lquantity, x.price, lquantity * (x.price - loldprice));
      end;
    end loop; --x
    --get the price changes GARMENTS
    for y in (select cr.startdate transactiondate, 9 transactionno, t.code plantcode,
                     (select min(r.routenumber)
                       from   routestop s, route r
                       where  s.customer_id = c.customer_id
                       and    s.route_id = r.route_id) routenumber, c.customernumber,
                     p.code productcode, nvl(cr.price, 0) price, p.product_id, c.customer_id,
                     l.productlistpercustomer_id
              from   productlistpercustomer l, customerrentprice cr, product p, customer c,
                     businessunit u, plant t
              where  l.productlistpercustomer_id = cr.productlistpercustomer_id
              and    cr.startdate between fromdate and todate
              and    cr.startdate <> l.dateactive
              and    cr.startdate > l.dateactive
              and    cr.startdate <= l.dateinactive
              and    cr.typeofrent = 2
              and    l.product_id = p.product_id
              and    l.customer_id = c.customer_id
              and    p.typeofmerchandise = 2
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id) loop
      begin
        begin
          --determine the garment quantity from wearerinventory
          select nvl(sum(changesperweek), 0)
          into   lquantity
          from   sqsetincirculation s, statusquoheader h
          where  s.customer_link_id = y.customer_id
          and    s.product_link_id = y.product_id
          and    s.statusquoheader_id = h.statusquoheader_id
          and    h.statusquotype = 2
          and    h.statusquodate = (select max(hb.statusquodate)
                                    from   statusquoheader hb
                                    where  hb.statusquotype = 2
                                    and    hb.statusquodate < y.transactiondate);
        exception
          when no_data_found then
            lquantity := 0;
        end;
        begin
          --determine the 'old' price
          select nvl(max(r.price), 0)
          into   loldprice
          from   customerrentprice r
          where  r.productlistpercustomer_id = y.productlistpercustomer_id
          and    r.typeofrent = 2
          and    r.startdate = (select max(rb.startdate)
                                from   customerrentprice rb
                                where  rb.productlistpercustomer_id = r.productlistpercustomer_id
                                and    rb.typeofrent = 2
                                and    rb.startdate < y.transactiondate);
        exception
          when no_data_found then
            loldprice := 0;
        end;
        --insert price changes GARMENTS ONLY
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (y.transactiondate, y.transactionno, y.plantcode, y.routenumber, y.customernumber,
           y.productcode, null, lquantity, y.price, lquantity * (y.price - loldprice));
      end;
    end loop; --y
  end price_changes;

  procedure credits_writeoffs(fromdate date, todate date) is
  begin
    for x in (select h.invoicedate transactiondate,
                     case
                       when l.invoicelinetype_id in (7, 9) then
                        11
                       else
                        10
                     end transactionno, h.deltocustomernumber customernumber, h.routenumber,
                     ip.wearernumber, (l.adjustedamount - l.amount) amount, l.price,
                     l.code productcode, t.code plantcode, l.billedqty quantity
              from   invoiceheader h, invoiceline l, invoicelineproduct ip, businessunit u, plant t,
                     customer c
              where  h.invoicedate between fromdate and todate
              and    h.invoiceheader_id = l.invoiceheader_id
              and    h.deltocustomer_link_id = c.customer_id
              and    c.defaultbusinessunit_id = u.businessunit_id
              and    u.plant_id = t.plant_id
              and    l.adjustmentreason_id is not null
              and    (l.adjustedamount - l.amount) <> 0
              and    l.invoiceline_id = ip.invoiceline_id(+)
              and    h.status_id = (select t.status_id
                                    from   status t
                                    where  t.statustype = 'IN'
                                    and    t.code = '2')) loop
      begin
        --insert credit/write off changes
        insert into posexport
          (transactiondate, transaction, plantcode, routenumber, customernumber, productcode,
           wearernumber, quantity, price, amount)
        values
          (x.transactiondate, x.transactionno, x.plantcode, x.routenumber, x.customernumber,
           x.productcode, x.wearernumber, x.quantity, nvl(x.price, 0), x.amount);
      end;
    end loop; --x
  end credits_writeoffs;

  function posexport(fromdate date, todate date) return boolean is
  begin
    if todate > fromdate then
      begin
        --first clear old data
        dbms_output.put_line('Delete from table posexport');
        delete from posexport;
        commit;
        --gather new data
        dbms_output.put_line('Start filling table posexport');
        newlost_account(fromdate, todate);
        newlost_customerproduct(fromdate, todate);
        changed_customerproduct(fromdate, todate);
        newstopped_wearers(fromdate, todate);
        changed_wearers(fromdate, todate);
        changed_sqsetsincirc(fromdate, todate);
        price_changes(fromdate, todate);
        credits_writeoffs(fromdate, todate);
        commit;
        --start export
        open_exportfile;
        execute immediate 'alter session set nls_date_format=''yyyy-mm-dd'' ';
        --collect the data to be exported
        dbms_output.put_line('Export from table posexport');
        dump_to_csv('select * from posexport');
        close_exportfile;
        --messages for user in output mode
        dbms_output.put_line('      file directory ' || utlfiledir);
        dbms_output.put_line('      file name      ' || exportfilename);
        dbms_output.put_line('Succesfully exported.');
      end;
    else
      return false;
    end if;
    return true;
  exception
    when others then
      begin
        rollback;
        --messages for user in output mode
        dbms_output.put_line('Export error!');
        dbms_output.put_line(substr(sqlerrm, 1, 200));
        return false;
      end;
  end;

end pack_posexport;
/
create or replace package pack_posplit is
  /*
  Pack_POSsplit Version 0.59
  Procedure createpos
  Process to Purchase Orders waiting for Approval

  ALT - ABS-57337 - Central stockroom issues - ABS-58458 - When module FININTERFACEPOS is in the license, the TaxCode is filled with value "T"
  when creating purchaseorderlines.

  ABS-92454 PO split does not take into account picked items for work orders

  ABS-145830 Customize package_posplit

  */
  procedure createpos(fp_stockroomid           in stockroom.stockroom_id%type,
                      fp_systemuserid          in systemuser.systemuser_id%type,
                      fp_posplitadditionalinfo in purchaseorderheader.posplitadditionalinfo%type,
                      fp_hasfininterfacepos    in integer);
end pack_posplit;
/
create or replace package body pack_posplit is
  ----------------------------------------------------------------------------
  --internal variables:
  ge_user___exception exception;
  gv_message         abslog.message%type := null;
  gv_languageid      languages.language_id%type;
  gv_sizestarid      sizedefinition.sizedefinition_id%type;
  gv_orderpriorityid purchaseorderheader.orderpriority_id%type;
  gv_po_ap_statusid  status.status_id%type;
  gv_enddate2099     date := to_date('31-12-2099', 'DD-MM-YYYY');
  gv_fininterfacepos integer := 0;
  gv_databasecode databasesettings.code%type;
  ----------------------------------------------------------------------------
  --internal functions:
  procedure write_log(fp_text         in abslog.message%type,
                      fp_priority     in abslog.priority%type,
                      fp_systemuserid in systemuser.systemuser_id%type) is
  begin
    --writelog
    abslogwrite.abslog_write(5, 'pack_posplit', null, fp_priority, fp_text || ' ' || sqlerrm,
                             fp_systemuserid);
  end write_log;

  procedure initialize is
  begin
    --initialize
    --get size star
    gv_message := 'initialize; get size star';
    select s.sizedefinition_id into gv_sizestarid from sizedefinition s where s.code = '*';
    --get language
    gv_message := 'initialize: get language';
    select min(language_id) into gv_languageid from languages where translatedescription = 'Y';
    if gv_languageid is null then
      select min(language_id) into gv_languageid from languages;
    end if;
    --get PO approval status
    select st.status_id
    into   gv_po_ap_statusid
    from   status st
    where  st.statustype = 'PO'
    and    st.code = '05'; --waiting for approval
    --get default orderpriority
    gv_message := 'initialize.get default orderpriority ordertype=2 standardpriority=Y';
    select opr.orderpriority_id
    into   gv_orderpriorityid
    from   orderpriority opr
    where  opr.ordertype = 2
    and    opr.standardpriority = 'Y';
    --get database code
    gv_message := 'initialize.get database code';
    select max(code) into gv_databasecode from databasesettings;
  end initialize;

  procedure createpos(fp_stockroomid           in stockroom.stockroom_id%type,
                      fp_systemuserid          in systemuser.systemuser_id%type,
                      fp_posplitadditionalinfo in purchaseorderheader.posplitadditionalinfo%type,
                      fp_hasfininterfacepos    in integer) is
    lv_rec_stockroom          stockroom%rowtype;
    lv_wocbu_yn               varchar2(1) := 'N'; -- Split Work Order Creation Business Unit
    lv_businessunitid_old     businessunit.businessunit_id%type := -1;
    lv_wocustno_yn            varchar2(1) := 'N'; -- Split Work Order Customer Number
    lv_customerid_old         customer.customer_id%type := -1;
    lv_worc_yn                varchar2(1) := 'N'; -- Split Work Order Reason Code
    lv_reasoncodeid_old       reasoncode.reasoncode_id%type := -1;
    lv_woexby_yn              varchar2(1) := 'N'; -- Split Work Order Executed By, 1 = Internal and 2 = External
    lv_executedby_old         workorder.executedby%type := -1;
    lv_woreqdel_yn            varchar2(1) := 'N'; -- Split Work Order Requested Delivery Date
    lv_neededdate_old         date := to_date('1-1-2000', 'dd-mm-yyyy');
    lv_wophaseddel_yn         varchar2(1) := 'N'; -- Split Work Order Phased Delivery Allowed
    lv_allowphasedelivery_old workorder.allowphasedelivery%type := 'X';
    lv_relatedcustid          customer.customer_id%type := -1;
    lv_supplierid             supplier.supplier_id%type := -1;
    lv_purchaseorderheaderid  purchaseorderheader.purchaseorderheader_id%type := null;
    lv_priority               purchaseorderheader.priority%type;
    lv_orderamount            purchaseorderheader.orderamount%type;

    procedure get_stockroom_splitcriteria is
    begin
      --get_stockroom_splitcriteria
      gv_message := 'get_stockroom_splitcriteria';
      /*
      STOCKROOM.USEPOSPLITFORGARMENTS IS '
      Flag that indicates whether PO Splitting Criteria should be used
      when generating PO concerning garments for this stockroom.
        Possible values:
          0 = PO Split criterions will not be used
          1 = PO Split criterions will be used
      */
      if lv_rec_stockroom.useposplitforgarments = 0 then
        begin
          --0 = PO Split criterions will not be used
          --Split on lowest level
          gv_message        := 'get_stockroom_splitcriteria, PO Split criterions will not be used';
          lv_wocbu_yn       := 'Y'; -- Split Work Order Creation Business Unit
          lv_wocustno_yn    := 'Y'; -- Split Work Order Customer Number
          lv_worc_yn        := 'Y'; -- Split Work Order Reason Code
          lv_woexby_yn      := 'Y'; -- Split Work Order Executed By, 1 = Internal and 2 = External
          lv_woreqdel_yn    := 'Y'; -- Split Work Order Requested Delivery Date
          lv_wophaseddel_yn := 'Y'; -- Split Work Order Phased Delivery Allowed
        end;
      else
        begin
          /*
          -->1 = PO Split criterions will be used
          --Always look at item type = 2 = garments for this package, no others are defined anyway..
          --We do NOT check if they are active yes or know the definition only counts.
          --If nothing is select, NO PO will be made!
          ID CODE        FACTORYDESCRIPTION
          1  WOCBU       Work Order Creation Business Unit
          2  WOCUSTNO    Work Order Customer Number
          3  WORC        Work Order Reason Code
          4  WOEXBY      Work Order Executed By, 1 = Internal and 2 = External
          5  WOREQDEL    Work Order Requested Delivery Date
          6  WOPHASEDDEL Work Order Phased Delivery Allowed
          */
          gv_message := 'get_stockroom_splitcriteria, PO Split criterions will be used';

          for ps in (select post.code
                     from   posplitcriterionstockroom pos
                     join   posplitcriteriontype post
                     on     post.posplitcriteriontype_id = pos.posplitcriteriontype_id
                     where  pos.stockroom_id = fp_stockroomid
                     order  by post.posplitcriteriontype_id) loop
            begin
              if ps.code = 'WOCBU' then
                lv_wocbu_yn := 'Y'; -- Split Work Order Creation Business Unit
              end if;
              if ps.code = 'WOCUSTNO' then
                lv_wocustno_yn := 'Y'; -- Split Work Order Customer Number
              end if;
              if ps.code = 'WORC' then
                lv_worc_yn := 'Y'; -- Split Work Order Reason Code
              end if;
              if ps.code = 'WOEXBY' then
                lv_woexby_yn := 'Y'; -- Split Work Order Executed By, 1 = Internal and 2 = External
              end if;
              if ps.code = 'WOREQDEL' then
                lv_woreqdel_yn := 'Y'; -- Split Work Order Requested Delivery Date
              end if;
              if ps.code = 'WOPHASEDDEL' then
                lv_wophaseddel_yn := 'Y'; -- Split Work Order Phased Delivery Allowed
              end if;
            end;
          end loop;
        end;
      end if;
    end get_stockroom_splitcriteria;

    procedure create_purchaseorderheader(fp_supplierid             in purchaseorderheader.supplier_id%type,
                                         fp_creationbusinessunitid in purchaseorderheader.creationbusinessunit_id%type,
                                         fp_splitcustomerlinkid    in purchaseorderheader.splitcustomer_link_id%type,
                                         fp_stockroomid            in purchaseorderheader.stockroom_id%type,
                                         fp_requesteddate          in purchaseorderheader.requesteddate%type,
                                         fp_customerid             in purchaseorderheader.customer_link_id%type,
                                         fp_currencyid             in purchaseorderheader.currency_id%type,
                                         fp_orderamount            in purchaseorderheader.orderamount%type,
                                         fp_purchaseordertype      in purchaseorderheader.purchaseordertype%type,
                                         fp_priority               in purchaseorderheader.priority%type,
                                         fp_supplyingstockroomid   in purchaseorderheader.suplyingstockroom_id%type default null,
                                         fp_executedby             in purchaseorderheader.executedby%type default 1,
                                         fp_reasoncodeid           in purchaseorderheader.reasoncode_id%type default null,
                                         fp_allowphasedelivery     in purchaseorderheader.allowphaseddelivery%type default 'N',
                                         fp_orderpriorityid        in purchaseorderheader.orderpriority_id%type default null) is
      lv_purchaseordernumber  purchaseorderheader.purchaseordernumber%type := 0;
      lv_orderdate            purchaseorderheader.orderdate%type := trunc(sysdate);
      lv_ordertype            purchaseorderheader.ordertype%type := 0;
      lv_exportdate           purchaseorderheader.exportdate%type := gv_enddate2099;
      lv_exportbatchnumber    purchaseorderheader.exportbatchnumber%type := null;
      lv_confirmeddate        purchaseorderheader.confirmeddate%type := gv_enddate2099;
      lv_approvaldate         purchaseorderheader.approvaldate%type := gv_enddate2099;
      lv_approvaluserid       purchaseorderheader.approvaluser_id%type := null;
      lv_exportuserid         purchaseorderheader.exportuser_id%type := null;
      lv_confirmeduserid      purchaseorderheader.confirmeduser_id%type := null;
      lv_firstreceivingdate   purchaseorderheader.firstreceivingdate%type := gv_enddate2099;
      lv_lastreceivingdate    purchaseorderheader.lastreceivingdate%type := gv_enddate2099;
      lv_origin               purchaseorderheader.origin%type := 1; --1=purchase request
      lv_canceldate           purchaseorderheader.canceldate%type := gv_enddate2099;
      lv_canceluserid         purchaseorderheader.canceluser_id%type := null;
      lv_orderuserid          purchaseorderheader.orderuser_id%type := null;
      lv_remark               purchaseorderheader.remark%type := null;
      lv_plantcompanyid       purchaseorderheader.plantcompany_id%type := null;
      lv_finexpdate           purchaseorderheader.finexpdate%type := null;
      lv_processedtoworkorder purchaseorderheader.processedtoworkorder%type := 'N';
      lv_deliverypointid      purchaseorderheader.deliverypoint_link_id%type := null;
      --lv_suplyingstockroomid  purchaseorderheader.suplyingstockroom_id%type := null;
    begin
      --insert into purchaseorderheader
      gv_message := 'create_purchaseorderheader.insert into purchaseorderheader';
      insert into purchaseorderheader
        (purchaseorderheader_id, purchaseordernumber, supplier_id, businessunit_id, stockroom_id,
         orderdate, requesteddate, status_id, ordertype, exportdate, exportbatchnumber,
         confirmeddate, customer_link_id, systemuser_id, timestamp, approvaldate, approvaluser_id,
         exportuser_id, confirmeduser_id, firstreceivingdate, lastreceivingdate, currency_id, origin,
         canceldate, canceluser_id, orderamount, orderuser_id, remark, plantcompany_id, finexpdate,
         purchaseordertype, processedtoworkorder, deliverypoint_link_id, suplyingstockroom_id,
         priority, executedby, reasoncode_id, allowphaseddelivery, posplitadditionalinfo,
         orderpriority_id, creationbusinessunit_id, splitcustomer_link_id)
      values
        (seq_purchaseorderheader.nextval, lv_purchaseordernumber, fp_supplierid,
         lv_rec_stockroom.managedbybu_id, fp_stockroomid, lv_orderdate, fp_requesteddate,
         gv_po_ap_statusid, lv_ordertype, lv_exportdate, lv_exportbatchnumber, lv_confirmeddate,
         fp_customerid, fp_systemuserid, sysdate, lv_approvaldate, lv_approvaluserid,
         lv_exportuserid, lv_confirmeduserid, lv_firstreceivingdate, lv_lastreceivingdate,
         fp_currencyid, lv_origin, lv_canceldate, lv_canceluserid, fp_orderamount, lv_orderuserid,
         lv_remark, lv_plantcompanyid, lv_finexpdate, fp_purchaseordertype, lv_processedtoworkorder,
         lv_deliverypointid, fp_supplyingstockroomid, fp_priority, nvl(fp_executedby, 1),
         fp_reasoncodeid, nvl(fp_allowphasedelivery, 'N'), fp_posplitadditionalinfo,
         coalesce(fp_orderpriorityid, gv_orderpriorityid), fp_creationbusinessunitid,
         fp_splitcustomerlinkid)
      returning purchaseorderheader_id into lv_purchaseorderheaderid;
    end create_purchaseorderheader;

    function create_purchaseorderline(fp_productid            in product.product_id%type,
                                      fp_sizedefinitionid     in sizedefinition.sizedefinition_id%type,
                                      fp_quantityordered      in purchaseorderline.quantityordered%type,
                                      fp_purchaseprice        in purchaseorderline.purchaseprice%type,
                                      fp_requestedgradeid     in purchaseorderline.requestedgrade_id%type,
                                      fp_linesequentialnumber in purchaseorderline.linesequentialnumber%type,
                                      fp_uniqueitem           in purchaseorderline.uniqueitem%type,
                                      fp_supplierid           in supplier.supplier_id%type)
      return purchaseorderline.purchaseorderline_id%type is
      lv_lastreceiveddate            purchaseorderline.lastreceiveddate%type;
      lv_quantityreceived            purchaseorderline.quantityreceived%type := 0;
      lv_quantitycancelled           purchaseorderline.quantitycancelled%type := 0;
      lv_supplierproductcode         purchaseorderline.supplierproductcode%type;
      lv_suppliersizecode            purchaseorderline.suppliersizecode%type;
      lv_quantityorderedstock        purchaseorderline.quantityorderedstock%type := fp_quantityordered;
      lv_quantityordereddirectissue  purchaseorderline.quantityordereddirectissue%type := 0;
      lv_quantityreceiveddirectissue purchaseorderline.quantityreceiveddirectissue%type := 0;
      lv_quantityconfirmed           purchaseorderline.quantityconfirmed%type;
      lv_confirmeddate               purchaseorderline.confirmeddate%type := gv_enddate2099;
      lv_confirmationuser_id         purchaseorderline.confirmationuser_id%type;
      lv_remark                      purchaseorderline.remark%type;
      lv_purchaseorderlineid         purchaseorderline.purchaseorderline_id%type;
      lv_taxcode                     purchaseorderline.taxcode%type;
      lv_turnovergroup_id            supplierproduct.turnovergroup_id%type;
    begin
      --create_purchaseorderline
      gv_message := 'create_purchaseorderline';
      select max(sp.supplierproductcode), max(sp.suppliersizecode), max(sp.turnovergroup_id)
      into   lv_supplierproductcode, lv_suppliersizecode, lv_turnovergroup_id
      from   supplierproduct sp
      join   productsizepersupproduct psp
      on     psp.supplierproduct_id = sp.supplierproduct_id
      where  sp.supplier_id = fp_supplierid
      and    psp.product_id = fp_productid
      and    psp.sizedefinition_id = fp_sizedefinitionid;
      --update or insert into purchaseorderline
      gv_message := 'update or insert into purchaseorderline';
      select pol.purchaseorderline_id
      into   lv_purchaseorderlineid
      from   purchaseorderline pol
      where  pol.purchaseorderheader_id = lv_purchaseorderheaderid
      and    pol.product_link_id = fp_productid
      and    pol.sizedefinition_link_id = fp_sizedefinitionid
      and    pol.uniqueitem = fp_uniqueitem
      and    pol.requestedgrade_id = fp_requestedgradeid;
      --update
      gv_message := 'update purchaseorderline ' || lv_purchaseorderlineid;
      update purchaseorderline pol
      set    pol.quantityordered = pol.quantityordered + fp_quantityordered,
             pol.quantityorderedstock = pol.quantityorderedstock + lv_quantityorderedstock,
             pol.timestamp = sysdate, pol.systemuser_id = fp_systemuserid
      where  pol.purchaseorderline_id = lv_purchaseorderlineid;
      return lv_purchaseorderlineid;
    exception
      when no_data_found then
        begin
          --insert into purchaseorderline
          gv_message := 'insert into purchaseorderline';
          lv_taxcode := case
                          when gv_fininterfacepos = 1 then
                           'T'
                          else
                           null
                        end;
          insert into purchaseorderline
            (purchaseorderline_id, purchaseorderheader_id, product_link_id, sizedefinition_link_id,
             lastreceiveddate, quantityordered, quantityreceived, quantitycancelled, systemuser_id,
             timestamp, supplierproductcode, suppliersizecode, quantityorderedstock,
             quantityordereddirectissue, quantityreceiveddirectissue, quantityconfirmed,
             purchaseprice, confirmeddate, confirmationuser_id, uniqueitem, remark, taxcode,
             turnovergroup_id, requestedgrade_id, linesequentialnumber)
          values
            (seq_purchaseorderline.nextval, lv_purchaseorderheaderid, fp_productid,
             fp_sizedefinitionid, lv_lastreceiveddate, fp_quantityordered, lv_quantityreceived,
             lv_quantitycancelled, fp_systemuserid, sysdate, lv_supplierproductcode,
             lv_suppliersizecode, lv_quantityorderedstock, lv_quantityordereddirectissue,
             lv_quantityreceiveddirectissue, lv_quantityconfirmed, fp_purchaseprice,
             lv_confirmeddate, lv_confirmationuser_id, fp_uniqueitem, lv_remark, lv_taxcode,
             lv_turnovergroup_id, fp_requestedgradeid, fp_linesequentialnumber)
          returning purchaseorderline_id into lv_purchaseorderlineid;
        end;
        return lv_purchaseorderlineid;
    end create_purchaseorderline;

    procedure link_wol_2_pol(fp_purchaserequestid   in purchaserequest.purchaserequest_id%type,
                             fp_businessunitid      in workorder.businessunit_id%type,
                             fp_neededdate          in workorder.neededdate%type,
                             fp_customerid          in workorder.customer_link_id%type,
                             fp_reasoncodeid        in workorderline.reasoncode_id%type,
                             fp_executedby          in workorder.executedby%type,
                             fp_allowphasedelivery  in workorder.allowphasedelivery%type,
                             fp_purchaseorderlineid in purchaseorderline.purchaseorderline_id%type) is
    begin
      ---link_wol_2_pol
      gv_message := 'link_wol_2_pol for purchaserequest id ' || to_char(fp_purchaserequestid);
      update workorderline wol
      set    wol.purchaseorderline_id = fp_purchaseorderlineid, wol.systemuser_id = fp_systemuserid,
             wol.timestamp = sysdate, wol.purchaserequest_id = null
      where  wol.purchaserequest_id = fp_purchaserequestid
      and    exists (select 1
              from   workorder wo
              where  wo.workorder_id = wol.workorder_id
              and    wo.neededdate = fp_neededdate
              and    wo.businessunit_id = fp_businessunitid
              and    wo.executedby = fp_executedby
              and    wo.reasoncode_id = fp_reasoncodeid
              and    wo.allowphasedelivery = fp_allowphasedelivery
              and    (wo.customer_link_id = fp_customerid or
                    (fp_customerid is null and wo.customer_link_id is null)));
    end link_wol_2_pol;

    procedure link_wole_2_pol(fp_purchaserequestid   in purchaserequest.purchaserequest_id%type,
                              fp_businessunitid      in workorder.businessunit_id%type,
                              fp_neededdate          in workorder.neededdate%type,
                              fp_customerid          in workorder.customer_link_id%type,
                              fp_reasoncodeid        in workorderline.reasoncode_id%type,
                              fp_executedby          in workorder.executedby%type,
                              fp_allowphasedelivery  in workorder.allowphasedelivery%type,
                              fp_purchaseorderlineid in purchaseorderline.purchaseorderline_id%type) is
    begin
      ---link_wole_2_pol
      gv_message := 'link_wole_2_pol for purchaserequest id ' || to_char(fp_purchaserequestid);
      update workorderlineemblem woem
      set    woem.purchaseorderline_id = fp_purchaseorderlineid,
             woem.systemuser_id = fp_systemuserid, woem.timestamp = sysdate,
             woem.purchaserequest_id = null
      where  woem.purchaserequest_id = fp_purchaserequestid
      and    exists (select 1
              from   workorderline wol
              join   workorder wo
              on     wo.workorder_id = wol.workorder_id
              where  wol.workorderline_id = woem.workorderline_id
              and    wo.neededdate = fp_neededdate
              and    wo.businessunit_id = fp_businessunitid
              and    wo.executedby = fp_executedby
              and    wo.reasoncode_id = fp_reasoncodeid
              and    wo.allowphasedelivery = fp_allowphasedelivery
              and    (wo.customer_link_id = fp_customerid or
                    (fp_customerid is null and wo.customer_link_id is null)));
    end link_wole_2_pol;

    procedure update_purchaseorderheader(fp_purchaseorderheadeid purchaseorderheader.purchaseorderheader_id%type,
                                         fp_orderamount          in purchaseorderheader.orderamount%type) is
    begin
      --update_purchaseorderheader
      gv_message := 'update_purchaseorderheader';
      update purchaseorderheader poh
      set    poh.orderamount = fp_orderamount, poh.systemuser_id = fp_systemuserid,
             poh.timestamp = sysdate
      where  poh.purchaseorderheader_id = fp_purchaseorderheadeid;
    end update_purchaseorderheader;

    procedure createpos4workorder is
      lv_quantityleftover     number;
      lv_linesequentialnumber purchaseorderline.linesequentialnumber%type;
      lv_uniquelycode         supplierproduct.uniqueitem%type;

    begin
      --loop purchaserequest on lowest group by level possible
      gv_message := 'createpos4workorder, loop pox';
      for pox in ( --workorderline.purchaserequest_id part 1 of the unions 2 parts
                 ( select wo.businessunit_id, wo.customer_link_id, wo.reasoncode_id, wo.executedby,
                          wo.neededdate, wo.allowphasedelivery, pr.customer_id relatedcust_id,
                          pr.supplier_id, max(s.currency_id) currency_id,
                          max(s.suppliertype) suppliertype, pr.priority,
                          max(rs.purchaseorderpriority_id) purchaseorderpriority_id,
                          max(wol.codeuniquely) codeuniquely,
                          max(s.supplyingstockroom_id) supplyingstockroom_id
                  from   purchaserequest pr
                  join   workorderline wol
                  on     wol.purchaserequest_id = pr.purchaserequest_id
                  join   workorder wo
                  on     wo.workorder_id = wol.workorder_id
                  join   supplier s
                  on     s.supplier_id = pr.supplier_id --supplier must exists!!
                  join   reasoncode rs
                  on     rs.reasoncode_id = wo.reasoncode_id
                  where  pr.stockroom_id = fp_stockroomid -->selected stockroomid
                  and    pr.poapprovaltype = 1 --> all select Purchase requests via the application
                  group  by pr.supplier_id, wo.businessunit_id, wo.customer_link_id, wo.reasoncode_id,
                             wo.executedby, wo.neededdate, wo.allowphasedelivery, pr.customer_id,
                             pr.priority
                  union
                  --workorderlineemblem.purchaserequest_id  part 2 of the unions 2 parts
                  select wo.businessunit_id, wo.customer_link_id, wo.reasoncode_id, wo.executedby,
                          wo.neededdate, wo.allowphasedelivery, pr.customer_id relatedcust_id,
                          pr.supplier_id, max(s.currency_id) currency_id,
                          max(s.suppliertype) suppliertype, pr.priority,
                          max(rs.purchaseorderpriority_id) purchaseorderpriority_id,
                          max(wol.codeuniquely) codeuniquely,
                          max(s.supplyingstockroom_id) supplyingstockroom_id
                  from   purchaserequest pr
                  join   workorderlineemblem woem
                  on     woem.purchaserequest_id = pr.purchaserequest_id
                  join   workorderline wol
                  on     wol.workorderline_id = woem.workorderline_id
                  join   workorder wo
                  on     wo.workorder_id = wol.workorder_id
                  join   supplier s
                  on     s.supplier_id = pr.supplier_id --supplier must exists!!
                  join   reasoncode rs
                  on     rs.reasoncode_id = wo.reasoncode_id
                  where  pr.stockroom_id = fp_stockroomid -->selected stockroomid
                  and    pr.poapprovaltype = 1 --> all select Purchase requests via the application
                  group  by pr.supplier_id, wo.businessunit_id, pr.supplier_id, wo.customer_link_id,
                             wo.reasoncode_id, wo.executedby, wo.neededdate, wo.allowphasedelivery,
                             pr.customer_id, pr.priority)
                  order  by supplier_id, businessunit_id, customer_link_id, reasoncode_id, executedby,
                             neededdate, allowphasedelivery, priority) loop
        begin
          --check if a new PO needs to be created
          if ((lv_wocbu_yn = 'Y' and pox.businessunit_id <> lv_businessunitid_old) or
             (lv_wocustno_yn = 'Y' and pox.customer_link_id <> lv_customerid_old) or
             (lv_worc_yn = 'Y' and pox.reasoncode_id <> lv_reasoncodeid_old) or
             (lv_woexby_yn = 'Y' and pox.executedby <> lv_executedby_old) or
             (lv_woreqdel_yn = 'Y' and pox.neededdate <> lv_neededdate_old) or
             (lv_wophaseddel_yn = 'Y' and pox.allowphasedelivery <> lv_allowphasedelivery_old) or
             (lv_relatedcustid <> nvl(pox.relatedcust_id, -1)) or --always for related customer
             (lv_supplierid <> nvl(pox.supplier_id, -1)) or --always for supplier id
             (lv_priority <> pox.priority) --always for priority
             ) then
            begin
              --create the new PO
              lv_linesequentialnumber := 0;
              lv_orderamount          := 0;
              create_purchaseorderheader(pox.supplier_id, pox.businessunit_id, pox.customer_link_id,
                                         fp_stockroomid, pox.neededdate, pox.relatedcust_id,
                                         pox.currency_id, lv_orderamount, pox.suppliertype,
                                         pox.priority, pox.supplyingstockroom_id, pox.executedby,
                                         pox.reasoncode_id, pox.allowphasedelivery,
                                         pox.purchaseorderpriority_id);
            end;
          end if;
          --for selected records, lookup workorders etc
          gv_message := 'createpos4workorder, loop poy wol';
          for poy in (select pr.product_id, pr.sizedefinition_id, pr.purchaseprice,
                             pr.purchaserequest_id, pr.requestedgrade_id,
                             (select sum(wol.quantityordered - wol.quantitycancelled - case
                                            when wol.quantitypicked > 0 then
                                             wol.quantitypicked
                                            else
                                             wol.quantityfilled
                                          end)
                               from   workorderline wol
                               join   workorder wo
                               on     wo.workorder_id = wol.workorder_id
                               where  wol.purchaserequest_id = pr.purchaserequest_id
                               and    wo.businessunit_id = pox.businessunit_id
                               and    wo.neededdate = pox.neededdate
                               and    ((wo.customer_link_id = pox.customer_link_id) or
                                     (wo.customer_link_id is null and pox.customer_link_id is null))
                               and    wo.reasoncode_id = pox.reasoncode_id
                               and    wo.executedby = pox.executedby
                               and    wo.allowphasedelivery = pox.allowphasedelivery) quantityordered,
                             pr.quantitytoorder
                      from   purchaserequest pr
                      where  pr.stockroom_id = fp_stockroomid -->selected stockroomid
                      and    pr.poapprovaltype = 1 --> all selected Purchase requests via the application
                      and    nvl(pr.customer_id, -1) = nvl(pox.relatedcust_id, -1)
                      and    pr.supplier_id = pox.supplier_id --supplier must exists!!
                      and    pr.priority = pox.priority
                      and    exists
                       (select 1
                              from   workorderline wol
                              join   workorder wo
                              on     wo.workorder_id = wol.workorder_id
                              where  wol.purchaserequest_id = pr.purchaserequest_id
                              and    wo.businessunit_id = pox.businessunit_id
                              and    wo.neededdate = pox.neededdate
                              and    ((wo.customer_link_id = pox.customer_link_id) or
                                    (wo.customer_link_id is null and pox.customer_link_id is null))
                              and    wo.reasoncode_id = pox.reasoncode_id
                              and    wo.executedby = pox.executedby
                              and    wo.allowphasedelivery = pox.allowphasedelivery)
                      order  by pr.priority, pr.product_id, pr.sizedefinition_id,
                                pr.requestedgrade_id, pr.customer_id) loop
            begin
              --link_wol_2_pol
              lv_linesequentialnumber := lv_linesequentialnumber + 1;
              lv_orderamount          := lv_orderamount + (poy.quantityordered * poy.purchaseprice);
              select nvl(min(sp.uniqueitem), pox.codeuniquely)
              into   lv_uniquelycode
              from   productsizepersupproduct pspsp, supplier s, supplierproduct sp
              where  sp.supplier_id = s.supplier_id
              and    sp.supplier_id = pox.supplier_id
              and    sp.supplierproduct_id = pspsp.supplierproduct_id
              and    pspsp.product_id = poy.product_id
              and    pspsp.sizedefinition_id = poy.sizedefinition_id;
              link_wol_2_pol(poy.purchaserequest_id, pox.businessunit_id, pox.neededdate,
                             pox.customer_link_id, pox.reasoncode_id, pox.executedby,
                             pox.allowphasedelivery,
                             create_purchaseorderline(poy.product_id, poy.sizedefinition_id,
                                                       poy.quantityordered, poy.purchaseprice,
                                                       poy.requestedgrade_id, lv_linesequentialnumber,
                                                       lv_uniquelycode, pox.supplier_id));
              --delete from purchaserequest pr
              gv_message := 'createpos4workorder, update/delete purchaserequest';
              update purchaserequest pr
              set    pr.quantitytoorder = pr.quantitytoorder - poy.quantityordered
              where  pr.purchaserequest_id = poy.purchaserequest_id
              returning pr.quantitytoorder into lv_quantityleftover;
              if lv_quantityleftover <= 0 then
                begin
                  delete from purchaserequest pr
                  where  pr.purchaserequest_id = poy.purchaserequest_id
                  and    pr.quantitytoorder <= 0
                  and    not exists (select 1
                          from   workorderline wol
                          where  wol.purchaserequest_id = pr.purchaserequest_id)
                  and    not exists
                   (select 1
                          from   workorderlineemblem woem
                          where  woem.purchaserequest_id = pr.purchaserequest_id);
                end;
              end if;
            end;
          end loop; --poy
          --for selected records, lookup workorder line emblems
          gv_message := 'createpos4workorder, loop poz wol emlems';
          for poz in (select pr.product_id, pr.sizedefinition_id, pr.purchaseprice,
                             pr.purchaserequest_id, pr.requestedgrade_id,
                             (select sum(woem.qtyrequested)
                               from   workorderlineemblem woem
                               join   workorderline wol
                               on     wol.workorderline_id = woem.workorderline_id
                               join   workorder wo
                               on     wo.workorder_id = wol.workorder_id
                               where  woem.purchaserequest_id = pr.purchaserequest_id
                               and    wo.businessunit_id = pox.businessunit_id
                               and    wo.neededdate = pox.neededdate
                               and    ((wo.customer_link_id = pox.customer_link_id) or
                                     (wo.customer_link_id is null and pox.customer_link_id is null))
                               and    wo.reasoncode_id = pox.reasoncode_id
                               and    wo.executedby = pox.executedby
                               and    wo.allowphasedelivery = pox.allowphasedelivery) quantityordered,
                             pr.quantitytoorder
                      from   purchaserequest pr
                      where  pr.stockroom_id = fp_stockroomid -->selected stockroomid
                      and    pr.poapprovaltype = 1 --> all selected Purchase requests via the application
                      and    nvl(pr.customer_id, -1) = nvl(pox.relatedcust_id, -1)
                      and    pr.supplier_id = pox.supplier_id --supplier must exists!!
                      and    pr.priority = pox.priority
                      and    exists
                       (select 1
                              from   workorderlineemblem woem
                              join   workorderline wol
                              on     wol.workorderline_id = woem.workorderline_id
                              join   workorder wo
                              on     wo.workorder_id = wol.workorder_id
                              where  woem.purchaserequest_id = pr.purchaserequest_id
                              and    wo.businessunit_id = pox.businessunit_id
                              and    wo.neededdate = pox.neededdate
                              and    ((wo.customer_link_id = pox.customer_link_id) or
                                    (wo.customer_link_id is null and pox.customer_link_id is null))
                              and    wo.reasoncode_id = pox.reasoncode_id
                              and    wo.executedby = pox.executedby
                              and    wo.allowphasedelivery = pox.allowphasedelivery)
                      order  by pr.priority, pr.product_id, pr.sizedefinition_id,
                                pr.requestedgrade_id, pr.customer_id) loop
            begin
              --link_wol_2_pol
              lv_linesequentialnumber := lv_linesequentialnumber + 1;
              lv_orderamount          := lv_orderamount + (poz.quantityordered * poz.purchaseprice);
              select nvl(min(sp.uniqueitem), pox.codeuniquely)
              into   lv_uniquelycode
              from   productsizepersupproduct pspsp, supplier s, supplierproduct sp
              where  sp.supplier_id = s.supplier_id
              and    sp.supplier_id = pox.supplier_id
              and    sp.supplierproduct_id = pspsp.supplierproduct_id
              and    pspsp.product_id = poz.product_id
              and    pspsp.sizedefinition_id = poz.sizedefinition_id;
              link_wole_2_pol(poz.purchaserequest_id, pox.businessunit_id, pox.neededdate,
                              pox.customer_link_id, pox.reasoncode_id, pox.executedby,
                              pox.allowphasedelivery,
                              create_purchaseorderline(poz.product_id, poz.sizedefinition_id,
                                                        poz.quantityordered, poz.purchaseprice,
                                                        poz.requestedgrade_id, lv_linesequentialnumber,
                                                        lv_uniquelycode, pox.supplier_id));
              --delete from purchaserequest pr
              gv_message := 'createpos4workorder, update/delete purchaserequest';
              update purchaserequest pr
              set    pr.quantitytoorder = pr.quantitytoorder - poz.quantityordered
              where  pr.purchaserequest_id = poz.purchaserequest_id
              returning pr.quantitytoorder into lv_quantityleftover;
              if lv_quantityleftover <= 0 then
                begin
                  delete from purchaserequest pr
                  where  pr.purchaserequest_id = poz.purchaserequest_id
                  and    pr.quantitytoorder <= 0
                  and    not exists (select 1
                          from   workorderline wol
                          where  wol.purchaserequest_id = pr.purchaserequest_id)
                  and    not exists
                   (select 1
                          from   workorderlineemblem woem
                          where  woem.purchaserequest_id = pr.purchaserequest_id);
                end;
              end if;
            end;
          end loop; --poz
          --update_purchaseorderheader.orderamount
          update_purchaseorderheader(lv_purchaseorderheaderid, lv_orderamount);
        end;
        lv_businessunitid_old     := pox.businessunit_id;
        lv_customerid_old         := pox.customer_link_id;
        lv_reasoncodeid_old       := pox.reasoncode_id;
        lv_executedby_old         := pox.executedby;
        lv_neededdate_old         := pox.neededdate;
        lv_allowphasedelivery_old := pox.allowphasedelivery;
        lv_relatedcustid          := nvl(pox.relatedcust_id, -1);
        lv_supplierid             := pox.supplier_id;
        lv_priority               := pox.priority;
      end loop; --pox
    end createpos4workorder;

    procedure createposleftover is
      lv_purchaseorderlineid  purchaseorderline.purchaseorderline_id%type;
      lv_linesequentialnumber purchaseorderline.linesequentialnumber%type;
    begin
      --createposleftover STOCKROOM_ID, SUPPLIER_ID, CUSTOMER_ID, PRODUCT_ID, SIZEDEFINITION_ID, REQUESTEDGRADE_ID, PRIORITY
      gv_message := 'createposleftover';
      for polx in (select pr.supplier_id, pr.priority, pr.customer_id,
                          max(pr.requesteddate) requesteddate,
                          sum(pr.quantitytoorder) quantitytoorder,
                          sum(pr.quantitytoorder * pr.purchaseprice) amounttoorder,
                          max(s.currency_id) currency_id, max(s.suppliertype) suppliertype,
                          max(s.supplyingstockroom_id) supplyingstockroom_id
                   from   purchaserequest pr
                   join   supplier s
                   on     s.supplier_id = pr.supplier_id --supplier must exists!!
                   where  pr.stockroom_id = fp_stockroomid -->selected stockroomid
                   and    pr.poapprovaltype = 1 --> all select Purchase requests via the application
                   group  by pr.supplier_id, pr.priority, pr.customer_id
                   order  by pr.supplier_id, pr.priority, pr.customer_id) loop
        begin
          --create the new PO
          lv_linesequentialnumber := 0;

          if gv_databasecode <> 'KLH' then
          create_purchaseorderheader(polx.supplier_id, lv_rec_stockroom.managedbybu_id, null,
                                     fp_stockroomid, polx.requesteddate, polx.customer_id,
                                     polx.currency_id, polx.amounttoorder, polx.suppliertype,
                                     polx.priority, polx.supplyingstockroom_id);
          end if;

          for poly in (select pr.product_id, pr.sizedefinition_id, pr.quantitytoorder,
                              pr.purchaseprice, pr.requestedgrade_id, pr.purchaserequest_id,
                              nvl((select max(sp.uniqueitem)
                                   from   supplierproduct sp
                                   join   productsizepersupproduct psp
                                   on     psp.supplierproduct_id = sp.supplierproduct_id
                                   where  psp.product_id = pr.product_id
                                   and    psp.sizedefinition_id = pr.sizedefinition_id
                                   and    sp.supplier_id = pr.supplier_id), 'N') uniqueitem
                       from   purchaserequest pr
                       where  pr.supplier_id = polx.supplier_id --supplier must exists!!
                       and    pr.stockroom_id = fp_stockroomid -->selected stockroomid
                       and    pr.poapprovaltype = 1 --> all select Purchase requests via the application
                       and    pr.priority = polx.priority
                       and    (pr.customer_id = polx.customer_id or
                             (pr.customer_id is null and polx.customer_id is null))
                       order  by pr.priority, pr.product_id, pr.sizedefinition_id,
                                 pr.requestedgrade_id, pr.customer_id) loop
            begin

              if gv_databasecode = 'KLH' then
                --MDI change get purchaseorederheaderid from  Purchaseorder with status waiting for approval
                select poh.purchaseorderheader_id
                into lv_purchaseorderheaderid
                from purchaseorderline pol
                join purchaseorderheader poh on poh.purchaseorderheader_id = pol.purchaseorderheader_id
                where poh.supplier_id =polx.supplier_id
                and poh.stockroom_id = fp_stockroomid
                and poh.status_id = (select st.status_id from status st where st.statustype = 'PO' and st.code='05') -->Purchaseorder with status waiting for approval
                and pol.product_link_id = poly.product_id
                and pol.sizedefinition_link_id = poly.sizedefinition_id;
              end if;

              lv_linesequentialnumber := lv_linesequentialnumber + 1;
              lv_purchaseorderlineid  := create_purchaseorderline(poly.product_id,
                                                                  poly.sizedefinition_id,
                                                                  poly.quantitytoorder,
                                                                  poly.purchaseprice,
                                                                  poly.requestedgrade_id,
                                                                  lv_linesequentialnumber,
                                                                  poly.uniqueitem, polx.supplier_id);
              --remove the purchaserequest
              gv_message := 'createposleftover, delete purchaserequest';
              delete from purchaserequest pr where pr.purchaserequest_id = poly.purchaserequest_id;
            end;
          end loop; --poly
        end;
      end loop; --polx
    end createposleftover;

  begin
    --see chapter 2.11.4.1  Create PO object based on split criteria
    gv_fininterfacepos := fp_hasfininterfacepos;
    --createpos; Process to Purchase Orders waiting for Approval
    gv_message := 'stockroom id ' || nvl(to_char(fp_stockroomid), 'NULL');
    select sr.* into lv_rec_stockroom from stockroom sr where sr.stockroom_id = fp_stockroomid;
    --get_stockroom_splitcriteria
    get_stockroom_splitcriteria;
    --createpos4workorder
    createpos4workorder;
    --createposleftover
    createposleftover;
    --commit
    commit;
  exception
    when ge_user___exception then
      begin
        rollback;
        write_log('createpos. ' || gv_message, 3, fp_systemuserid);
      end;

    when no_data_found then
      begin
        rollback;
        write_log('createpos. No data found ' || gv_message, 3, fp_systemuserid);
      end;

    when others then
      begin
        rollback;
        write_log('createpos. Error others ' || gv_message || ' ' || sqlerrm, 3, fp_systemuserid);
      end;

  end createpos;

begin
  initialize;
exception
  when others then
    begin
      rollback;
      write_log(gv_message || ' ' || sqlerrm, 5, 0);
    end;

end pack_posplit;
/
create or replace package pack_price is
  /* ------------------------------------------------------------------------------------------------
   Package pack_price version 1.00
  /* ---------------------------------------------------------------------------------------------- */
  /*
    18/11/2009 (502831) HVH New developed.
    08/01/2010          HVH Issue fixed with rent price for changes per week.
                            When exact# of changes was passed for size <> * in some cases wrong price was returned
    12/02/2010          HVH Added Weight Price and Weight Discount
    19/02/2010          HVH Added Rent and Wash Discount + performance improvement on all price search proc's
    22/03/2011          SSB Added Special Charge functions
    29/04/2011          HVH Improved Special Charge procedure and extended return string of SpecialCharge_Details
    21/11/2012          SSB Added Residential Rent functions
    13/02/2013          HVH Added Wash_Price_PT for washprices with specific pricetype (i.e. heavy soil)
                            Also added Loan_Price functions.
    01/03/2013          PVD Update for unrelated loan and changes before for general price determination
    17/09/2013          RVI Update for under/overuse wash prices
    25/02/2014          HVH Return replacement price when inventorybillingtype = 5
    27/02/2016          HVH Extended pricelistcode from 6 to 15 chars in xxx_price_details functions
    4/08/2017           DLA Updated for size billing group
    11/01/2018          DLA Fix for size billing group
    15/01/2018          SSB Fix for UK weekly underuse method
    19/05/2021          DLA ABS-117421 Size billing group NULL causing issues with display and invoicing
    19/08/2021          APA ABS-119993 Customer coefficient for replacement price
    13/09/2021          ABS-123845 PACK_PRICE call takes alot of time and get stuck
    16/11/2021          LAC ABS-118827 Replacement price for loss for pool with BM4 is not calculated
    21-01-2022          ABS-130035 Replacement price, redone for, Bill Loss Now Global Loss Price
    08/03/2022          ABS-130035 besides replacement price now also wash price calculated in right way
    10/03/2022          ABS-130035 besides replacement/wash price now also rent price calculated in right way
    15/03/2022          ABS-130035 besides replacement/wash/rent price now also sales price recalculated
    25/03/2022          ABS-129982 add washprice for BM1
    20/12/2022          ABS-144248 Pack_price_new is significantly slower than original pack_price
    20/12/2022          ABS-150058 Pack Price - pulling 0 percent for percentage special charge
    05/09/2023          ABS-155463 Change behaviour of startdate in pack_price
    02/10/2023          ABS-156508 pack_price add bgprotectionprice
    15/04/2024          ABS-163459 improve speed pack_price
    16/04/2024          ABS-164010 Pack_Price Oracle fix
    20/06/2024          ABS-164379 Special size group prices not shown in PLPC or Contract Product
    28/05/2024          ABS-165202 Restriction in Pack_Price on max prices of 99999
  */

  /* ----------------------------------------------------------------------------------------------
  /* General remarks Rent price procedures/functions.

     This procedure and functions return the rent price (and other price details) for a given
     customer, product, size and finishingmethod, that is valid on the date that is passed in the
     parameter pricedate. If this optional parameter is omited, it will return the price valid on the sysdate.

     The procedure and functions can be used in 2 ways:
     a) To retrieve a price for a product list per customer line.
        (so without a specific # of changes or specific delivery frequency)
        For this purpose omit, or pass 0 to chgperwk_or_freq parameter.
        It will try to find the most recent valid price for any number of changes or any frequency.

     b) To retrieve a price for a product with a specific # of changes or specific delivery frequency.
        For this purpose pass a value <> 0 to chgperwk_or_freq parameter.
        For garments with billingmethod 1 a specific number of changes can be passed.
        If there is no price defined for that specific number of changes, it will try
        to find the price for number of changes *
        For delivery frequency based pricing it is possible to pass a specific frequency.
        The frequency is defined in # of weeks:
        Example: for delivery scheme EOW (Every other week) frequency = 2. (weekly=1)
  */

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Rent_Price_Details

    This is the base procedure used by the Rent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure get_rent_price_details(fp_customerid             in customer.customer_id%type,
                                   fp_productid              in product.product_id%type,
                                   fp_sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate              in pricelistpercustomer.dateactive%type,
                                   fp_chgperwk_or_freq       in generalrentprice.changesperweek%type,
                                   fp_price                  out customerrentprice.price%type,
                                   fp_price_found_yn         out varchar2,
                                   fp_price_start_date       out customerrentprice.startdate%type,
                                   fp_result_code            out number,
                                   fp_result_desc            out varchar2,
                                   fp_price_list_type        out varchar2,
                                   fp_price_list_code        out generalpricelist.code%type,
                                   fp_price_list_desc        out generalpricelist.description%type,
                                   fp_changesperwkfoundprice out customerrentprice.changesperweek%type,
                                   fp_price_type_code        out customerrentprice.typeofrent%type,
                                   fp_price_type_desc        out varchar2,
                                   fp_inv_freq_code          out customerrentprice.invoicefrequencynumber%type,
                                   fp_inv_freq_desc          out varchar2,
                                   fp_customerrentpriceid    out customerrentprice.customerrentprice_id%type);

  /* ----------------------------------------------------------------------------------------------
    Function Rent_Price_Details

    Returns all price details, like procedure Get_Rent_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181       ( 1): invoice freq code
    pos 182 - 191 (10): invoice freq description
    pos 192 - 201 (10): found price is defined for this number of changes per week
    pos 202 - 210 ( 9): price list code part 2 char 7-15
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    Y 1     Multiple prices applicable for different # of changes.
    Y 2     Multiple prices applicable for different frequencies.
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method with wash price only
    N 3     Price not relevant, billing method = 4 piece rate only
    N 4     Price not relevant, defined on wearer level as wearer total price.
    N 5     Price not relevant, defined at wearer function level
    N 8     Error in parameters
    N 9     ORA Error
  */
  function rent_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return varchar2
    parallel_enable;

  /* ----------------------------------------------------------------------------------------------
     Function Rent_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function rent_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function CustomerRent_PriceID
     Use this function in calculations. It will return customer rent price id determined in Get_Rent_price_Details procedure.
  */
  function customerrent_priceid(customerid        in customer.customer_id%type,
                                productid         in product.product_id%type,
                                sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                finishingmethodid in finishingmethod.finishingmethod_id%type,
                                pricedate         in pricelistpercustomer.dateactive%type default null,
                                chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function Rent_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function rent_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;

  /* ---------------------------------------------------------------------------------------------- */
  /* General remarks Wash price procedures/functions.

     This procedure and functions return the wash price (and other price details) for a given
     customer, product, size and finishingmethod, that is valid on the date that is passed in the
     parameter pricedate. If this optional parameter is omited, it will return the price valid on the sysdate.

     The procedure and functions can be used in 2 ways:
     a) To retrieve a price for a product list per customer line.
        (so without indication if the price is for a LOG (Laundry Owned Goods) or COG (Customer Owned Goods) item)
        For this purpose omit, or pass 0 to pricetype parameter.
        It will try to find the most recent valid price for any number of changes or any frequency.

     b) To retrieve a price for a product for which it is known if it is a LOG or COG item.
        Pass 1 for LOG, pass 2 for COG to parameter pricetype

     c) To retrieve a price for a product for for a specific known price type (PT) use the Wash_Price_PT functions
        For example for price type Heavy Soil. Possible price types are described under Get_Wash_Price_Details_PT

  */

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Wash_Price_Details

    This is the base procedure used by the Wash_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */

  procedure get_wash_price_details(fp_customerid        in customer.customer_id%type,
                                   fp_productid         in product.product_id%type,
                                   fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate         in pricelistpercustomer.dateactive%type,
                                   fp_pricetype         in number, -- 0=all, 1=LOG, 2=COG
                                   fp_price             out customerwashprice.price%type,
                                   fp_price_found_yn    out varchar2,
                                   fp_price_start_date  out customerwashprice.startdate%type,
                                   fp_result_code       out number,
                                   fp_result_desc       out varchar2,
                                   fp_price_list_type   out varchar2,
                                   fp_price_list_code   out generalpricelist.code%type,
                                   fp_price_list_desc   out generalpricelist.description%type,
                                   fp_price_type_code   out customerwashprice.pricetype%type,
                                   fp_price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Price_Details

    Returns all price details, like procedure Get_Wash_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 189 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    Y 1     Distinct prices can be applicable LOG and COG
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method 3 with rent price only
    N 3     Price not relevant, billing method = 1 flat rated rent
    N 4     Price not relevant, billing method = 2 rent based on minimum
    N 5     Price not relevant, disposable / sales only item
    N 6     Price not relevant, billing method = 4 with price for LOG only
    N 7     Price not relevant, billing method = 4 with price for COG only
    N 8     Error in parameters
    N 9     ORA Error
  */
  function wash_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return varchar2
    parallel_enable;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function wash_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      pricetype         in number default 0) return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function wash_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Wash_Price_Details_PT

    This is the base procedure used by the Wash_Price_PT functions.
    This procedure can be used to know all details about a wash price for a specified price type (PT)

    Possible price types are:
    1 = All items
    2 = COG items only
    3 = Price on client delivery note
    4 = Wash part of Split price
    5 = Heavy Soil
  */

  procedure get_wash_price_details_pt(customerid        in customer.customer_id%type,
                                      productid         in product.product_id%type,
                                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                                      pricedate         in pricelistpercustomer.dateactive%type,
                                      pricetype         in number,
                                      price             out customerwashprice.price%type,
                                      price_found_yn    out varchar2,
                                      price_start_date  out customerwashprice.startdate%type,
                                      result_code       out number,
                                      result_desc       out varchar2,
                                      price_list_type   out varchar2,
                                      price_list_code   out generalpricelist.code%type,
                                      price_list_desc   out generalpricelist.description%type,
                                      price_type_code   out customerwashprice.pricetype%type,
                                      price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Price_Details_PT

    Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
    Returns all price details, like procedure Get_Wash_Price_Details_PT,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 189 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function wash_price_details_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_PT
     Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function wash_price_pt(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         pricedate         in pricelistpercustomer.dateactive%type default null,
                         pricetype         in number) return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_Display_PT
     Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function wash_price_display_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return number;

  /* ----------------------------------------------------------------------------------------------
     Procedure Get_Replacement_Price_Details

     This is the base procedure used by the Replacement_PriceXXX functions.
     This procedure can be used to know all details about a price.
  */
  procedure get_replacement_price_details(fp_customerid        in customer.customer_id%type,
                                          fp_productid         in product.product_id%type,
                                          fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                          fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                          fp_pricedate         in pricelistpercustomer.dateactive%type,
                                          fp_price             out customerreplacementprice.price%type,
                                          fp_price_found_yn    out varchar2,
                                          fp_price_start_date  out customerreplacementprice.startdate%type,
                                          fp_result_code       out number,
                                          fp_result_desc       out varchar2,
                                          fp_price_list_type   out varchar2,
                                          fp_price_list_code   out generalpricelist.code%type,
                                          fp_price_list_desc   out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Replacement_Price_Details

    Returns all price details, like procedure Get_Replacement_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method = 4 piece rate only
    N 3     Price not relevant, disposable / sales only item
    N 8     Error in parameters
    N 9     ORA Error
  */
  function replacement_price_details(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Replacement_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function replacement_price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Replacement_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function replacement_price_display(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Procedure Get_Sales_Price_Details

     This is the base procedure used by the Sales_PriceXXX functions.
     This procedure can be used to know all details about a price.
  */
  procedure get_sales_price_details(fp_customerid       in customer.customer_id%type,
                                    fp_productid        in product.product_id%type,
                                    fp_sizedefinitionid in sizedefinition.sizedefinition_id%type,
                                    fp_pricedate        in pricelistpercustomer.dateactive%type,
                                    fp_price            out customersalesprice.price%type,
                                    fp_price_found_yn   out varchar2,
                                    fp_price_start_date out customersalesprice.startdate%type,
                                    fp_result_code      out number,
                                    fp_result_desc      out varchar2,
                                    fp_price_list_type  out varchar2,
                                    fp_price_list_code  out generalpricelist.code%type,
                                    fp_price_list_desc  out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Sales_Price_Details

    Returns all price details, like procedure Get_Sales_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function sales_price_details(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Sales_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function sales_price(customerid       in customer.customer_id%type,
                       productid        in product.product_id%type,
                       sizedefinitionid in sizedefinition.sizedefinition_id%type,
                       pricedate        in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Sales_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function sales_price_display(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_price_details(customerid         in customer.customer_id%type,
                                     weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                     soil_yn            in customerweightprice.soil%type,
                                     pricedate          in pricelistpercustomer.dateactive%type,
                                     price              out customerweightprice.price%type,
                                     price_found_yn     out varchar2,
                                     price_start_date   out customerweightprice.startdate%type,
                                     result_code        out number,
                                     result_desc        out varchar2,
                                     price_list_type    out varchar2,
                                     price_list_code    out generalpricelist.code%type,
                                     price_list_desc    out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Weight_Price_Details

    Returns all price details, like procedure Get_Weight_Price_Details,
    This function returns them all concatenated in a fixed length return string.
    Parameter soil_yn should be populated with 'Y' for soil weight price or 'N' for clean weight price.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, weights not invoiced
    N 3     Price not defined, weights invoiced soil, not clean
    N 4     Price not defined, weights invoiced clean, not soil
    N 8     Error in parameters
    N 9     ORA Error
  */

  function weight_price_details(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function weight_price(customerid         in customer.customer_id%type,
                        weighingcategoryid in weighingcategory.weighingcategory_id%type,
                        soil_yn            in customerweightprice.soil%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function weight_price_display(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_speccharge_details(customerid        in customer.customer_id%type,
                                   specialchargeid   in specialcharge.specialcharge_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerspecialchargeprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerspecialchargeprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type,
                                   specialchargecode out specialcharge.code%type,
                                   percentage        out customerspecialchargeprice.percentage%type,
                                   minimumamount     out specialcharge.minimumamount%type,
                                   maximumamount     out specialcharge.maximumamount%type);

  /* ----------------------------------------------------------------------------------------------
    Function SpecialCharge_Details

    Returns all price details, like procedure Get_SpecialCharge_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price format: 99999.99999 ,  spaces when no price found or not applicable.
    pos  13       ( 1): price or percentage returned Y / N
    pos  14 - 21  ( 8): price or percentage start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, B=Base table price, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69 - 74  ( 6): special charge code
    pos  75       ( 1): price result code , see list below.
    pos  76 - 155 (80): price result description
    pos 156 - 162 ( 7): percentage fromat: 999.99, spaces when not found or not applicable.
    pos 163 - 172 (10): minimum amount fromat: 999999.99, spaces when not found or not applicable.
    pos 173 - 182 (10): maximum amount fromat: 999999.99, spaces when not found or not applicable.
    pos 183 - 191 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price or percentage found, no remark
    N 1     Price or percentage not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */

  function specialcharge_details(customerid      in customer.customer_id%type,
                                 specialchargeid in specialcharge.specialcharge_id%type,
                                 pricedate       in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function specialcharge_price(customerid      in customer.customer_id%type,
                               specialchargeid in specialcharge.specialcharge_id%type,
                               pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function specialcharge_price_display(customerid      in customer.customer_id%type,
                                       specialchargeid in specialcharge.specialcharge_id%type,
                                       pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Percentage
     Use this function in calculations. It will return percentage 0.00 in case the percentage could not be found.
  */
  function specialcharge_percentage(customerid      in customer.customer_id%type,
                                    specialchargeid in specialcharge.specialcharge_id%type,
                                    pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Perc_Display
     Use this function for display or print purposes. It will return null in case the percentage could not be found.
  */
  function specialcharge_percentage_disp(customerid      in customer.customer_id%type,
                                         specialchargeid in specialcharge.specialcharge_id%type,
                                         pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MinAmount
     Use this function in calculations. It will return MinAmount 0.00 in case the MinAmount could not be found.
  */
  function specialcharge_minamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MinAmount_Disp
     Use this function for display or print purposes. It will return null in case the MinAmount could not be found.
  */
  function specialcharge_minamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MaxAmount
     Use this function in calculations. It will return MaxAmount 0.00 in case the MaxAmount could not be found.
  */
  function specialcharge_maxamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MaxAmount_Disp
     Use this function for display or print purposes. It will return null in case the MaxAmount could not be found.
  */
  function specialcharge_maxamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_rent_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerrentdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerrentdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Rent_Discount_Details

    Returns all Discount details, like procedure Get_Rent_Discount_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description

    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, billing method with wash price only
    N 3     Discount not relevant, billing method = 4 piece rate only
    N 4     Discount not applicable, price defined on wearer level as wearer total price.
    N 5     Discount not applicable, price defined at wearer function level
    N 8     Discount in parameters
    N 9     ORA Error
  */

  function rent_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */

  function rent_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */

  function rent_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerwashdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerwashdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Discount_Details

    Returns all Discount details, like procedure Get_Wash_Discount_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description

    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, billing method 3 with rent price only
    N 3     Discount not defined, billing method = 1 flat rated rent
    N 4     Discount not defined, billing method = 2 rent based on minimum
    N 5     Discount not relevant, disposable / sales only item
    N 8     Error in parameters
    N 9     ORA Error
  */

  function wash_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */

  function wash_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */

  function wash_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_discount_details(customerid          in customer.customer_id%type,
                                        weighingcategoryid  in weighingcategory.weighingcategory_id%type,
                                        soil_yn             in customerweightdiscount.soil%type,
                                        discountdate        in discountlistpercustomer.dateactive%type,
                                        discount            out customerweightdiscount.discount%type,
                                        discount_found_yn   out varchar2,
                                        discount_start_date out customerweightdiscount.startdate%type,
                                        result_code         out number,
                                        result_desc         out varchar2,
                                        discount_list_type  out varchar2,
                                        discount_list_code  out generaldiscountlist.code%type,
                                        discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Weight_Discount_Details

    Returns all Discount details, like procedure Get_Weight_Discount_Details,
    This function returns them all concatenated in a fixed length return string.
    Parameter soil_yn should be populated with 'Y' for soil weight Discount or 'N' for clean weight Discount.

    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description

    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, weights not invoiced
    N 3     Discount not defined, weights invoiced soil, not clean
    N 4     Discount not defined, weights invoiced clean, not soil
    N 8     Error in parameters
    N 9     ORA Error
  */

  function weight_discount_details(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */
  function weight_discount(customerid         in customer.customer_id%type,
                           weighingcategoryid in weighingcategory.weighingcategory_id%type,
                           soil_yn            in customerweightdiscount.soil%type,
                           discountdate       in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */
  function weight_discount_display(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_ResidentialRent_Price_Details

    This is the base procedure used by the ResidentialRent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure get_residrent_price_details(customerid        in customer.customer_id%type,
                                        productid         in product.product_id%type,
                                        sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                        finishingmethodid in finishingmethod.finishingmethod_id%type,
                                        pricedate         in pricelistpercustomer.dateactive%type,
                                        price             out customerrentprice.price%type,
                                        price_found_yn    out varchar2,
                                        price_start_date  out customerrentprice.startdate%type,
                                        result_code       out number,
                                        result_desc       out varchar2,
                                        price_list_type   out varchar2,
                                        price_list_code   out generalpricelist.code%type,
                                        price_list_desc   out generalpricelist.description%type,
                                        price_type_code   out customerrentprice.typeofrent%type,
                                        price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function ResidentialRent_Price_Details

    Returns all price details, like procedure Get_ResidentialRent_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 190 (10): found price is defined for this number of changes per week
    pos 191 - 199 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method with wash price only
    N 3     Price not relevant, billing method = 4 piece rate only
    N 4     Price not relevant, defined on wearer level as wearer total price.
    N 5     Price not relevant, defined at wearer function level
    N 8     Error in parameters
    N 9     ORA Error
  */
  function residentialrent_price_details(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function ResidentialRent_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function residentialrent_price(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function ResidentialRent_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function residentialrent_price_display(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Loan_Price_Details

    This is the base procedure used by the Rent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure get_loan_price_details(customerid        in customer.customer_id%type,
                                   productid         in product.product_id%type,
                                   sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerrentprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerrentprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Loan_Price_Details

    Returns all price details, like procedure Get_Loan_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function loan_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Loan_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function loan_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Loan_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function loan_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Budget_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function budget_price(fpcustomerid    customerbudgetdefinition.customer_id%type,
                        fpcode          customerbudgetdefinition.code%type,
                        fpreferencedate date) return number;
  /*--------------------------------------------------------------------------------------------------------*\
  Function get_budgetprotectionprice

  Values for fp_pricecomponent are
    1 = Garment Maintenance Protection (GMP)
    2 = Garment Setup Protection (GSP)
    3 = Garment Loss Protection (GLP)
    4 = Garment Repair Protection (GRP)
    5 = Merchandise Buyout Protection (MBYOP)
    6 = Garment Emblem Protection (GEP)
  \*--------------------------------------------------------------------------------------------------------*/
  function budgetprotectionprice(fp_customerid        in customer.customer_id%type,
                                 fp_productid         in product.product_id%type,
                                 fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 fp_pricecomponent    in customerbgprotectionprice.pricecomponent%type,
                                 fp_pricedate         in pricelistpercustomer.dateactive%type default trunc(sysdate))
    return number;

  function budgetprotectionprice_details(fp_customerid        in customer.customer_id%type,
                                         fp_productid         in product.product_id%type,
                                         fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         fp_pricecomponent    in customerbgprotectionprice.pricecomponent%type,
                                         fp_pricedate         in pricelistpercustomer.dateactive%type default trunc(sysdate))
    return varchar2;
  /*-----General functions that can be used------------------------------------------------------------------*/
  function customer_uses_specialprices(customerid in customer.customer_id%type) return boolean;
  function get_standard_szbillinggroup return number;
  function get_product_size_billinggroup(productid in product.product_id%type,
                                         sizeid    in sizedefinition.sizedefinition_id%type)
    return number;
  procedure get_size_billing_groups(customerid                     in customer.customer_id%type,
                                    productid                      in product.product_id%type,
                                    sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                    pricetype                      number,
                                    lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                    lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type);
end pack_price;
/
create or replace package body pack_price is
  --Global variable
  gv_decimals number(1);
  gv_pricestr varchar2(12);
  /*--------------------------------------------------------------------------------------------------------*/
  --internal functions/procedures
  procedure get_pricestr is
    pragma udf;
  begin
    case nvl(gv_decimals, 4)
      when 4 then
        gv_pricestr := '999999D9999';
      when 3 then
        gv_pricestr := '9999999D999';
      when 2 then
        gv_pricestr := '99999999D99';
      when 1 then
        gv_pricestr := '999999999D9';
      else
        gv_pricestr := '999999D9999';
    end case;
  end get_pricestr;

  function getsizestarid return number is
    pragma udf;
    lv_sizestarid number;
  begin
    select sd.sizedefinition_id into lv_sizestarid from sizedefinition sd where sd.code = '*';
    return lv_sizestarid;
  exception
    when no_data_found then
      return null;
  end getsizestarid;

  function get_product_size_billinggroup(productid in product.product_id%type,
                                         sizeid    in sizedefinition.sizedefinition_id%type)
    return number is
    pragma udf;
    sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
  begin
    select ps.sizebillinggroup_id
    into   sizebillinggroupid
    from   productsize ps
    where  ps.product_id = productid
    and    ps.sizedefinition_id = sizeid;

    if (sizebillinggroupid is null) then
      begin
        select sb.sizebillinggroup_id
        into   sizebillinggroupid
        from   sizebillinggroup sb
        where  sb.standard = 'Y'
        and    exists (select 1
                from   sizebillgroupperprodgroup sbp
                join   productgroup pg
                on     sbp.productgroup_id = pg.productgroup_id
                join   product p
                on     pg.productgroup_id = p.productgroup_id
                where  p.product_id = productid);
      exception
        when no_data_found then
          sizebillinggroupid := 0;
      end;
    end if;
    return sizebillinggroupid;
  exception
    when no_data_found then
      sizebillinggroupid := 0;
      return sizebillinggroupid;
  end get_product_size_billinggroup;

  procedure get_size_billing_groups2(customerid                     in customer.customer_id%type,
                                     productid                      in product.product_id%type,
                                     sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                     pricetype                      number,
                                     lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                     lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type) is
    pragma udf;
    lv_customer_uses_sz_billing    boolean;
    lv_ss_sizespecialchargeoptions int;
    lv_is_special_size_price_used  boolean;
  begin
    begin
      select value
      into   lv_ss_sizespecialchargeoptions
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'SIZESPECIALCHARGEOPTIONS'
      and    c.customer_id = customerid;
    exception
      when no_data_found then
        lv_ss_sizespecialchargeoptions := 0;
    end;
    if lv_ss_sizespecialchargeoptions <> 0 then
      begin
        if pricetype = 2 then
          lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 1 or
                                           lv_ss_sizespecialchargeoptions = 4 or
                                           lv_ss_sizespecialchargeoptions = 5 or
                                           lv_ss_sizespecialchargeoptions = 7;
        end if;
        if pricetype = 3 then
          lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 3 or
                                           lv_ss_sizespecialchargeoptions = 5 or
                                           lv_ss_sizespecialchargeoptions = 6 or
                                           lv_ss_sizespecialchargeoptions = 7;
        end if;
        if pricetype = 4 then
          lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 2 or
                                           lv_ss_sizespecialchargeoptions = 4 or
                                           lv_ss_sizespecialchargeoptions = 6 or
                                           lv_ss_sizespecialchargeoptions = 7;
        end if;
        --when used first exact, then standard then NULL (0)
        lv_customer_uses_sz_billing    := customer_uses_specialprices(customerid);
        lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
        if lv_customer_uses_sz_billing and lv_is_special_size_price_used then
          lv_specific_sizebillinggroupid := get_product_size_billinggroup(productid,
                                                                          sizedefinitionid);

          if lv_specific_sizebillinggroupid = 0 then
            lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
          end if;
        else
          lv_specific_sizebillinggroupid := 0;
        end if;
      end;
    else
      begin
        --when not used first NULL (0) then standard billinggroup
        lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
        lv_specific_sizebillinggroupid := 0;
      end;
    end if;
  end get_size_billing_groups2;
  --
  procedure get_plpc_info(fp_customerid                  in number,
                          fp_productid                   in number,
                          fp_sizeid                      in number,
                          fp_sizestarid                  in number,
                          fp_finishingmethodid           in number,
                          fp_date                        in out date,
                          fp_plpcid                      out number,
                          fp_billingmethod               out number,
                          fp_inventorybillingtype        out number,
                          fp_chargelossforpool           out varchar2,
                          fp_priceusage                  out number,
                          fp_tom                         out number,
                          fp_garmentrentspecification    out number,
                          fp_businessunitid              out number,
                          fp_chargewashesonlyforcog      out productlistpercustomer.chargewashesonlyforcog%type,
                          fp_minimumturnaround           out productlistpercustomer.minimumturnaround%type,
                          fp_rentpriceperfrequency       out productlistpercustomer.rentpriceperfrequency%type,
                          fp_invoicefreqrelatedrentprice out productlistpercustomer.invoicefreqrelatedrentprice%type,
                          fp_splitinvoicesperactivity    out customer.splitinvoicesperactivity%type,
                          fp_productgroupid              out productgroup.productgroup_id%type) is
    pragma udf;

    procedure lookup_plpc is
    begin
      --lookup_plpc
      select /*+index(l XAK3PRODUCTLISTPERCUSTOMER)*/
       l.productlistpercustomer_id, l.billingmethod, l.inventorybillingtype, l.chargelossforpool,
       l.priceusage, p.typeofmerchandise, c.garmentrentspecification, c.defaultbusinessunit_id,
       l.chargewashesonlyforcog, l.minimumturnaround, l.rentpriceperfrequency,
       l.invoicefreqrelatedrentprice, c.splitinvoicesperactivity, p.productgroup_id, cur.decimals
      into   fp_plpcid, fp_billingmethod, fp_inventorybillingtype, fp_chargelossforpool,
             fp_priceusage, fp_tom, fp_garmentrentspecification, fp_businessunitid,
             fp_chargewashesonlyforcog, fp_minimumturnaround, fp_rentpriceperfrequency,
             fp_invoicefreqrelatedrentprice, fp_splitinvoicesperactivity, fp_productgroupid,
             gv_decimals
      from   productlistpercustomer l
      join   product p
      on     p.product_id = l.product_id
      join   customer c
      on     c.customer_id = l.customer_id
      join   currency cur
      on     cur.currency_id = c.currency_id
      where  l.customer_id = fp_customerid
      and    l.product_id = fp_productid
      and    l.sizedefinition_id = fp_sizeid
      and    l.finishingmethod_id = fp_finishingmethodid
      and    (fp_date >= l.dateactive and fp_date <= l.dateinactive);
    exception
      when no_data_found then
        begin
          --search size star
          select /*+index(l XAK3PRODUCTLISTPERCUSTOMER)*/
           l.productlistpercustomer_id, l.billingmethod, l.inventorybillingtype, l.chargelossforpool,
           l.priceusage, p.typeofmerchandise, c.garmentrentspecification, c.defaultbusinessunit_id,
           l.chargewashesonlyforcog, l.minimumturnaround, l.rentpriceperfrequency,
           l.invoicefreqrelatedrentprice, c.splitinvoicesperactivity, p.productgroup_id,
           cur.decimals
          into   fp_plpcid, fp_billingmethod, fp_inventorybillingtype, fp_chargelossforpool,
                 fp_priceusage, fp_tom, fp_garmentrentspecification, fp_businessunitid,
                 fp_chargewashesonlyforcog, fp_minimumturnaround, fp_rentpriceperfrequency,
                 fp_invoicefreqrelatedrentprice, fp_splitinvoicesperactivity, fp_productgroupid,
                 gv_decimals
          from   productlistpercustomer l
          join   product p
          on     p.product_id = l.product_id
          join   customer c
          on     c.customer_id = l.customer_id
          join   currency cur
          on     cur.currency_id = c.currency_id
          where  l.customer_id = fp_customerid
          and    l.product_id = fp_productid
          and    l.sizedefinition_id = fp_sizestarid
          and    l.finishingmethod_id = fp_finishingmethodid
          and    (fp_date >= l.dateactive and fp_date <= l.dateinactive);
        exception
          when no_data_found then
            begin
              --no data found
              fp_plpcid                      := null;
              fp_billingmethod               := null;
              fp_inventorybillingtype        := null;
              fp_chargelossforpool           := null;
              fp_priceusage                  := null;
              fp_tom                         := null;
              fp_garmentrentspecification    := null;
              fp_businessunitid              := null;
              fp_chargewashesonlyforcog      := null;
              fp_minimumturnaround           := null;
              fp_rentpriceperfrequency       := null;
              fp_invoicefreqrelatedrentprice := null;
              fp_splitinvoicesperactivity    := null;
              fp_productgroupid              := null;
              gv_decimals                    := null;
            end;
        end;
    end lookup_plpc;
  begin
    fp_date := nvl(fp_date, trunc(sysdate));
    --get_plpc_info
    lookup_plpc;
  end get_plpc_info;
  /*--------------------------------------------------------------------------------------------------------*/

  procedure get_rent_price_details(fp_customerid             in customer.customer_id%type,
                                   fp_productid              in product.product_id%type,
                                   fp_sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate              in pricelistpercustomer.dateactive%type,
                                   fp_chgperwk_or_freq       in generalrentprice.changesperweek%type,
                                   fp_price                  out customerrentprice.price%type,
                                   fp_price_found_yn         out varchar2,
                                   fp_price_start_date       out customerrentprice.startdate%type,
                                   fp_result_code            out number,
                                   fp_result_desc            out varchar2,
                                   fp_price_list_type        out varchar2,
                                   fp_price_list_code        out generalpricelist.code%type,
                                   fp_price_list_desc        out generalpricelist.description%type,
                                   fp_changesperwkfoundprice out customerrentprice.changesperweek%type,
                                   fp_price_type_code        out customerrentprice.typeofrent%type,
                                   fp_price_type_desc        out varchar2,
                                   fp_inv_freq_code          out customerrentprice.invoicefrequencynumber%type,
                                   fp_inv_freq_desc          out varchar2,
                                   fp_customerrentpriceid    out customerrentprice.customerrentprice_id%type) is
    pragma udf;
    --locale variables
    lv_databasecode                        databasesettings.code%type;
    lv_pricedate                           date;
    lv_plpcid                              number;
    lv_billingmethod                       number;
    lv_inventorybillingtype                number;
    lv_chargelossforpool                   varchar2(1);
    lv_priceusage                          number;
    lv_tom                                 number;
    lv_garmentrentspecification            number;
    lv_sizestarid                          sizedefinition.sizedefinition_id%type;
    lv_businessunitid                      number;
    lv_underuse_count                      number := 0;
    lv_typeofrent                          customerrentprice.typeofrent%type;
    lv_chargewashesonlyforcog              productlistpercustomer.chargewashesonlyforcog%type;
    lv_minimumturnaround                   productlistpercustomer.minimumturnaround%type;
    lv_standard_sizebillinggroupid         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizebillinggroupid         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizebillinggroupid sizebillinggroup.systemuser_id%type;
    lv_rentpriceperfrequency               productlistpercustomer.rentpriceperfrequency%type;
    lv_invoicefreqrelatedrentprice         productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_changesperweek                      customerrentprice.changesperweek%type;
    lv_splitinvoicesperactivity            customer.splitinvoicesperactivity%type;
    lv_invoice_freq                        customerrentprice.invoicefrequencynumber%type;
    lv_productgroupid                      product.productgroup_id%type;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'Y1',
                     'Multiple prices can be applicable for different # of changes', 'Y2',
                     'Multiple prices can be applicable for different frequencies', 'N1',
                     'Price not defined', 'N2',
                     'Price not relevant, billing method 3 with wash price only', 'N3',
                     'Price not relevant, billing method = 4 piece rate only', 'N4',
                     'Price not relevant, defined at wearer level as wearer total price', 'N5',
                     'Price not relevant, defined at wearer function level', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end decode_error;

    function decode_inv_freq(fpfreq_code in varchar2) return varchar2 is
    begin
      case fpfreq_code
        when '40' then
          return('4 Weekly');
        when '110' then
          return('Monthly');
        else
          return('Weekly');
      end case;
    end decode_inv_freq;

    function decode_type_of_rent(fptypeofrent in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fptypeofrent, 1, 'Price per Piece', 2, 'Changes per Week', 3, 'Overuse Price', 4,
                     'Frequency Based Price', 5, 'Underuse Price', 6, 'Lease Price', 7, 'Split Price',
                     8, 'Price per Invoice Freq.', 'Unknown type of rent')
      into   r
      from   dual;
      return r;
    end decode_type_of_rent;

    procedure initialize is
    begin
      --initialize
      lv_pricedate       := fp_pricedate;
      fp_price_found_yn  := 'N';
      fp_price_list_type := 2;
      lv_invoice_freq    := 10; -- default is weekly
      lv_sizestarid      := getsizestarid;
      lv_changesperweek  := fp_chgperwk_or_freq;
      --get_plpc_info
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
      --
      get_size_billing_groups2(fp_customerid, fp_productid, fp_sizedefinitionid, 3,
                               lv_standard_sizebillinggroupid,
                               lv_initial_specific_sizebillinggroupid);
      --get db code
      select db.code into lv_databasecode from databasesettings db;
    end initialize;

    procedure lookforprice is
      lv_priceliststartdate date;

      procedure get_generalrentprice(fp_generalpricelistid in number,
                                     fp_sizeid             in number,
                                     fp_changesperweek     in number) is
      begin
        if fp_changesperweek = 0 then
          begin
            --get general rent price, no check changes per week
            for y in (select grp.price price, grp.startdate, g.code, g.description,
                             grp.changesperweek
                      from   generalrentprice grp
                      join   generalpricelist g
                      on     g.generalpricelist_id = grp.generalpricelist_id
                      where  g.pricetype = 2 -- rent price
                      and    grp.typeofrent = lv_typeofrent
                      and    g.active = 'Y'
                      and    g.generalpricelist_id = fp_generalpricelistid
                      and    grp.product_id = fp_productid
                      and    grp.sizedefinition_id = fp_sizeid
                      and    grp.finishingmethod_id = fp_finishingmethodid
                      and    grp.startdate <= lv_pricedate
                      and    (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by grp.startdate desc, grp.changesperweek asc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := y.price;
                fp_price_start_date       := greatest(lv_priceliststartdate, y.startdate);
                fp_price_list_type        := 'G'; -- general
                fp_price_list_code        := y.code;
                fp_price_list_desc        := y.description;
                fp_changesperwkfoundprice := y.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        else
          begin
            --get general rent price, check changes per week
            for y in (select grp.price price, grp.startdate, g.code, g.description,
                             grp.changesperweek
                      from   generalrentprice grp
                      join   generalpricelist g
                      on     g.generalpricelist_id = grp.generalpricelist_id
                      where  g.pricetype = 2 -- rent price
                      and    grp.typeofrent = lv_typeofrent
                      and    g.active = 'Y'
                      and    g.generalpricelist_id = fp_generalpricelistid
                      and    grp.product_id = fp_productid
                      and    grp.sizedefinition_id = fp_sizeid
                      and    grp.finishingmethod_id = fp_finishingmethodid
                      and    (grp.changesperweek = lv_changesperweek or grp.changesperweek = -1)
                      and    grp.startdate <= lv_pricedate
                      and    (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by grp.startdate desc, grp.changesperweek desc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := y.price;
                fp_price_start_date       := greatest(lv_priceliststartdate, y.startdate);
                fp_price_list_type        := 'G'; -- general
                fp_price_list_code        := y.code;
                fp_price_list_desc        := y.description;
                fp_changesperwkfoundprice := y.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        end if;
      end get_generalrentprice;

      procedure get_customerentprice(fp_changesperweek in number) is
      begin
        if fp_changesperweek = 0 then
          begin
            --get customer rent price, no check changes per week
            for z in (select curp.price, curp.startdate, curp.customerrentprice_id,
                             curp.changesperweek
                      from   customerrentprice curp
                      where  curp.productlistpercustomer_id = lv_plpcid
                      and    curp.typeofrent = lv_typeofrent
                      and    curp.startdate <= lv_pricedate
                      and    (curp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(curp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by curp.startdate desc, curp.changesperweek asc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := z.price;
                fp_price_start_date       := greatest(lv_priceliststartdate, z.startdate);
                fp_price_list_type        := 'C'; -- customer specific
                fp_price_list_code        := null;
                fp_price_list_desc        := 'Customer Specific.';
                fp_customerrentpriceid    := z.customerrentprice_id;
                fp_changesperwkfoundprice := z.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        else
          begin
            --get customer replacement price, check changes per week
            for z in (select curp.price, curp.startdate, curp.customerrentprice_id,
                             curp.changesperweek
                      from   customerrentprice curp
                      where  curp.productlistpercustomer_id = lv_plpcid
                      and    curp.typeofrent = lv_typeofrent
                      and    curp.changesperweek = lv_changesperweek
                      and    curp.startdate <= lv_pricedate
                      and    (curp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(curp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by curp.startdate desc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := z.price;
                fp_price_start_date       := greatest(lv_priceliststartdate, z.startdate);
                fp_price_list_type        := 'C'; -- customer specific
                fp_price_list_code        := null;
                fp_price_list_desc        := 'Customer Specific.';
                fp_customerrentpriceid    := z.customerrentprice_id;
                fp_changesperwkfoundprice := z.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        end if;
      end get_customerentprice;

      procedure lookpricefor_sgb(fp_generalpricelistid in number) is
      begin
        if fp_generalpricelistid is not null then
          begin
            --look for size equal
            get_generalrentprice(fp_generalpricelistid, fp_sizedefinitionid, lv_changesperweek);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_generalrentprice(fp_generalpricelistid, lv_sizestarid, lv_changesperweek);
              end;
            end if;
            --look for change per week -1
            if lv_typeofrent = 2 and lv_changesperweek <> 0 and lv_changesperweek <> -1 and
               fp_price_found_yn = 'N' then
              begin
                get_generalrentprice(fp_generalpricelistid, fp_sizedefinitionid, -1);
                if fp_price_found_yn = 'N' then
                  begin
                    --look for size star, changes per week -1
                    get_generalrentprice(fp_generalpricelistid, lv_sizestarid, -1);
                  end;
                end if;
              end;
            end if;
          end;
        else
          begin
            --look for size equal
            get_customerentprice(lv_changesperweek);
            --look for change per week -1
            if lv_typeofrent = 2 and lv_changesperweek <> 0 and lv_changesperweek <> -1 and
               fp_price_found_yn = 'N' then
              begin
                get_customerentprice(-1);
              end;
            end if;
          end;
        end if;
      end lookpricefor_sgb;
    begin
      --lookforprice rentprice
      for x in (select plc.generalpricelist_id, plc.dateactive
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 2 -- rent price
                and    plc.dateactive <= lv_pricedate
                and    plc.dateinactive >= lv_pricedate
                order  by plc.priority asc, plc.dateinactive desc) loop
        begin
          lv_priceliststartdate          := x.dateactive;
          lv_specific_sizebillinggroupid := lv_initial_specific_sizebillinggroupid;
          lookpricefor_sgb(x.generalpricelist_id);
          if fp_price_found_yn = 'N' then
            begin
              --start look for different sizebillinggroup
              if lv_specific_sizebillinggroupid <> lv_standard_sizebillinggroupid then
                begin
                  --standard sizebillinggroup
                  lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
              if fp_price_found_yn = 'N' and lv_specific_sizebillinggroupid <> 0 then
                begin
                  --no sizebillinggroup
                  lv_specific_sizebillinggroupid := 0;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
            end;
          end if; --price found N
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --initialize
    initialize;
    lv_typeofrent := 1;
    --
    if lv_billingmethod = 3 and lv_priceusage = 3 then
      /*wash only*/
      fp_result_code := 2; -- Price not relevant, billing method with wash price only
    elsif lv_billingmethod = 4 then
      fp_result_code := 3; -- Price not relevant, billing method = 4 piece rate only
    elsif lv_billingmethod = 1 and lv_tom = 2 and lv_garmentrentspecification = 5 then
      -- total wearer price
      fp_result_code := 4; -- Price not relevant, wearer total price
    elsif lv_billingmethod = 1 and lv_tom = 2 and lv_garmentrentspecification = 6 then
      -- wearer function price
      fp_result_code := 5; -- Price not relevant, wearer function price
    else
      begin
        if lv_billingmethod = 1 and lv_tom = 2 -- changes per week
         then
          lv_typeofrent := 2; -- changes per week
        else
          if lv_billingmethod = 1 and lv_tom <> 2 and lv_rentpriceperfrequency = 'Y' then
            lv_typeofrent := 4; -- frequency based
          else
            lv_changesperweek := 0;
          end if; -- frequency based=Y
        end if; -- changes/week
        if lv_billingmethod = 3 and lv_priceusage = 1 /* split */
         then
          lv_typeofrent := 7; -- split
        end if;
        if lv_billingmethod = 5 then
          lv_typeofrent := 6; -- lease
        end if;
        if lv_billingmethod = 2 and lv_minimumturnaround <> 0 and lv_databasecode <> 'AMM' then
          begin
            --check_underuse
            select count(1)
            into   lv_underuse_count
            from   systemsetting st
            join   businessunit bu
            on     bu.plant_id = st.plant_id
            where  st.name = 'UNDERUSEMETHOD'
            and    st.value in ('2', '4')
            and    bu.businessunit_id = lv_businessunitid;
            if lv_underuse_count > 0 then
              --underuse
              lv_typeofrent := 5;
            end if;
          end;
        end if;
        --
        if lv_billingmethod = 3 and lv_invoicefreqrelatedrentprice = 'Y' and
           lv_splitinvoicesperactivity = 'Y' then
          begin
            lv_typeofrent := 8;
            -- determine invoice frequency. Take lowest frequency,(to avoid BU determination) assuming that
            -- an activity for a customer is processed in only 1 plant,
            -- or if in multiple they have the same invoice frequency.
            select min(freq.invoicefrequencynumber) -- take lowest freq.
            into   lv_invoice_freq
            from   customeractivities ca, invoicefrequency freq, productgroup pg
            where  ca.customer_id = fp_customerid
            and    ca.activity_id = pg.activity_id
            and    pg.productgroup_id = lv_productgroupid
            and    freq.invoicefrequency_id = ca.invoicefrequency_id;
            if lv_invoice_freq < 100 and lv_invoice_freq <> 40 then
              lv_invoice_freq := 10;
            end if;
            if lv_invoice_freq > 100 then
              lv_invoice_freq := 110;
            end if;
          end;
        end if;
        --lookforprice
        lookforprice;
      end;
    end if;
    if fp_price_found_yn = 'Y' then
      begin
        if fp_chgperwk_or_freq = 0 then
          case lv_typeofrent
            when 2 then
              fp_result_code := '1'; -- when typeofrent is chgsperweek return result code about multiple prices possible
            when 4 then
              fp_result_code := '2'; -- when typeofrent is frequency return result code about multiple prices possible
            else
              fp_result_code := '0';
          end case;
        else
          fp_result_code := '0';
        end if;
        fp_result_desc     := decode_error('Y' || to_char(fp_result_code));
        fp_price_type_code := lv_typeofrent;
        fp_price_type_desc := decode_type_of_rent(fp_price_type_code);
        fp_inv_freq_code   := lv_invoice_freq;
        fp_inv_freq_desc   := decode_inv_freq(fp_inv_freq_code);
      end;
    else
      begin
        if fp_result_code is null then
          -- no price found
          fp_result_code := 1;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_rent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return varchar2
    parallel_enable is
    pragma udf;
    /* See package header for description of return string.   */
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(to_char(inv_freq_code), ' '), 1) ||
           rpad(nvl(inv_freq_desc, ' '), 10) ||
           lpad(nvl(to_char(changesperwkfoundprice), ' '), 10) ||
           rpad(nvl(to_char(customerrentpriceid), ' '), 1) ||
           rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end rent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(nvl(price, 0));
  end rent_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function customerrent_priceid(customerid        in customer.customer_id%type,
                                productid         in product.product_id%type,
                                sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                finishingmethodid in finishingmethod.finishingmethod_id%type,
                                pricedate         in pricelistpercustomer.dateactive%type default null,
                                chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(nvl(customerrentpriceid, 0));
  end customerrent_priceid;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(price);
  end rent_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_price_details(fp_customerid        in customer.customer_id%type,
                                   fp_productid         in product.product_id%type,
                                   fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate         in pricelistpercustomer.dateactive%type,
                                   fp_pricetype         in number, -- 0=all, 1=LOG, 2=COG
                                   fp_price             out customerwashprice.price%type,
                                   fp_price_found_yn    out varchar2,
                                   fp_price_start_date  out customerwashprice.startdate%type,
                                   fp_result_code       out number,
                                   fp_result_desc       out varchar2,
                                   fp_price_list_type   out varchar2,
                                   fp_price_list_code   out generalpricelist.code%type,
                                   fp_price_list_desc   out generalpricelist.description%type,
                                   fp_price_type_code   out customerwashprice.pricetype%type,
                                   fp_price_type_desc   out varchar2) is
    pragma udf;
    --locale variables
    lv_pricedate                   date;
    lv_plpcid                      number;
    lv_billingmethod               number;
    lv_inventorybillingtype        number;
    lv_chargelossforpool           varchar2(1);
    lv_priceusage                  number;
    lv_tom                         number;
    lv_garmentrentspecification    number;
    lv_sizestarid                  sizedefinition.sizedefinition_id%type;
    lv_businessunitid              number;
    lv_underuse_count              number := 0;
    lv_charge_wash_cog             varchar2(1);
    lv_changeswks_related_max      number;
    lv_charge_wash_chgwk           varchar2(1);
    lv_chargewashesonlyforcog      productlistpercustomer.chargewashesonlyforcog%type;
    lv_minimumturnaround           productlistpercustomer.minimumturnaround%type;
    lv_pricetype                   customerwashprice.pricetype%type;
    lv_pricetype_gen_prlist        generalwashprice.pricetype%type;
    lv_rentpriceperfrequency       productlistpercustomer.rentpriceperfrequency%type;
    lv_invoicefreqrelatedrentprice productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_splitinvoicesperactivity    customer.splitinvoicesperactivity%type;
    lv_productgroupid              product.productgroup_id%type;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'Y1',
                     'Distinct prices can be applicable LOG and COG', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, billing method 3 with rent price only', 'N3',
                     'Price not relevant, billing method = 1 flat rated rent', 'N4',
                     'Price not relevant, billing method = 2 rent based on minimum', 'N5',
                     'Price not relevant, disposable / sales only item', 'N6',
                     'Price not relevant, billing method = 4 with price for LOG only', 'N7',
                     'Price not relevant, billing method = 4 with price for COG only', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end decode_error;

    function decode_price_type(fppricetype in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fppricetype, 1, 'All (COG or LOG)', 2, 'COG Only', 4, 'Split Price',
                     'Unknown price type')
      into   r
      from   dual;
      return r;
    end decode_price_type;

    procedure initialize is
    begin
      --initialize
      lv_pricedate       := fp_pricedate;
      fp_price_found_yn  := 'N';
      fp_price_list_type := 1;
      lv_sizestarid      := getsizestarid;
      --get_plpc_info on size level
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
    end initialize;

    procedure lookforprice is
      lv_priceliststartdate date;

      procedure get_generalwhprice(fp_generalpricelistid in number, fp_sizeid in number) is
      begin
        --get_generalwhprice
        if fp_pricetype = 0 -- not specified LOG or COG take most recent active price
           and lv_pricetype_gen_prlist <> 4 -- for split price always look for split prices
           and not (lv_billingmethod = 4 and lv_chargewashesonlyforcog = 3) -- for COG only look only for COG prices
         then
          begin
            for a in (select gwp.price, gwp.startdate, gwp.pricetype, g.code, g.description
                      from   generalwashprice gwp
                      join   generalpricelist g
                      on     g.generalpricelist_id = gwp.generalpricelist_id
                      where  g.generalpricelist_id = fp_generalpricelistid
                      and    g.pricetype = 1 -- Wash
                      and    g.active = 'Y'
                      and    gwp.product_id = fp_productid
                      and    gwp.sizedefinition_id = fp_sizeid
                      and    gwp.finishingmethod_id = fp_finishingmethodid
                      and    gwp.startdate <= lv_pricedate
                      and    (gwp.pricetype <> 4 or lv_billingmethod <> 4) -- don't select split prices for BM 4
                      order  by gwp.startdate desc, gwp.pricetype asc) loop
              begin
                fp_price_found_yn   := 'Y';
                fp_price            := a.price;
                fp_price_start_date := greatest(lv_priceliststartdate, a.startdate);
                fp_price_list_type  := 'G'; -- general
                fp_price_list_code  := a.code;
                fp_price_list_desc  := a.description;
                --price found exit loop
                exit;
              end;
            end loop; --a
          end;
        else
          begin
            for b in (select gwp.price, gwp.startdate, gwp.pricetype, g.code, g.description
                      from   generalwashprice gwp
                      join   generalpricelist g
                      on     g.generalpricelist_id = gwp.generalpricelist_id
                      where  g.generalpricelist_id = fp_generalpricelistid
                      and    g.pricetype = 1 -- Wash
                      and    g.active = 'Y'
                      and    gwp.product_id = fp_productid
                      and    gwp.sizedefinition_id = fp_sizeid
                      and    gwp.finishingmethod_id = fp_finishingmethodid
                      and    gwp.startdate <= lv_pricedate
                      and    gwp.pricetype = lv_pricetype_gen_prlist
                      order  by gwp.startdate desc) loop
              begin
                fp_price_found_yn   := 'Y';
                fp_price            := b.price;
                fp_price_start_date := greatest(lv_priceliststartdate, b.startdate);
                fp_price_list_type  := 'G'; -- general
                fp_price_list_code  := b.code;
                fp_price_list_desc  := b.description;
                --price found exit loop
                exit;
              end;
            end loop; --b
          end;
        end if;
      end get_generalwhprice;

      procedure get_customerwhprice(fp_prodlistid in number) is
      begin
        --get_customerwhprice
        for c in (select cupri.price, cupri.startdate, cupri.pricetype
                  from   customerwashprice cupri
                  where  cupri.productlistpercustomer_id = fp_prodlistid
                  and    cupri.startdate <= lv_pricedate
                  and    cupri.pricetype = lv_pricetype
                  order  by cupri.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := c.price;
            fp_price_start_date := greatest(lv_priceliststartdate, c.startdate);
            fp_price_list_type  := 'C'; -- customer specific
            fp_price_list_code  := null;
            fp_price_list_desc  := 'Customer Specific.';
            --price found exit loop
            exit;
          end;
        end loop; --c
      end get_customerwhprice;
    begin
      --lookforprice washprice
      for x in (select plc.generalpricelist_id, plc.dateactive
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 1 -- Wash
                and    plc.dateactive <= lv_pricedate
                and    plc.dateinactive >= lv_pricedate
                order  by plc.priority) loop
        begin
          lv_priceliststartdate := x.dateactive;
          if x.generalpricelist_id is not null then
            begin
              --look for size equal
              get_generalwhprice(x.generalpricelist_id, fp_sizedefinitionid);
              if fp_price_found_yn = 'N' then
                begin
                  --look for size star
                  get_generalwhprice(x.generalpricelist_id, lv_sizestarid);
                end;
              end if;
            end;
          else
            begin
              --look for size equal
              get_customerwhprice(lv_plpcid);
              --do NOT look on star level
            end;
          end if;
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --initialize
    initialize;
    begin
      select value
      into   lv_charge_wash_cog
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'CHARGEWASHCOGCHG/WEEK'
      and    c.customer_id = fp_customerid;
    exception
      when no_data_found then
        lv_charge_wash_cog := 'N';
    end;
    begin
      select value
      into   lv_changeswks_related_max
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'CHANGESWEEKRELATEDTOMAX'
      and    c.customer_id = fp_customerid;
    exception
      when no_data_found then
        lv_changeswks_related_max := 1;
    end;
    begin
      select value
      into   lv_charge_wash_chgwk
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'CHARGEWASHCHG/WEEK'
      and    c.customer_id = fp_customerid;
    exception
      when no_data_found then
        lv_charge_wash_chgwk := 'N';
    end;
    --
    if lv_billingmethod = 3 and lv_priceusage = 2 then
      begin
        /* rent price only*/
        fp_result_code := 2; -- Price not relevant, billing method 3 with rent price only
      end;
    elsif lv_billingmethod = 1 then
      begin
        if lv_chargewashesonlyforcog = 3 and
           not (lv_charge_wash_cog = 'Y' and lv_changeswks_related_max = 2) then
          begin
            fp_result_code := 3; -- Price not relevant
          end;
        elsif lv_chargewashesonlyforcog = 1 and lv_charge_wash_chgwk = 'N' then
          begin
            fp_result_code := 3; -- Price not relevant
          end;
        end if;
      end;
    end if;
    if lv_tom = 3 then
      begin
        fp_result_code := 5; -- Price not relevant, disposable or sales only item.
      end;
    elsif lv_billingmethod = 4 and lv_tom <> 3 and lv_chargewashesonlyforcog = 2 /*LOG Only*/
          and fp_pricetype = 2 /*COG Only*/
     then
      begin
        fp_result_code := 6; -- Price not relevant, billing method = 4 with for LOG only
      end;
    elsif lv_billingmethod = 4 and lv_tom <> 3 and lv_chargewashesonlyforcog = 3 /*COG Only*/
          and fp_pricetype = 1 /*LOG Only*/
     then
      begin
        fp_result_code := 7; -- Price not relevant, billing method = 4 with for COG only
      end;
    else
      begin
        if lv_billingmethod = 2 then
          begin
            -- Determine system setting UNDERUSEMETHOD
            select count(1)
            into   lv_underuse_count
            from   systemsetting st
            join   businessunit bu
            on     bu.plant_id = st.plant_id
            where  st.name = 'UNDERUSEMETHOD'
            and    st.value = '2'
            and    bu.businessunit_id = lv_businessunitid;
          end;
        end if;
        -- Only for UNDERUSEMETHOD = 2 the MinimumTurnaround must be > 0
        if lv_billingmethod = 2 and lv_underuse_count > 0 and lv_minimumturnaround = 0 then
          begin
            fp_result_code := 4; -- Price not relevant, billing method = 2 rent based on minimum
          end;
        else
          begin
            lv_pricetype := 1; -- All
            if fp_pricetype = 2 and -- COG
               lv_billingmethod in (3, 4) and lv_chargewashesonlyforcog in (1, 3) and /* separate price for COG/LOG,  or COG only */
               lv_priceusage <> 1 /* split */
             then
              begin
                lv_pricetype := 2; -- COG only
              end;
            end if;
            if fp_pricetype = 0 and -- all
               lv_billingmethod = 4 and lv_chargewashesonlyforcog = 3 then
              begin
                lv_pricetype := 2; -- COG only
              end;
            end if;
            if lv_billingmethod = 1 then
              begin
                if lv_chargewashesonlyforcog = 3 then
                  begin
                    if lv_charge_wash_cog = 'Y' and lv_changeswks_related_max = 2 then
                      begin
                        lv_pricetype := 2;
                      end;
                    end if;
                  end;
                end if;
              end;
            end if;
            if lv_billingmethod = 3 and lv_priceusage = 1 -- split
             then
              begin
                lv_pricetype_gen_prlist := 4;
              end;
            else
              begin
                lv_pricetype_gen_prlist := lv_pricetype;
              end;
            end if;
            --lookforprice
            lookforprice;
          end;
        end if;
      end;
    end if;
    ----
    if fp_price_found_yn = 'Y' then
      begin
        if fp_pricetype = 0 and lv_chargewashesonlyforcog = 1 -- separate price LOG/COG
         then
          fp_result_code := '1';
        else
          fp_result_code := '0';
        end if;
        fp_result_desc     := decode_error('Y' || to_char(fp_result_code));
        fp_price_type_desc := decode_price_type(fp_price_type_code);
      end;
    else
      begin
        if fp_result_code is null then
          begin
            -- no price found
            fp_result_code := 1;
          end;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_wash_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return varchar2
    parallel_enable is

    pragma udf;
    /* See package header for description of return string.   */
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  begin
    get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           pricetype, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           price_type_code, price_type_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end wash_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      pricetype         in number default 0) return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  begin
    get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           pricetype, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           price_type_code, price_type_desc);
    return(nvl(price, 0));
  end wash_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return number is
    pragma udf;
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  begin
    get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           pricetype, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           price_type_code, price_type_desc);
    return(price);
  end wash_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_price_details_pt(customerid        in customer.customer_id%type,
                                      productid         in product.product_id%type,
                                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                                      pricedate         in pricelistpercustomer.dateactive%type,
                                      pricetype         in number,
                                      price             out customerwashprice.price%type,
                                      price_found_yn    out varchar2,
                                      price_start_date  out customerwashprice.startdate%type,
                                      result_code       out number,
                                      result_desc       out varchar2,
                                      price_list_type   out varchar2,
                                      price_list_code   out generalpricelist.code%type,
                                      price_list_desc   out generalpricelist.description%type,
                                      price_type_code   out customerwashprice.pricetype%type,
                                      price_type_desc   out varchar2) is
    pragma udf;
  begin
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) or (pricetype is null) or (pricetype = 0) then
      result_code := 8; -- error in parameters
    else
      get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                             pricetype, price, price_found_yn, price_start_date, result_code,
                             result_desc, price_list_type, price_list_code, price_list_desc,
                             price_type_code, price_type_desc);
    end if;
  end get_wash_price_details_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_details_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  begin
    get_wash_price_details_pt(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                              pricetype, price, price_found_yn, price_start_date, result_code,
                              result_desc, price_list_type, price_list_code, price_list_desc,
                              price_type_code, price_type_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end wash_price_details_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_pt(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         pricedate         in pricelistpercustomer.dateactive%type default null,
                         pricetype         in number) return number is
    pragma udf;
    /* Returns the wash price for the specified pricetype, if not found, returns 0.  For use in calculations.  */
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  begin
    get_wash_price_details_pt(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                              pricetype, price, price_found_yn, price_start_date, result_code,
                              result_desc, price_list_type, price_list_code, price_list_desc,
                              price_type_code, price_type_desc);
    return(nvl(price, 0));
  end wash_price_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_display_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return number is
    pragma udf;
    /* Returns the wash price for the specified pricetype, if not found, returns null. For display/print purposes. */
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  begin
    get_wash_price_details_pt(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                              pricetype, price, price_found_yn, price_start_date, result_code,
                              result_desc, price_list_type, price_list_code, price_list_desc,
                              price_type_code, price_type_desc);
    return(price);
  end wash_price_display_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_replacement_price_details(fp_customerid        in customer.customer_id%type,
                                          fp_productid         in product.product_id%type,
                                          fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                          fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                          fp_pricedate         in pricelistpercustomer.dateactive%type,
                                          fp_price             out customerreplacementprice.price%type,
                                          fp_price_found_yn    out varchar2,
                                          fp_price_start_date  out customerreplacementprice.startdate%type,
                                          fp_result_code       out number,
                                          fp_result_desc       out varchar2,
                                          fp_price_list_type   out varchar2,
                                          fp_price_list_code   out generalpricelist.code%type,
                                          fp_price_list_desc   out generalpricelist.description%type) is
    pragma udf;
    --locale variables
    lv_pricedate                           date;
    lv_plpcid                              number;
    lv_billingmethod                       number;
    lv_inventorybillingtype                number;
    lv_chargelossforpool                   varchar2(1);
    lv_priceusage                          number;
    lv_tom                                 number;
    lv_garmentrentspecification            number;
    lv_sizestarid                          sizedefinition.sizedefinition_id%type;
    lv_standard_sizebillinggroupid         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizebillinggroupid         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizebillinggroupid sizebillinggroup.systemuser_id%type;
    lv_businessunitid                      number;
    lv_chargewashesonlyforcog              productlistpercustomer.chargewashesonlyforcog%type;
    lv_minimumturnaround                   productlistpercustomer.minimumturnaround%type;
    lv_rentpriceperfrequency               productlistpercustomer.rentpriceperfrequency%type;
    lv_invoicefreqrelatedrentprice         productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_splitinvoicesperactivity            customer.splitinvoicesperactivity%type;
    lv_productgroupid                      product.productgroup_id%type;

    function decode_error(errorcode in varchar2) return varchar2 is
      lv_message varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, billingmethod is 4 piece rate only', 'N3',
                     'Price not relevant, disposable / sales only item', 'N8', 'Error in parameters',
                     'N9', 'ORA Error', 'Unknown error code')
      into   lv_message
      from   dual;
      return lv_message;
    end decode_error;

    procedure initialize is
    begin
      --initialize
      lv_pricedate       := fp_pricedate;
      fp_price_found_yn  := 'N';
      fp_price_list_type := 3;
      lv_sizestarid      := getsizestarid;
      --get_plpc_info
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
      --
      get_size_billing_groups2(fp_customerid, fp_productid, fp_sizedefinitionid, 3,
                               lv_standard_sizebillinggroupid,
                               lv_initial_specific_sizebillinggroupid);
    end initialize;

    procedure lookforprice is
      lv_priceliststartdate date;

      procedure get_generalrpprice(fp_generalpricelistid in number,
                                   fp_pricecoefficient   in number,
                                   fp_sizeid             in number) is
      begin
        --get general replacement price
        for y in (select fp_pricecoefficient * grp.price price, grp.startdate, g.code, g.description
                  from   generalreplacementprice grp
                  join   generalpricelist g
                  on     g.generalpricelist_id = grp.generalpricelist_id
                  where  g.pricetype = 3 -- replacement price
                  and    g.active = 'Y'
                  and    g.generalpricelist_id = fp_generalpricelistid
                  and    grp.product_id = fp_productid
                  and    grp.sizedefinition_id = fp_sizeid
                  and    grp.startdate <= lv_pricedate
                  and    nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by grp.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := y.price;
            fp_price_start_date := greatest(lv_priceliststartdate, y.startdate);
            fp_price_list_type  := 'G'; -- general
            fp_price_list_code  := y.code;
            fp_price_list_desc  := y.description;
            --price found exit loop
            exit;
          end;
        end loop;
      end get_generalrpprice;

      procedure get_customerrpprice(fp_sizeid in number) is
      begin
        --get customer replacement price
        for z in (select cupri.price, cupri.startdate
                  from   customerreplacementprice cupri
                  where  cupri.customer_id = fp_customerid
                  and    cupri.product_id = fp_productid
                  and    cupri.sizedefinition_id = fp_sizeid
                  and    cupri.startdate <= lv_pricedate
                  and    nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by cupri.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := z.price;
            fp_price_start_date := greatest(lv_priceliststartdate, z.startdate);
            fp_price_list_type  := 'C'; -- customer specific
            fp_price_list_code  := null;
            fp_price_list_desc  := 'Customer Specific.';
            --price found exit loop
            exit;
          end;
        end loop;
      end get_customerrpprice;

      procedure lookpricefor_sgb(fp_generalpricelistid in number, fp_pricecoefficient in number) is
      begin
        if fp_generalpricelistid is not null then
          begin
            --look for size equal
            get_generalrpprice(fp_generalpricelistid, fp_pricecoefficient, fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_generalrpprice(fp_generalpricelistid, fp_pricecoefficient, lv_sizestarid);
              end;
            end if;
          end;
        else
          begin
            --look for size equal
            get_customerrpprice(fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_customerrpprice(lv_sizestarid);
              end;
            end if;
          end;
        end if;
      end lookpricefor_sgb;
    begin
      --lookforprice replacement
      for x in (select plc.generalpricelist_id, plc.pricecoefficient, plc.dateactive
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 3 -- replacement price
                and    plc.dateactive <= lv_pricedate
                and    plc.dateinactive >= lv_pricedate
                order  by plc.priority) loop
        begin
          lv_priceliststartdate          := x.dateactive;
          lv_specific_sizebillinggroupid := lv_initial_specific_sizebillinggroupid;
          lookpricefor_sgb(x.generalpricelist_id, x.pricecoefficient);
          if fp_price_found_yn = 'N' then
            begin
              --start look for different sizebillinggroup
              if lv_specific_sizebillinggroupid <> lv_standard_sizebillinggroupid then
                begin
                  --standard sizebillinggroup
                  lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
                  lookpricefor_sgb(x.generalpricelist_id, x.pricecoefficient);
                end;
              end if;
              if fp_price_found_yn = 'N' and lv_specific_sizebillinggroupid <> 0 then
                begin
                  --no sizebillinggroup
                  lv_specific_sizebillinggroupid := 0;
                  lookpricefor_sgb(x.generalpricelist_id, x.pricecoefficient);
                end;
              end if;
            end;
          end if; --price found N
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --initialize
    initialize;
    --
    if (lv_billingmethod = 4 and lv_chargelossforpool <> 'Y') then
      begin
        /*piece rate only and no loss charges*/
        fp_result_code := 2; -- Price not relevant, billing method piece rate only
      end;
    elsif lv_tom = 3 then
      begin
        /* disposable / sales only*/
        fp_result_code := 3; -- Price not relevant, disposable or sales only product
      end;
    else
      begin
        --lookforprice, even if no plpc found lookup
        lookforprice;
      end;
    end if;
    if fp_price_found_yn = 'Y' then
      begin
        fp_result_desc     := decode_error('Y0');
        fp_price_list_desc := nvl(fp_price_list_desc, 'Customer Specific.');
      end;
    else
      begin
        -- no price found
        if fp_result_code is null then
          fp_result_code := 1;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_replacement_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function replacement_price_details(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price            customerreplacementprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerreplacementprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_replacement_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                  pricedate, price, price_found_yn, price_start_date, result_code,
                                  result_desc, price_list_type, price_list_code, price_list_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end replacement_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function replacement_price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             finishingmethodid in finishingmethod.finishingmethod_id%type,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price            customerreplacementprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerreplacementprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_replacement_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                  pricedate, price, price_found_yn, price_start_date, result_code,
                                  result_desc, price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end replacement_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function replacement_price_display(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price            customerreplacementprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerreplacementprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_replacement_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                  pricedate, price, price_found_yn, price_start_date, result_code,
                                  result_desc, price_list_type, price_list_code, price_list_desc);
    return(price);
  end replacement_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_sales_price_details(fp_customerid       in customer.customer_id%type,
                                    fp_productid        in product.product_id%type,
                                    fp_sizedefinitionid in sizedefinition.sizedefinition_id%type,
                                    fp_pricedate        in pricelistpercustomer.dateactive%type,
                                    fp_price            out customersalesprice.price%type,
                                    fp_price_found_yn   out varchar2,
                                    fp_price_start_date out customersalesprice.startdate%type,
                                    fp_result_code      out number,
                                    fp_result_desc      out varchar2,
                                    fp_price_list_type  out varchar2,
                                    fp_price_list_code  out generalpricelist.code%type,
                                    fp_price_list_desc  out generalpricelist.description%type) is
    pragma udf;
    --locale variables
    lv_sizestarid                          sizedefinition.sizedefinition_id%type;
    lv_standard_sizebillinggroupid         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizebillinggroupid         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizebillinggroupid sizebillinggroup.systemuser_id%type;

    procedure initialize is
    begin
      --initialize
      fp_price_found_yn  := 'N';
      fp_price_list_type := 4;
      lv_sizestarid      := getsizestarid;
      --get decimals
      select max(cu.decimals)
      into   gv_decimals
      from   customer c
      join   currency cu
      on     cu.currency_id = c.currency_id
      where  c.customer_id = fp_customerid;
      --
      get_size_billing_groups2(fp_customerid, fp_productid, fp_sizedefinitionid, 3,
                               lv_standard_sizebillinggroupid,
                               lv_initial_specific_sizebillinggroupid);
    end initialize;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end decode_error;

    procedure lookforprice is
      lv_priceliststartdate date;

      procedure get_generalsalesprice(fp_generalpricelistid in number, fp_sizeid in number) is
      begin
        --get general sales price
        for y in (select gsp.price price, gsp.startdate, g.code, g.description
                  from   generalsalesprice gsp
                  join   generalpricelist g
                  on     g.generalpricelist_id = gsp.generalpricelist_id
                  where  g.pricetype = 4 -- sales price
                  and    g.active = 'Y'
                  and    g.generalpricelist_id = fp_generalpricelistid
                  and    gsp.product_id = fp_productid
                  and    gsp.sizedefinition_id = fp_sizeid
                  and    gsp.startdate <= fp_pricedate
                  and    nvl(gsp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by gsp.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := y.price;
            fp_price_start_date := greatest(lv_priceliststartdate, y.startdate);
            fp_price_list_type  := 'G'; -- general
            fp_price_list_code  := y.code;
            fp_price_list_desc  := y.description;
            --price found exit loop
            exit;
          end;
        end loop;
      end get_generalsalesprice;

      procedure get_customersalesprice(fp_sizeid in number) is
      begin
        --get customer sales price
        for z in (select cusal.price, cusal.startdate
                  from   customersalesprice cusal
                  where  cusal.customer_id = fp_customerid
                  and    cusal.product_id = fp_productid
                  and    cusal.sizedefinition_id = fp_sizeid
                  and    cusal.startdate <= fp_pricedate
                  and    nvl(cusal.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by cusal.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := z.price;
            fp_price_start_date := greatest(lv_priceliststartdate, z.startdate);
            fp_price_list_type  := 'C'; -- customer specific
            fp_price_list_code  := null;
            fp_price_list_desc  := 'Customer Specific.';
            --price found exit loop
            exit;
          end;
        end loop;
      end get_customersalesprice;

      procedure lookpricefor_sgb(fp_generalpricelistid in number) is
      begin
        if fp_generalpricelistid is not null then
          begin
            --look for size equal
            get_generalsalesprice(fp_generalpricelistid, fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_generalsalesprice(fp_generalpricelistid, lv_sizestarid);
              end;
            end if;
          end;
        else
          begin
            --look for size equal
            get_customersalesprice(fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_customersalesprice(lv_sizestarid);
              end;
            end if;
          end;
        end if;
      end lookpricefor_sgb;
    begin
      --lookforprice sales
      for x in (select plc.generalpricelist_id, plc.dateactive
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 4 -- sales price
                and    plc.dateactive <= fp_pricedate
                and    plc.dateinactive >= fp_pricedate
                order  by plc.priority) loop
        begin
          lv_priceliststartdate          := x.dateactive;
          lv_specific_sizebillinggroupid := lv_initial_specific_sizebillinggroupid;
          lookpricefor_sgb(x.generalpricelist_id);
          if fp_price_found_yn = 'N' then
            begin
              --start look for different sizebillinggroup
              if lv_specific_sizebillinggroupid <> lv_standard_sizebillinggroupid then
                begin
                  --standard sizebillinggroup
                  lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
              if fp_price_found_yn = 'N' and lv_specific_sizebillinggroupid <> 0 then
                begin
                  --no sizebillinggroup
                  lv_specific_sizebillinggroupid := 0;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
            end;
          end if; --price found N
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --main sales
    --initialize
    initialize;
    --lookforprice
    lookforprice;
    if fp_price_found_yn = 'Y' then
      begin
        fp_result_desc     := decode_error('Y0');
        fp_price_list_desc := nvl(fp_price_list_desc, 'Customer Specific.');
      end;
    else
      begin
        -- no price found
        if fp_result_code is null then
          fp_result_code := 1;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_sales_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function sales_price_details(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price            customersalesprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customersalesprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_sales_price_details(customerid, productid, sizedefinitionid, pricedate, price,
                            price_found_yn, price_start_date, result_code, result_desc,
                            price_list_type, price_list_code, price_list_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end sales_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function sales_price(customerid       in customer.customer_id%type,
                       productid        in product.product_id%type,
                       sizedefinitionid in sizedefinition.sizedefinition_id%type,
                       pricedate        in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price            customersalesprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customersalesprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_sales_price_details(customerid, productid, sizedefinitionid, pricedate, price,
                            price_found_yn, price_start_date, result_code, result_desc,
                            price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end sales_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function sales_price_display(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price            customersalesprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customersalesprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_sales_price_details(customerid, productid, sizedefinitionid, pricedate, price,
                            price_found_yn, price_start_date, result_code, result_desc,
                            price_list_type, price_list_code, price_list_desc);
    return(price);
  end sales_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_price_details(customerid         in customer.customer_id%type,
                                     weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                     soil_yn            in customerweightprice.soil%type,
                                     pricedate          in pricelistpercustomer.dateactive%type,
                                     price              out customerweightprice.price%type,
                                     price_found_yn     out varchar2,
                                     price_start_date   out customerweightprice.startdate%type,
                                     result_code        out number,
                                     result_desc        out varchar2,
                                     price_list_type    out varchar2,
                                     price_list_code    out generalpricelist.code%type,
                                     price_list_desc    out generalpricelist.description%type) is
    pragma udf;
    price_found                 boolean;
    price_not_relevant          boolean;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_pricelist_type           varchar2(1);
    lv_price                    customerweightprice.price%type;
    lv_price_start_date         customerweightprice.startdate%type;
    lv_generalpricelistid       generalweightprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    lv_weighingcatpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    lv_invoice_method           weighingcategpercustomer.invoicemethod%type;
    lv_priceliststartdate       date;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, weights not invoiced', 'N3',
                     'Price not defined, weights invoiced soil, not clean ', 'N4',
                     'Price not defined, weights invoiced clean, not soil ', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

  begin
    -- main Weight
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found        := false;
    price_not_relevant := false;
    price              := null;
    price_found_yn     := 'N';
    price_start_date   := null;
    result_code        := null;
    result_desc        := null;
    price_list_type    := null;
    price_list_code    := null;
    price_list_desc    := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    if (customerid is null) or (weighingcategoryid is null) or (soil_yn not in ('Y', 'N')) then
      result_code := 8; -- error in parameters
    end if;
    --get decimals
    select max(cu.decimals)
    into   gv_decimals
    from   customer c
    join   currency cu
    on     cu.currency_id = c.currency_id
    where  c.customer_id = customerid;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not price_found) and (not price_not_relevant) loop
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id, pricelistpercustomer.dateactive
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 5 -- this means weight price
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid, lv_priceliststartdate;
      -- load weighingcategpercustomer etc to determine price usage
      lv_weighingcatpercustomerid := null;
      lv_invoice_method           := null;
      open vcsr for
        select wcpc.weighingcategpercustomer_id, wcpc.invoicemethod
        from   weighingcategpercustomer wcpc
        where  wcpc.customer_id = customerid
        and    wcpc.weighingcategory_id = weighingcategoryid
        and    ((lv_pricedate >= wcpc.dateactive and lv_pricedate <= wcpc.dateinactive) or i > 1)
        order  by wcpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_weighingcatpercustomerid, lv_invoice_method;
        if lv_invoice_method = 1 then
          /* no invoicing based on weight */
          price_not_relevant := true;
          result_code        := 2; -- Price not relevant, customer is not invoiced based on weight
        end if;
        if lv_invoice_method in (2, 4) and soil_yn = 'N' then
          /* configured soil, requested clean */
          price_not_relevant := true;
          result_code        := 3; -- Price not relevant, customer is invoiced based on soil weight
        end if;
        if lv_invoice_method = 3 and soil_yn = 'Y' then
          /* configured clean, requested soil */
          price_not_relevant := true;
          result_code        := 4; -- Price not relevant, customer is invoiced based on clean weight
        end if;
      end if;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) and (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gwp.price, gwp.startdate, g.code, g.description
                       from   generalweightprice gwp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 5 -- weight price
                       and    g.active = 'Y'
                       and    gwp.generalpricelist_id = g.generalpricelist_id
                       and    gwp.weighingcategory_id = weighingcategoryid
                       and    gwp.soil = soil_yn
                       and    gwp.startdate <= lv_pricedate
                       order  by gwp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.price, cupri.startdate
                       from   customerweightprice cupri
                       where  cupri.weighingcategpercustomer_id = lv_weighingcatpercustomerid
                       and    cupri.soil = soil_yn
                       and    cupri.startdate <= lv_pricedate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid, lv_priceliststartdate; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:  1 = try to find for active weighingcategorypercustomer
        2 = try to find for any weighingcategorypercustomer */
        i := i + 1;
        if lv_weighingcatpercustomerid is not null then
          -- active wcpc already found, so do not perform extra loop
          i := i + 1;
        end if;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := greatest(lv_priceliststartdate, lv_price_start_date);
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G' then
        price_list_desc := lv_pricelist_desc;
      else
        price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_weight_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_price_details(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price            customerweightprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerweightprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_weight_price_details(customerid, weighingcategoryid, soil_yn, pricedate, price,
                             price_found_yn, price_start_date, result_code, result_desc,
                             price_list_type, price_list_code, price_list_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end weight_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_price(customerid         in customer.customer_id%type,
                        weighingcategoryid in weighingcategory.weighingcategory_id%type,
                        soil_yn            in customerweightprice.soil%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price            customerweightprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerweightprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_weight_price_details(customerid, weighingcategoryid, soil_yn, pricedate, price,
                             price_found_yn, price_start_date, result_code, result_desc,
                             price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end weight_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_price_display(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price            customerweightprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerweightprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_weight_price_details(customerid, weighingcategoryid, soil_yn, pricedate, price,
                             price_found_yn, price_start_date, result_code, result_desc,
                             price_list_type, price_list_code, price_list_desc);
    return(price);
  end weight_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_speccharge_details(customerid        in customer.customer_id%type,
                                   specialchargeid   in specialcharge.specialcharge_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerspecialchargeprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerspecialchargeprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type,
                                   specialchargecode out specialcharge.code%type,
                                   percentage        out customerspecialchargeprice.percentage%type,
                                   minimumamount     out specialcharge.minimumamount%type,
                                   maximumamount     out specialcharge.maximumamount%type) is
    pragma udf;
    price_found           boolean;
    dummy                 number;
    lv_fixedamount_yn     specialcharge.fixedamount%type;
    lv_fixedamount_str    varchar2(10);
    lv_pricedate          date;
    lv_pricelist_type     varchar2(1);
    lv_price              customerspecialchargeprice.price%type;
    lv_price_start_date   customerspecialchargeprice.startdate%type;
    lv_generalpricelistid generalpricelist.generalpricelist_id%type;
    lv_pricelist_code     generalpricelist.code%type;
    lv_pricelist_desc     generalpricelist.description%type;
    lv_percentage         customerspecialchargeprice.percentage%type;
    lv_minimumamount      customerspecialchargeprice.minimumamount%type;
    lv_maximumamount      customerspecialchargeprice.maximumamount%type;
    lv_priceliststartdate date;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;

    function decode_error(errorcode in varchar2, type_str in varchar2 default null) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', type_str || ' found', 'N1', type_str || ' not defined', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

  begin
    -- main SpecialCharge
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found       := false;
    price             := null;
    price_found_yn    := 'N';
    price_start_date  := null;
    result_code       := null;
    result_desc       := null;
    price_list_type   := null;
    price_list_code   := null;
    price_list_desc   := null;
    lv_fixedamount_yn := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    select c.fixedamount, decode(c.fixedamount, 'Y', 'Price', 'Percentage')
    into   lv_fixedamount_yn, lv_fixedamount_str
    from   specialcharge c
    where  c.specialcharge_id = specialchargeid;
    if ((customerid is null) or (specialchargeid is null) or (lv_fixedamount_yn is null)) then
      result_code := 8; -- error in parameters
    end if;
    --get decimals
    select max(cu.decimals)
    into   gv_decimals
    from   customer c
    join   currency cu
    on     cu.currency_id = c.currency_id
    where  c.customer_id = customerid;
    if result_code is null then
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id, pricelistpercustomer.dateactive
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 10 -- this means special charge price
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid, lv_priceliststartdate;
      -- start loop on pricelistpercustomer
      /* --------------------- L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_percentage       := null;
            lv_minimumamount    := null;
            lv_maximumamount    := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gscp.price, gscp.startdate, g.code, g.description, gscp.percentage,
                              gscp.minimumamount, gscp.maximumamount
                       from   generalspecialchargeprice gscp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 10 -- special charge price
                       and    g.active = 'Y'
                       and    gscp.generalpricelist_id = g.generalpricelist_id
                       and    gscp.specialcharge_id = specialchargeid
                       and    gscp.startdate <= lv_pricedate
                       order  by gscp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc,
                   lv_percentage, lv_minimumamount, lv_maximumamount, dummy;
            close vcsr;
            if (lv_fixedamount_yn = 'Y' and lv_price is not null) or
               (lv_fixedamount_yn = 'N' and lv_percentage is not null) then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_percentage       := null;
            lv_minimumamount    := null;
            lv_maximumamount    := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.price, cupri.startdate, cupri.percentage, cupri.minimumamount,
                              cupri.maximumamount
                       from   customerspecialchargeprice cupri
                       where  cupri.specialcharge_id = specialchargeid
                       and    cupri.customer_id = customerid
                       and    cupri.startdate <= lv_pricedate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_percentage, lv_minimumamount, lv_maximumamount,
                   dummy;
            close vcsr;
            if ((lv_price is not null) or (lv_percentage is not null)) then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid, lv_priceliststartdate; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   L O O P ----------------------------------------------------------*/
      -- if no price found then take from special charge base table
      if (not price_found) then
        open vcsr for
          select x.*, rownum
          from   (select sc.newamount, sc.startdate, sc.newpercentage, sc.minimumamount,
                          sc.maximumamount
                   from   specialcharge sc
                   where  sc.specialcharge_id = specialchargeid
                   order  by sc.startdate desc) x
          where  rownum = 1; -- take first
        fetch vcsr
          into lv_price, lv_price_start_date, lv_percentage, lv_minimumamount, lv_maximumamount,
               dummy;
        close vcsr;
        if ((lv_price is not null) or (lv_percentage is not null)) then
          price_found       := true;
          lv_pricelist_type := 'B'; -- base table
        end if;
      end if;
    end if; -- result_code is null
    if price_found then
      if lv_fixedamount_yn = 'Y' then
        price      := lv_price;
        percentage := null;
      else
        price      := null;
        percentage := lv_percentage;
      end if; -- lv_fixedamount_yn ='Y'
      price_found_yn   := 'Y';
      price_start_date := greatest(lv_price_start_date, lv_priceliststartdate);
      result_code      := '0';
      select s.code
      into   specialchargecode
      from   specialcharge s
      where  s.specialcharge_id = specialchargeid;
      result_desc     := decode_error('Y' || to_char(result_code), lv_fixedamount_str);
      price_list_type := lv_pricelist_type;
      price_list_code := lv_pricelist_code;
      minimumamount   := lv_minimumamount;
      maximumamount   := lv_maximumamount;
      case lv_pricelist_type
        when 'G' then
          price_list_desc := lv_pricelist_desc;
        when 'B' then
          price_list_desc := 'Base ' || lv_fixedamount_str;
        else
          price_list_desc := 'Customer Specific.';
      end case;
    else
      if result_code is null then
        -- no price/percentage found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code, lv_fixedamount_str);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price/percentage found
      result_desc := decode_error('N' || result_code, lv_fixedamount_str);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_speccharge_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_details(customerid      in customer.customer_id%type,
                                 specialchargeid in specialcharge.specialcharge_id%type,
                                 pricedate       in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(specialchargecode, ' '), 6) ||
           rpad(nvl(to_char(result_code), ' '), 1) || rpad(nvl(result_desc, ' '), 80) ||
           rpad(nvl(to_char(percentage, '999D99'), ' '), 7) ||
           rpad(nvl(to_char(minimumamount, '999999D99'), ' '), 10) ||
           rpad(nvl(to_char(maximumamount, '999999D99'), ' '), 10) ||
           rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end specialcharge_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_price(customerid      in customer.customer_id%type,
                               specialchargeid in specialcharge.specialcharge_id%type,
                               pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(price, 0));
  end specialcharge_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_price_display(customerid      in customer.customer_id%type,
                                       specialchargeid in specialcharge.specialcharge_id%type,
                                       pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(price);
  end specialcharge_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_percentage(customerid      in customer.customer_id%type,
                                    specialchargeid in specialcharge.specialcharge_id%type,
                                    pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the percentage, if not found, returns 0.  For use in calculations.  */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(percentage, 0));
  end specialcharge_percentage;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_percentage_disp(customerid      in customer.customer_id%type,
                                         specialchargeid in specialcharge.specialcharge_id%type,
                                         pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the percentage, if not found, returns null.  For display/print purposes. */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(percentage);
  end specialcharge_percentage_disp;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_minamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the MinAmount, if not found, returns 0.  For use in calculations.  */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(minimumamount, 0));
  end specialcharge_minamount;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_minamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the MinAmount, if not found, returns null.  For display/print purposes. */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(minimumamount);
  end specialcharge_minamount_disp;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_maxamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the MaxAmount, if not found, returns 0.  For use in calculations.  */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(maximumamount, 0));
  end specialcharge_maxamount;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_maxamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the MaxAmount, if not found, returns null.  For display/print purposes. */
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(maximumamount);
  end specialcharge_maxamount_disp;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_rent_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerrentdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerrentdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type) is
    pragma udf;
    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerrentdiscount.discount%type;
    lv_discount_start_date      customerrentdiscount.startdate%type;
    lv_generaldiscountlistid    generalrentdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_customergarmrentspec     customer.garmentrentspecification%type;
    lv_size                     sizedefinition.sizedefinition_id%type;
    type tcsr is ref cursor;
    vcsr                 tcsr;
    vdiscountlistpercust tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Discount found', 'N1', 'Discount not defined', 'N2',
                     'Discount not relevant, billing method 3 with wash price only', 'N3',
                     'Discount not relevant, billing method = 4 piece rate only', 'N4',
                     'Discount not applicable, price defined at wearer level as wearer total price',
                     'N5', 'Discount not applicable, price defined at wearer function level', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

  begin
    -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found        := false;
    discount_not_relevant := false;
    discount              := null;
    discount_found_yn     := 'N';
    discount_start_date   := null;
    result_code           := null;
    result_desc           := null;
    discount_list_type    := null;
    discount_list_code    := null;
    discount_list_desc    := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    lv_size := sizedefinitionid;
    i       := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open vdiscountlistpercust for
        select discountlistpercustomer.generaldiscountlist_id
        from   discountlistpercustomer
        where  discountlistpercustomer.customer_id = customerid
        and    discountlistpercustomer.pricetype = 2 -- this means rent discount
        and    discountlistpercustomer.dateactive <= lv_discountdate
        and    discountlistpercustomer.dateinactive >= lv_discountdate
        order  by discountlistpercustomer.priority;
      fetch vdiscountlistpercust
        into lv_generaldiscountlistid;
      -- load weighingcategpercustomer etc to determine discount usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_typeofmerchandize        := null;
      lv_priceusage               := null;
      lv_customergarmrentspec     := null;
      open vcsr for
        select plpc.productlistpercustomer_id, plpc.billingmethod, plpc.priceusage,
               p.typeofmerchandise, c.garmentrentspecification
        from   productlistpercustomer plpc, product p, customer c
        where  plpc.customer_id = customerid
        and    plpc.product_id = productid
        and    plpc.sizedefinition_id = lv_size
        and    plpc.finishingmethod_id = finishingmethodid
        and    p.product_id = plpc.product_id
        and    c.customer_id = plpc.customer_id
        and    ((lv_discountdate >= plpc.dateactive and lv_discountdate <= plpc.dateinactive) or
              i > 1)
        order  by plpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_typeofmerchandize,
               lv_customergarmrentspec;
        if lv_billingmethod = 3 and lv_priceusage = 3 then
          /*wash only*/
          discount_not_relevant := true;
          result_code           := 2; -- Price not relevant, billing method 3 with wash price only
        end if;
        if lv_billingmethod = 4 then
          discount_not_relevant := true;
          result_code           := 3; -- Price not relevant, billing method = 4 piece rate only
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize = 2 and lv_customergarmrentspec = 5 then
          -- total wearer price
          discount_not_relevant := true;
          result_code           := 4; -- Price not relevant, wearer total price
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize = 2 and lv_customergarmrentspec = 6 then
          -- wearer function price
          discount_not_relevant := true;
          result_code           := 5; -- Price not relevant, wearer function price
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vdiscountlistpercust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select grp.discount, grp.startdate, g.code, g.description
                       from   generalrentdiscount grp, generaldiscountlist g
                       where  g.generaldiscountlist_id = lv_generaldiscountlistid
                       and    g.pricetype = 2 -- rent discount
                       and    g.active = 'Y'
                       and    grp.generaldiscountlist_id = g.generaldiscountlist_id
                       and    grp.product_id = productid
                       and    grp.sizedefinition_id = lv_size
                       and    grp.finishingmethod_id = finishingmethodid
                       and    grp.startdate <= lv_discountdate
                       order  by grp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc,
                   dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.discount, cupri.startdate
                       from   customerrentdiscount cupri
                       where  cupri.productlistpercustomer_id = lv_productlistpercustomerid
                       and    cupri.startdate <= lv_discountdate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch vdiscountlistpercust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when activ plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code         := '0';
      result_desc         := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G' then
        discount_list_desc := lv_discountlist_desc;
      else
        discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_rent_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_rent_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) || discount_found_yn ||
           rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(discount_list_type, ' '), 1) || rpad(nvl(discount_list_code, ' '), 6) ||
           rpad(nvl(discount_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80));
  end rent_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the discount, if not found, returns 0.  For use in calculations.  */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_rent_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(nvl(discount, 0));
  end rent_discount;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the discount, if not found, returns null.  For display/print purposes. */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_rent_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(discount);
  end rent_discount_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerwashdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerwashdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type) is
    pragma udf;
    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerwashdiscount.discount%type;
    lv_discount_start_date      customerwashdiscount.startdate%type;
    lv_generaldiscountlistid    generalwashdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_priceliststartdate       date;
    type tcsr is ref cursor;
    vcsr                 tcsr;
    vdiscountlistpercust tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Discount found', 'N1', 'Discount not defined', 'N2',
                     'Discount not relevant, billing method 3 with rent price only', 'N3',
                     'Discount not relevant, billing method = 1 flat rated rent', 'N4',
                     'Discount not relevant, billing method = 2 rent based on minimum', 'N5',
                     'Discount not relevant, disposable / sales only item', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

  begin
    -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found        := false;
    discount_not_relevant := false;
    discount              := null;
    discount_found_yn     := 'N';
    discount_start_date   := null;
    result_code           := null;
    result_desc           := null;
    discount_list_type    := null;
    discount_list_code    := null;
    discount_list_desc    := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    lv_size := sizedefinitionid;
    i       := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open vdiscountlistpercust for
        select discountlistpercustomer.generaldiscountlist_id, discountlistpercustomer.dateactive
        from   discountlistpercustomer
        where  discountlistpercustomer.customer_id = customerid
        and    discountlistpercustomer.pricetype = 1 -- this means wash discount
        and    discountlistpercustomer.dateactive <= lv_discountdate
        and    discountlistpercustomer.dateinactive >= lv_discountdate
        order  by discountlistpercustomer.priority;
      fetch vdiscountlistpercust
        into lv_generaldiscountlistid, lv_priceliststartdate;
      -- load weighingcategpercustomer etc to determine discount usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_typeofmerchandize        := null;
      lv_priceusage               := null;
      open vcsr for
        select plpc.productlistpercustomer_id, plpc.billingmethod, plpc.priceusage,
               p.typeofmerchandise
        from   productlistpercustomer plpc, product p
        where  plpc.customer_id = customerid
        and    plpc.product_id = productid
        and    plpc.sizedefinition_id = lv_size
        and    plpc.finishingmethod_id = finishingmethodid
        and    p.product_id = plpc.product_id
        and    ((lv_discountdate >= plpc.dateactive and lv_discountdate <= plpc.dateinactive) or
              i > 1)
        order  by plpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_typeofmerchandize;
        if lv_billingmethod = 3 and lv_priceusage = 2 then
          /* rent price only*/
          discount_not_relevant := true;
          result_code           := 2; -- Price not relevant, billing method 3 with rent price only
        end if;
        if lv_billingmethod = 1 /*and pricetype<>2*/
         then
          discount_not_relevant := true;
          result_code           := 3; -- Price not relevant, billing method = 1 flat rated rent only
        end if;
        if lv_billingmethod = 2 then
          discount_not_relevant := true;
          result_code           := 4; -- Price not relevant, billing method = 2 rent based on minimum
        end if;
        if lv_typeofmerchandize = 3 then
          discount_not_relevant := true;
          result_code           := 5; -- Price not relevant, disposable or sales only item.
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vdiscountlistpercust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gwp.discount, gwp.startdate, g.code, g.description
                       from   generalwashdiscount gwp, generaldiscountlist g
                       where  g.generaldiscountlist_id = lv_generaldiscountlistid
                       and    g.pricetype = 1 -- wash discount
                       and    g.active = 'Y'
                       and    gwp.generaldiscountlist_id = g.generaldiscountlist_id
                       and    gwp.product_id = productid
                       and    gwp.sizedefinition_id = lv_size
                       and    gwp.finishingmethod_id = finishingmethodid
                       and    gwp.startdate <= lv_discountdate
                       order  by gwp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc,
                   dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.discount, cupri.startdate
                       from   customerwashdiscount cupri
                       where  cupri.productlistpercustomer_id = lv_productlistpercustomerid
                       and    cupri.startdate <= lv_discountdate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch vdiscountlistpercust
          into lv_generaldiscountlistid, lv_priceliststartdate; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when activ plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := greatest(lv_discount_start_date, lv_priceliststartdate);
      result_code         := '0';
      result_desc         := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G' then
        discount_list_desc := lv_discountlist_desc;
      else
        discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_wash_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_wash_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) || discount_found_yn ||
           rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(discount_list_type, ' '), 1) || rpad(nvl(discount_list_code, ' '), 6) ||
           rpad(nvl(discount_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80));
  end wash_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the discount, if not found, returns 0.  For use in calculations.  */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_wash_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(nvl(discount, 0));
  end wash_discount;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the discount, if not found, returns null.  For display/print purposes. */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_wash_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(discount);
  end wash_discount_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_discount_details(customerid          in customer.customer_id%type,
                                        weighingcategoryid  in weighingcategory.weighingcategory_id%type,
                                        soil_yn             in customerweightdiscount.soil%type,
                                        discountdate        in discountlistpercustomer.dateactive%type,
                                        discount            out customerweightdiscount.discount%type,
                                        discount_found_yn   out varchar2,
                                        discount_start_date out customerweightdiscount.startdate%type,
                                        result_code         out number,
                                        result_desc         out varchar2,
                                        discount_list_type  out varchar2,
                                        discount_list_code  out generaldiscountlist.code%type,
                                        discount_list_desc  out generaldiscountlist.description%type) is
    pragma udf;
    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerweightdiscount.discount%type;
    lv_discount_start_date      customerweightdiscount.startdate%type;
    lv_generaldiscountlistid    generalwashdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_weighingcatpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    lv_invoice_method           weighingcategpercustomer.invoicemethod%type;
    lv_priceliststartdate       date;
    type tcsr is ref cursor;
    vcsr                 tcsr;
    vdiscountlistpercust tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Discount found', 'N1', 'Discount not defined', 'N2',
                     'Discount not relevant, weights not invoiced', 'N3',
                     'Discount not defined, weights invoiced soil, not clean ', 'N4',
                     'Discount not defined, weights invoiced clean, not soil ', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

  begin
    -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found        := false;
    discount_not_relevant := false;
    discount              := null;
    discount_found_yn     := 'N';
    discount_start_date   := null;
    result_code           := null;
    result_desc           := null;
    discount_list_type    := null;
    discount_list_code    := null;
    discount_list_desc    := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) or (weighingcategoryid is null) or (soil_yn not in ('Y', 'N')) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open vdiscountlistpercust for
        select discountlistpercustomer.generaldiscountlist_id, discountlistpercustomer.dateactive
        from   discountlistpercustomer
        where  discountlistpercustomer.customer_id = customerid
        and    discountlistpercustomer.pricetype = 5 -- this means weight discount
        and    discountlistpercustomer.dateactive <= lv_discountdate
        and    discountlistpercustomer.dateinactive >= lv_discountdate
        order  by discountlistpercustomer.priority;
      fetch vdiscountlistpercust
        into lv_generaldiscountlistid, lv_priceliststartdate;
      -- load weighingcategpercustomer etc to determine discount usage
      lv_weighingcatpercustomerid := null;
      lv_invoice_method           := null;
      open vcsr for
        select wcpc.weighingcategpercustomer_id, wcpc.invoicemethod
        from   weighingcategpercustomer wcpc
        where  wcpc.customer_id = customerid
        and    wcpc.weighingcategory_id = weighingcategoryid
        and    ((lv_discountdate >= wcpc.dateactive and lv_discountdate <= wcpc.dateinactive) or
              i > 1)
        order  by wcpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_weighingcatpercustomerid, lv_invoice_method;
        if lv_invoice_method = 1 then
          /* no invoicing based on weight */
          discount_not_relevant := true;
          result_code           := 2; -- discount not relevant, customer is not invoiced based on weight
        end if;
        if lv_invoice_method in (2, 4) and soil_yn = 'N' then
          /* configured soil, requested clean */
          discount_not_relevant := true;
          result_code           := 3; -- discount not relevant, customer is invoiced based on soil weight
        end if;
        if lv_invoice_method = 3 and soil_yn = 'Y' then
          /* configured clean, requested soil */
          discount_not_relevant := true;
          result_code           := 4; -- discount not relevant, customer is invoiced based on clean weight
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vdiscountlistpercust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gwp.discount, gwp.startdate, g.code, g.description
                       from   generalweightdiscount gwp, generaldiscountlist g
                       where  g.generaldiscountlist_id = lv_generaldiscountlistid
                       and    g.pricetype = 5 -- weight discount
                       and    g.active = 'Y'
                       and    gwp.generaldiscountlist_id = g.generaldiscountlist_id
                       and    gwp.weighingcategory_id = weighingcategoryid
                       and    gwp.soil = soil_yn
                       and    gwp.startdate <= lv_discountdate
                       order  by gwp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc,
                   dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.discount, cupri.startdate
                       from   customerweightdiscount cupri
                       where  cupri.weighingcategpercustomer_id = lv_weighingcatpercustomerid
                       and    cupri.soil = soil_yn
                       and    cupri.startdate <= lv_discountdate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch vdiscountlistpercust
          into lv_generaldiscountlistid, lv_priceliststartdate; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:  1 = try to find for active weighingcategorypercustomer
        2 = try to find for any weighingcategorypercustomer */
        i := i + 1;
        if lv_weighingcatpercustomerid is not null then
          -- active wcpc already found, so do not perform extra loop
          i := i + 1;
        end if;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := greatest(lv_priceliststartdate, lv_discount_start_date);
      result_code         := '0';
      result_desc         := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G' then
        discount_list_desc := lv_discountlist_desc;
      else
        discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_weight_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_discount_details(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_weight_discount_details(customerid, weighingcategoryid, soil_yn, discountdate, discount,
                                discount_found_yn, discount_start_date, result_code, result_desc,
                                discount_list_type, discount_list_code, discount_list_desc);
    return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) || discount_found_yn ||
           rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(discount_list_type, ' '), 1) || rpad(nvl(discount_list_code, ' '), 6) ||
           rpad(nvl(discount_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80));
  end weight_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_discount(customerid         in customer.customer_id%type,
                           weighingcategoryid in weighingcategory.weighingcategory_id%type,
                           soil_yn            in customerweightdiscount.soil%type,
                           discountdate       in discountlistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the discount, if not found, returns 0.  For use in calculations.  */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_weight_discount_details(customerid, weighingcategoryid, soil_yn, discountdate, discount,
                                discount_found_yn, discount_start_date, result_code, result_desc,
                                discount_list_type, discount_list_code, discount_list_desc);
    return(nvl(discount, 0));
  end weight_discount;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_discount_display(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the discount, if not found, returns null.  For display/print purposes. */
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  begin
    get_weight_discount_details(customerid, weighingcategoryid, soil_yn, discountdate, discount,
                                discount_found_yn, discount_start_date, result_code, result_desc,
                                discount_list_type, discount_list_code, discount_list_desc);
    return(discount);
  end weight_discount_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_residrent_price_details(customerid        in customer.customer_id%type,
                                        productid         in product.product_id%type,
                                        sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                        finishingmethodid in finishingmethod.finishingmethod_id%type,
                                        pricedate         in pricelistpercustomer.dateactive%type,
                                        price             out customerrentprice.price%type,
                                        price_found_yn    out varchar2,
                                        price_start_date  out customerrentprice.startdate%type,
                                        result_code       out number,
                                        result_desc       out varchar2,
                                        price_list_type   out varchar2,
                                        price_list_code   out generalpricelist.code%type,
                                        price_list_desc   out generalpricelist.description%type,
                                        price_type_code   out customerrentprice.typeofrent%type,
                                        price_type_desc   out varchar2) is
    pragma udf;
    price_found                boolean;
    price_not_relevant         boolean;
    lv_size                    sizedefinition.sizedefinition_id%type;
    lv_finmethod               finishingmethod.finishingmethod_id%type;
    i                          number;
    dummy                      number;
    lv_pricedate               date;
    lv_residentialrentid       residentialrent.residentialrent_id%type;
    lv_customergarmrentspec    customer.garmentrentspecification%type;
    lv_pricelist_type          varchar2(1);
    lv_custsplitinvperactivity customer.splitinvoicesperactivity%type;
    lv_typeofmerchandize       product.typeofmerchandise%type;
    lv_typeofrent              generalrentprice.typeofrent%type;
    lv_typeofrent_general      generalrentprice.typeofrent%type;
    lv_typeofrent_specific     generalrentprice.typeofrent%type;
    lv_productgroup_id         product.productgroup_id%type;
    lv_price                   customerresidentialrentprice.price%type;
    lv_price_start_date        customerresidentialrentprice.startdate%type;
    lv_generalpricelistid      generalrentprice.generalpricelist_id%type;
    lv_pricelist_code          generalpricelist.code%type;
    lv_pricelist_desc          generalpricelist.description%type;
    lv_priceliststartdate      date;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, billing method 3 with wash price only', 'N3',
                     'Price not relevant, billing method = 4 piece rate only', 'N4',
                     'Price not relevant, defined at wearer level as wearer total price', 'N5',
                     'Price not relevant, defined at wearer function level', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

    function decode_type_of_rent(fptypeofrent in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fptypeofrent, 9, 'Residential Rent', 'Unknown type of rent') into r from dual;
      return r;
    end;

  begin
    -- main rent price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found        := false;
    price_not_relevant := false;
    price              := null;
    price_found_yn     := 'N';
    price_start_date   := null;
    result_code        := null;
    result_desc        := null;
    price_list_type    := null;
    price_list_code    := null;
    price_list_desc    := null;
    price_type_code    := null;
    price_type_desc    := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size      := sizedefinitionid;
    lv_finmethod := finishingmethodid;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and (not price_not_relevant) loop
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id, pricelistpercustomer.dateactive
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 2
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid, lv_priceliststartdate;
      lv_residentialrentid       := null;
      lv_custsplitinvperactivity := null;
      open vcsr for
        select rr.residentialrent_id, p.typeofmerchandise, p.productgroup_id,
               c.garmentrentspecification, c.splitinvoicesperactivity, cur.decimals
        from   residentialrent rr, product p, customer c, currency cur
        where  rr.customer_id = customerid
        and    c.currency_id = cur.currency_id
        and    rr.product_id = productid
        and    p.product_id = productid
        and    c.customer_id = customerid
        and    rr.sizedefinition_id = lv_size
        and    rr.finishingmethod_id = lv_finmethod
        and    ((lv_pricedate >= rr.startdate and lv_pricedate <= rr.enddate) or i > 2)
        -- only filter on active in iteration 3 and 4
        order  by rr.startdate desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_residentialrentid, lv_typeofmerchandize, lv_productgroup_id,
               lv_customergarmrentspec, lv_custsplitinvperactivity, gv_decimals;
        lv_typeofrent          := 9;
        lv_typeofrent_general  := lv_typeofrent;
        lv_typeofrent_specific := lv_typeofrent;
      end if;
      close vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) and (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select grp.price, grp.startdate, g.code, g.description
                       from   generalrentprice grp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 2
                       and    g.active = 'Y'
                       and    grp.generalpricelist_id = g.generalpricelist_id
                       and    grp.product_id = productid
                       and    grp.sizedefinition_id = lv_size
                       and    grp.finishingmethod_id = lv_finmethod
                       and    grp.startdate <= lv_pricedate
                       and    grp.typeofrent = lv_typeofrent_general
                       order  by grp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid, lv_priceliststartdate; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- select original size again and try for an inactive plpc
          if lv_residentialrentid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if not price_found then
      open vcsr for
        select x.*, rownum
        from   (select cupri.price, cupri.startdate
                 from   customerresidentialrentprice cupri
                 where  cupri.customer_id = customerid
                 and    cupri.product_id = productid
                 and    cupri.sizedefinition_id = sizedefinitionid
                 and    cupri.finishingmethod_id = finishingmethodid
                 and    cupri.startdate <= lv_pricedate
                 order  by cupri.startdate desc) x
        where  rownum = 1; -- take first
      fetch vcsr
        into lv_price, lv_price_start_date, dummy;
      close vcsr;
      if lv_price is not null then
        price_found := true;
      end if;
    end if;
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := greatest(lv_priceliststartdate, lv_price_start_date);
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G' then
        price_list_desc := lv_pricelist_desc;
      else
        price_list_desc := 'Customer Specific.';
      end if;
      price_type_code := lv_typeofrent;
      price_type_desc := decode_type_of_rent(price_type_code);
    else
      if result_code is null then
        -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_residrent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function residentialrent_price_details(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(100);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerrentprice.typeofrent%type;
    price_type_desc  varchar2(30);
  begin
    get_residrent_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                pricedate, price, price_found_yn, price_start_date, result_code,
                                result_desc, price_list_type, price_list_code, price_list_desc,
                                price_type_code, price_type_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end residentialrent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function residentialrent_price(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(100);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerrentprice.typeofrent%type;
    price_type_desc  varchar2(30);
  begin
    get_residrent_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                pricedate, price, price_found_yn, price_start_date, result_code,
                                result_desc, price_list_type, price_list_code, price_list_desc,
                                price_type_code, price_type_desc);
    return(nvl(price, 0));
  end residentialrent_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function residentialrent_price_display(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(100);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerrentprice.typeofrent%type;
    price_type_desc  varchar2(30);
  begin
    get_residrent_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                pricedate, price, price_found_yn, price_start_date, result_code,
                                result_desc, price_list_type, price_list_code, price_list_desc,
                                price_type_code, price_type_desc);
    return(price);
  end residentialrent_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_loan_price_details(customerid        in customer.customer_id%type,
                                   productid         in product.product_id%type,
                                   sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerrentprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerrentprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type) is
    pragma udf;
    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_pricelist_type           varchar2(1);
    lv_typeofrent               customerrentprice.typeofrent%type;
    lv_price                    customerrentprice.price%type;
    lv_price_start_date         customerrentprice.startdate%type;
    lv_generalpricelistid       generalrentprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    lv_priceliststartdate       date;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;

  begin
    -- main loan price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    lv_typeofrent      := 10; -- Loan
    price_found        := false;
    price_not_relevant := false;
    price              := null;
    price_found_yn     := 'N';
    price_start_date   := null;
    result_code        := null;
    result_desc        := null;
    price_list_type    := null;
    price_list_code    := null;
    price_list_desc    := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size      := sizedefinitionid;
    lv_finmethod := finishingmethodid;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    --get decimals
    select max(cu.decimals)
    into   gv_decimals
    from   customer c
    join   currency cu
    on     cu.currency_id = c.currency_id
    where  c.customer_id = customerid;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and (not price_not_relevant) loop
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id, pricelistpercustomer.dateactive
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 2
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid, lv_priceliststartdate;
      -- load plpc
      lv_productlistpercustomerid := null;
      open vcsr for
        select plpc.productlistpercustomer_id
        from   productlistpercustomer plpc
        where  plpc.customer_id = customerid
        and    plpc.product_id = productid
        and    plpc.sizedefinition_id = lv_size
        and    plpc.finishingmethod_id = lv_finmethod
        and    ((lv_pricedate >= plpc.dateactive and lv_pricedate <= plpc.dateinactive) or i > 2)
        -- only filter on active in iteration 3 and 4
        order  by plpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_productlistpercustomerid;
      end if;
      close vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) and (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select grp.price, grp.startdate, g.code, g.description
                       from   generalrentprice grp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 2
                       and    g.active = 'Y'
                       and    grp.generalpricelist_id = g.generalpricelist_id
                       and    grp.product_id = productid
                       and    grp.sizedefinition_id = lv_size
                       and    grp.finishingmethod_id = lv_finmethod
                       and    grp.typeofrent = lv_typeofrent
                       and    grp.startdate <= lv_pricedate
                       order  by grp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.price, cupri.startdate
                       from   customerrentprice cupri
                       where  cupri.productlistpercustomer_id = lv_productlistpercustomerid
                       and    cupri.startdate <= lv_pricedate
                       and    cupri.typeofrent = lv_typeofrent
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, dummy;
            close vcsr;

            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid, lv_priceliststartdate; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- select original size again and try for an inactive plpc
          if lv_productlistpercustomerid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := greatest(lv_priceliststartdate, lv_price_start_date);
      result_code      := 0;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G' then
        price_list_desc := lv_pricelist_desc;
      else
        price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_loan_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function loan_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_loan_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           price, price_found_yn, price_start_date, result_code, result_desc,
                           price_list_type, price_list_code, price_list_desc);
    get_pricestr;
    return(rpad(nvl(to_char(price, gv_pricestr), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end loan_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function loan_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the loan price, if not found, returns 0.  For use in calculations.  */
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_loan_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           price, price_found_yn, price_start_date, result_code, result_desc,
                           price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end loan_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function loan_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    pragma udf;
    /* Returns the loan price, if not found, returns null.  For display/print purposes. */
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  begin
    get_loan_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           price, price_found_yn, price_start_date, result_code, result_desc,
                           price_list_type, price_list_code, price_list_desc);
    return(price);
  end loan_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  function budget_price(fpcustomerid    customerbudgetdefinition.customer_id%type,
                        fpcode          customerbudgetdefinition.code%type,
                        fpreferencedate date) return number is
    pragma udf;
    /* Returns the budget price, if not found, returns 0.  For use in calculations.  */
    vcustbudgetdefid customerbudgetdefinition.customerbudgetdefinition_id%type;
    vprice           number;
  begin
    select cbd.customerbudgetdefinition_id
    into   vcustbudgetdefid
    from   customerbudgetdefinition cbd
    where  cbd.customer_id = fpcustomerid
    and    cbd.code = fpcode;
    begin
      select cbp.price
      into   vprice
      from   customerbudgetprice cbp
      where  cbp.customerbudgetdefinition_id = vcustbudgetdefid
      and    cbp.startdate <= fpreferencedate
      and    cbp.startdate = (select max(cbp.startdate)
                              from   customerbudgetprice cbp
                              where  cbp.customerbudgetdefinition_id = vcustbudgetdefid
                              and    cbp.startdate <= fpreferencedate);

      return vprice;
    exception
      when no_data_found then
        return 0;
    end;
  end budget_price;
  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_budgetprotectionprice_details(fp_customerid        in customer.customer_id%type,
                                              fp_productid         in product.product_id%type,
                                              fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                              fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                              fp_pricecomponent    in customerbgprotectionprice.pricecomponent%type,
                                              fp_pricedate         in pricelistpercustomer.dateactive%type,
                                              fp_price             out customerwashprice.price%type,
                                              fp_price_found_yn    out varchar2,
                                              fp_price_start_date  out customerwashprice.startdate%type,
                                              fp_result_code       out number,
                                              fp_result_desc       out varchar2,
                                              fp_price_list_type   out varchar2,
                                              fp_price_list_code   out generalpricelist.code%type,
                                              fp_price_list_desc   out generalpricelist.description%type) is
    pragma udf;
    --locale variables
    procedure initialize is
      lv_pricedate                   date;
      lv_plpcid                      number;
      lv_billingmethod               number;
      lv_inventorybillingtype        number;
      lv_chargelossforpool           varchar2(1);
      lv_priceusage                  number;
      lv_tom                         number;
      lv_garmentrentspecification    number;
      lv_sizestarid                  sizedefinition.sizedefinition_id%type;
      lv_businessunitid              number;
      lv_chargewashesonlyforcog      productlistpercustomer.chargewashesonlyforcog%type;
      lv_minimumturnaround           productlistpercustomer.minimumturnaround%type;
      lv_rentpriceperfrequency       productlistpercustomer.rentpriceperfrequency%type;
      lv_invoicefreqrelatedrentprice productlistpercustomer.invoicefreqrelatedrentprice%type;
      lv_splitinvoicesperactivity    customer.splitinvoicesperactivity%type;
      lv_productgroupid              product.productgroup_id%type;
      lv_garmentsetup                plpcbudgetprotection.garmentsetup%type;
    begin
      --initialize, get size star
      lv_sizestarid := getsizestarid;
      lv_pricedate  := fp_pricedate;
      --get plpc info
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
      --
      select lpb.garmentsetup
      into   lv_garmentsetup
      from   plpcbudgetprotection lpb
      where  lpb.productlistpercustomer_id = lv_plpcid;
      if lv_garmentsetup = 'N' then
        raise no_data_found;
      end if;
    end initialize;

    procedure get_generalbpprice(fp_generalpricelistid in generalpricelist.generalpricelist_id%type) is
    begin
      --get_generalbpprice
      for x in (select gbp.price, gbp.startdate, gpl.code, gpl.description
                from   generalbgprotectionprice gbp
                join   generalpricelist gpl
                on     gpl.generalpricelist_id = gbp.generalpricelist_id
                where  gbp.generalpricelist_id = fp_generalpricelistid
                and    gbp.product_id = fp_productid
                and    gbp.sizedefinition_id = fp_sizedefinitionid
                and    gbp.pricecomponent = fp_pricecomponent
                and    gbp.startdate <= fp_pricedate
                and    gpl.active = 'Y'
                order  by gbp.startdate desc) loop
        begin
          fp_price_start_date := greatest(fp_price_start_date, x.startdate);
          fp_price_list_type  := 'G'; --General price list
          fp_price_list_code  := x.code;
          fp_price_list_desc  := x.description;
          fp_price            := x.price;
          fp_price_found_yn   := 'Y';
          exit;
        end;
      end loop; --x
    end get_generalbpprice;

    procedure get_customerbpprice is
    begin
      --get_customerbpprice
      for y in (select cbp.price, cbp.startdate
                from   customerbgprotectionprice cbp
                where  cbp.customer_id = fp_customerid
                and    cbp.product_id = fp_productid
                and    cbp.sizedefinition_id = fp_sizedefinitionid
                and    cbp.pricecomponent = fp_pricecomponent
                order  by cbp.startdate desc) loop
        begin
          fp_price_start_date := greatest(fp_price_start_date, y.startdate);
          fp_price_list_type  := 'C'; --Customer specific
          fp_price_list_code  := null;
          fp_price_list_desc  := 'Customer Specific.';
          fp_price            := y.price;
          fp_price_found_yn   := 'Y';
          exit;
        end;
      end loop; --y
    end get_customerbpprice;
  begin
    --initialize
    initialize;
    --get_budgetprotectionprice_details
    for x in (select plc.generalpricelist_id, plc.dateactive
              from   pricelistpercustomer plc
              where  plc.customer_id = fp_customerid
              and    plc.pricetype = 9 -- budgetprotectionprice
              and    plc.dateactive <= fp_pricedate
              and    plc.dateinactive >= fp_pricedate
              order  by plc.priority asc, plc.dateactive desc) loop
      begin
        fp_price_start_date := x.dateactive;
        if x.generalpricelist_id is not null then
          begin
            get_generalbpprice(x.generalpricelist_id);
          end;
        else
          begin
            get_customerbpprice;
          end;
        end if;
        if fp_price_found_yn = 'Y' then
          begin
            fp_result_code := '0';
            fp_result_desc := 'Price found';
            exit;
          end;
        end if;
      end;
    end loop; --x
    if nvl(fp_price_found_yn, 'N') <> 'Y' then
      begin
        raise no_data_found;
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_price            := 0;
        fp_price_start_date := null;
        fp_price_list_type  := null;
        fp_price_list_code  := null;
        fp_price_list_desc  := null;
        fp_price_found_yn   := 'N';
        fp_result_code      := '1';
        fp_result_desc      := 'Price not defined';
      end;
  end get_budgetprotectionprice_details;

  function budgetprotectionprice_details(fp_customerid        in customer.customer_id%type,
                                         fp_productid         in product.product_id%type,
                                         fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         fp_pricecomponent    in customerbgprotectionprice.pricecomponent%type,
                                         fp_pricedate         in pricelistpercustomer.dateactive%type default trunc(sysdate))
    return varchar2 is
    pragma udf;
    /* See package header for description of return string.   */
    lv_price            number;
    lv_price_found_yn   varchar2(1);
    lv_price_start_date customerrentprice.startdate%type;
    lv_result_code      number;
    lv_result_desc      varchar2(80);
    lv_price_list_type  varchar2(1);
    lv_price_list_code  generalpricelist.code%type;
    lv_price_list_desc  generalpricelist.description%type;
  begin
    --call get_budgetprotectionprice_details
    get_budgetprotectionprice_details(fp_customerid, fp_productid, fp_sizedefinitionid,
                                      fp_finishingmethodid, nvl(fp_pricecomponent, 1),
                                      nvl(fp_pricedate, trunc(sysdate)), lv_price, lv_price_found_yn,
                                      lv_price_start_date, lv_result_code, lv_result_desc,
                                      lv_price_list_type, lv_price_list_code, lv_price_list_desc);
    get_pricestr;
    return(rpad(nvl(to_char(lv_price, gv_pricestr), ' '), 12) || lv_price_found_yn ||
           rpad(nvl(to_char(lv_price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(lv_price_list_type, ' '), 1) ||
           rpad(nvl(substr(lv_price_list_code, 1, 6), ' '), 6) ||
           rpad(nvl(lv_price_list_desc, ' '), 40) || rpad(nvl(to_char(lv_result_code), ' '), 1) ||
           rpad(nvl(lv_result_desc, ' '), 80));
  end budgetprotectionprice_details;

  function budgetprotectionprice(fp_customerid        in customer.customer_id%type,
                                 fp_productid         in product.product_id%type,
                                 fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 fp_pricecomponent    in customerbgprotectionprice.pricecomponent%type,
                                 fp_pricedate         in pricelistpercustomer.dateactive%type default trunc(sysdate))
    return number is
    pragma udf;
    lv_price            number;
    lv_price_found_yn   varchar2(1);
    lv_price_start_date customerrentprice.startdate%type;
    lv_result_code      number;
    lv_result_desc      varchar2(80);
    lv_price_list_type  varchar2(1);
    lv_price_list_code  generalpricelist.code%type;
    lv_price_list_desc  generalpricelist.description%type;
  begin
    --call get_budgetprotectionprice_details
    get_budgetprotectionprice_details(fp_customerid, fp_productid, fp_sizedefinitionid,
                                      fp_finishingmethodid, nvl(fp_pricecomponent, 1),
                                      nvl(fp_pricedate, trunc(sysdate)), lv_price, lv_price_found_yn,
                                      lv_price_start_date, lv_result_code, lv_result_desc,
                                      lv_price_list_type, lv_price_list_code, lv_price_list_desc);
    return lv_price;
  exception
    when no_data_found then
      return 0;
  end budgetprotectionprice;
  /*--------------------------------------------------------------------------------------------------------*/
  function customer_uses_specialprices(customerid in customer.customer_id%type) return boolean is
    pragma udf;
    use_special_prices customer.useprodsizesurchargepricing%type;
  begin
    select c.useprodsizesurchargepricing
    into   use_special_prices
    from   customer c
    where  c.customer_id = customerid;
    return use_special_prices = 'Y';
  exception
    when no_data_found then
      return false;
  end customer_uses_specialprices;

  function get_standard_szbillinggroup return number is
    pragma udf;
    standard_sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
  begin
    select min(sz.sizebillinggroup_id)
    into   standard_sizebillinggroupid
    from   sizebillinggroup sz
    where  sz.standard = 'Y';
    return nvl(standard_sizebillinggroupid, 0);
  exception
    when too_many_rows then
      return 0; --should only be 1 standard
    when no_data_found then
      return 0;
  end get_standard_szbillinggroup;

  procedure get_size_billing_groups(customerid                     in customer.customer_id%type,
                                    productid                      in product.product_id%type,
                                    sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                    pricetype                      number,
                                    lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                    lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type) is
    pragma udf;
    lv_customer_uses_sz_billing    boolean;
    lv_ss_sizespecialchargeoptions int;
    lv_is_special_size_price_used  boolean;
  begin
    begin
      select value
      into   lv_ss_sizespecialchargeoptions
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'SIZESPECIALCHARGEOPTIONS'
      and    c.customer_id = customerid;
    exception
      when no_data_found then
        lv_ss_sizespecialchargeoptions := 0;
    end;
    if pricetype = 2 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 1 or
                                       lv_ss_sizespecialchargeoptions = 4 or
                                       lv_ss_sizespecialchargeoptions = 5 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    if pricetype = 3 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 3 or
                                       lv_ss_sizespecialchargeoptions = 5 or
                                       lv_ss_sizespecialchargeoptions = 6 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    if pricetype = 4 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 2 or
                                       lv_ss_sizespecialchargeoptions = 4 or
                                       lv_ss_sizespecialchargeoptions = 6 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    lv_customer_uses_sz_billing    := customer_uses_specialprices(customerid);
    lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
    if lv_customer_uses_sz_billing and lv_is_special_size_price_used then
      lv_specific_sizebillinggroupid := get_product_size_billinggroup(productid, sizedefinitionid);
    else
      lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
    end if;
  end get_size_billing_groups;

end pack_price;
/
create or replace package pack_priceupdate is

  /****************************************************************************\
  * -- Author   : PVD                                                          *
  * -- Created  : 22-9-2009                                                    *
  * -- Purpose  : Update of prices                                             *
  * -- Messages : 0 ok                                                         *
  *               1 no data found                                              *
  *               2 wrong value used                                           *
  *               3 duplicate value on index                                   *
  *               4 other error message                                        *
  \****************************************************************************/

  function generalpriceupdate(fp_pricetypechar          in varchar2,
                              fp_from_pricelistcode     in generalpricelist.code%type,
                              fp_to___pricelistcode     in generalpricelist.code%type,
                              fp_invoicefrequencynumber in number, --0 is no invoice select!
                              fp_startdate              in date,
                              fp_checkdate              in date, -- prices after this date are NOT to be updated!
                              fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                              fp_updatenumber           in number, -- depends on updatetype if it is a percentage or amount
                              fp_maxprice               in number,
                              fp_from_productgroup      in productgroup.code%type,
                              fp_to___productgroup      in productgroup.code%type,
                              fp_from_product           in product.code%type,
                              fp_to___product           in product.code%type,
                              fp_from_size              in sizedefinition.code%type,
                              fp_to___size              in sizedefinition.code%type,
                              fp_from_finishingmethod   in finishingmethod.code%type,
                              fp_to___finishingmethod   in finishingmethod.code%type) return number;

  function customerpriceupdate(fp_pricetypechar          in varchar2,
                               fp_from_customernumber    in customer.customernumber%type,
                               fp_to___customernumber    in customer.customernumber%type,
                               fp_from_chaincode         in chain.code%type,
                               fp_to___chaincode         in chain.code%type,
                               fp_from_activitycode      in activity.code%type,
                               fp_to___activitycode      in activity.code%type,
                               fp_invoicefrequencynumber in number, --0 is no invoice select!
                               fp_startdate              in date,
                               fp_checkdate              in date, -- prices after this date are NOT to be updated!
                               fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                               fp_updatenumber           in number, -- depends on updatetype if it is a percentage or amount
                               fp_maxprice               in number,
                               fp_from_productgroup      in productgroup.code%type,
                               fp_to___productgroup      in productgroup.code%type,
                               fp_from_product           in product.code%type,
                               fp_to___product           in product.code%type,
                               fp_from_size              in sizedefinition.code%type,
                               fp_to___size              in sizedefinition.code%type,
                               fp_from_finishingmethod   in finishingmethod.code%type,
                               fp_to___finishingmethod   in finishingmethod.code%type) return number;

end pack_priceupdate;
/
create or replace package body pack_priceupdate is
  gv_roundfactor number := 3;
  gv_wrongvalue exception;
  gv_defaultuserid  systemuser.systemuser_id%type;
  gv_defaultusrname systemuser.username%type := 'SYSADM';
  gv_message        abslog.message%type;

  procedure write_log(fp_message  in abslog.message%type,
                      fp_priority in abslog.priority%type default 1) is
  begin
    /*
    Write message in ABSLOG with these priorities
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info
    */
    abslogwrite.abslog_write(5, 'pack_priceupdate', null, fp_priority, fp_message,
                             gv_defaultuserid);
  end write_log;

  function build_where_clause(fp_checkdate              in date, -- prices after this date are NOT to be updated!
                              fp_from_productgroup      in productgroup.code%type,
                              fp_to___productgroup      in productgroup.code%type,
                              fp_from_product           in product.code%type,
                              fp_to___product           in product.code%type,
                              fp_from_size              in sizedefinition.code%type,
                              fp_to___size              in sizedefinition.code%type,
                              fp_from_finishingmethod   in finishingmethod.code%type,
                              fp_to___finishingmethod   in finishingmethod.code%type,
                              fp_invoicefrequencynumber in number default null) return varchar2 is
    lv_whereclause varchar2(512) := null;
  begin
    gv_message := 'build where clause';
    --check date
    if fp_checkdate is not null then
      lv_whereclause := lv_whereclause || ' and gp.startdate < to_date(''' ||
                        to_char(fp_checkdate, 'dd-mm-yyyy') || ''',''dd-mm-yyyy'')';
    end if;
    --product group selection
    if fp_from_productgroup is not null and fp_to___productgroup is not null then
      lv_whereclause := lv_whereclause ||
                        ' and p.productgroup_id in ( select pg.productgroup_id from productgroup pg where pg.code between ''' ||
                        fp_from_productgroup || ''' and ''' || fp_to___productgroup || ''')';
    end if;
    --product selection
    if fp_from_product is not null and fp_to___product is not null then
      lv_whereclause := lv_whereclause || ' and p.code between ''' || fp_from_product ||
                        ''' and ''' || fp_to___product || '''';
    end if;
    --size selection
    if fp_from_size is not null and fp_to___size is not null then
      lv_whereclause := lv_whereclause || ' and s.code between ''' || fp_from_size || ''' and ''' ||
                        fp_to___size || '''';
    end if;
    --finishingmethod selection
    if fp_from_finishingmethod is not null and fp_to___finishingmethod is not null then
      lv_whereclause := lv_whereclause || ' and f.code between ''' || fp_from_finishingmethod ||
                        ''' and ''' || fp_to___finishingmethod || '''';
    end if;
    --optional invoicefrequencynumber select ---->ONLY for RENT
    if fp_invoicefrequencynumber is not null and fp_invoicefrequencynumber <> 10 then
      lv_whereclause := lv_whereclause ||
                        ' and gp.typeofrent = 8 and gp.invoicefrequencynumber =  ' ||
                        fp_invoicefrequencynumber;
    end if;
    return lv_whereclause;
  end build_where_clause;

  function build_where_clause_customer(fp_from_customernumber in customer.customernumber%type,
                                       fp_to___customernumber in customer.customernumber%type,
                                       fp_from_chaincode      in chain.code%type,
                                       fp_to___chaincode      in chain.code%type,
                                       fp_from_activitycode   in activity.code%type,
                                       fp_to___activitycode   in activity.code%type) return varchar2 is
    lv_whereclause varchar2(512) := null;
  begin
    gv_message := 'build where clause customer';
    --customer selection
    if fp_from_customernumber is not null and fp_to___customernumber is not null then
      lv_whereclause := lv_whereclause || ' and c.customernumber between ' ||
                        fp_from_customernumber || ' and ' || fp_to___customernumber;
    end if;
    --chain code selection
    if fp_from_chaincode is not null and fp_to___chaincode is not null then
      lv_whereclause := lv_whereclause || ' and ch.code between ''' || fp_from_chaincode ||
                        ''' and ''' || fp_to___chaincode || '''';
    end if;
    --activity selection
    if fp_from_activitycode is not null and fp_to___activitycode is not null then
      lv_whereclause := lv_whereclause ||
                        ' and exists ( select 1 from customeractivities ca, activity a
                                       where ca.customer_id = c.customer_id
                                         and a.code between ''' ||
                        fp_from_activitycode || ''' and ''' || fp_to___activitycode || ''')';
    end if;
    return lv_whereclause;
  end build_where_clause_customer;

  procedure update_generalrentprice(lvrec_generalrentprice in out generalrentprice%rowtype,
                                    fp_startdate           in date,
                                    fp_updatetype          in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                    fp_updatenumber        in number, -- depends on updatetype if it is a percentage or amount
                                    fp_maxprice            in number) is
  begin
    gv_message := 'update_generalrentprice, copying generalrentprice id ' ||
                  lvrec_generalrentprice.generalrentprice_id;
    select seq_generalrentprice.nextval into lvrec_generalrentprice.generalrentprice_id from dual;
    lvrec_generalrentprice.startdate     := fp_startdate;
    lvrec_generalrentprice.systemuser_id := gv_defaultuserid;
    lvrec_generalrentprice.timestamp     := sysdate;
    if fp_updatetype = 0 then
      if lvrec_generalrentprice.price + ((fp_updatenumber / 100) * lvrec_generalrentprice.price) <=
         fp_maxprice then
        --percentage
        lvrec_generalrentprice.price := round(lvrec_generalrentprice.price +
                                              ((fp_updatenumber / 100) *
                                              lvrec_generalrentprice.price), gv_roundfactor);
        insert into generalrentprice values lvrec_generalrentprice;
      else
        if fp_maxprice > lvrec_generalrentprice.price then
          lvrec_generalrentprice.price := fp_maxprice;
          insert into generalrentprice values lvrec_generalrentprice;
        end if;
      end if; -- percentage
    else
      --fixed amount
      if lvrec_generalrentprice.price + fp_updatenumber <= fp_maxprice then
        lvrec_generalrentprice.price := round(lvrec_generalrentprice.price + fp_updatenumber,
                                              gv_roundfactor);
        insert into generalrentprice values lvrec_generalrentprice;
      else
        --price > then max, only update if maxprice is more then current price
        if fp_maxprice > lvrec_generalrentprice.price then
          lvrec_generalrentprice.price := fp_maxprice;
          insert into generalrentprice values lvrec_generalrentprice;
        end if;
      end if;
    end if; --fixed amount
  end update_generalrentprice;

  procedure update_generalrentprices(fppricelistcode           generalpricelist.code%type,
                                     fp_generalpricelistid     in generalpricelist.generalpricelist_id%type,
                                     fp_invoicefrequencynumber in number, --0 is no invoice select!
                                     fp_startdate              in date,
                                     fp_checkdate              in date, -- prices after this date are NOT to be updated!
                                     fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                     fp_updatenumber           in number, -- depends on updatetype if it is a percentage or amount
                                     fp_maxprice               in number,
                                     fp_from_productgroup      in productgroup.code%type,
                                     fp_to___productgroup      in productgroup.code%type,
                                     fp_from_product           in product.code%type,
                                     fp_to___product           in product.code%type,
                                     fp_from_size              in sizedefinition.code%type,
                                     fp_to___size              in sizedefinition.code%type,
                                     fp_from_finishingmethod   in finishingmethod.code%type,
                                     fp_to___finishingmethod   in finishingmethod.code%type) is
    lv_whereclause varchar2(512) := null;
    type cursor_type is ref cursor;
    x                      cursor_type;
    lvrec_generalrentprice generalrentprice%rowtype;
    lv_counter             number := 0;
  begin
    gv_message     := 'update general rentprice lists';
    lv_whereclause := build_where_clause(fp_checkdate, fp_from_productgroup, fp_to___productgroup,
                                         fp_from_product, fp_to___product, fp_from_size, fp_to___size,
                                         fp_from_finishingmethod, fp_to___finishingmethod,
                                         fp_invoicefrequencynumber);
    --process based on all records from table ptvextid that are selected with where clause
    gv_message := 'loop generalrentprice';
    open x for 'select gp.*
                from   generalrentprice gp, product p, sizedefinition s, finishingmethod f
                where  gp.generalpricelist_id = ' || fp_generalpricelistid || ' and    gp.product_id = p.product_id
                and    gp.sizedefinition_id = s.sizedefinition_id
                and    gp.startdate = ( select max(gx.startdate)
                                        from generalrentprice gx
                                        where gx.generalpricelist_id = gp.generalpricelist_id
                                        and gx.product_id =gp.product_id
                                        and gx.sizedefinition_id = gp.sizedefinition_id
                                        and gx.finishingmethod_id = gp.finishingmethod_id
                                        and gx.typeofrent = gp.typeofrent
                                        and gx.startdate < to_date(''' || to_char(fp_startdate,
                                                                                      'dd-mm-yyyy') || ''',''dd-mm-yyyy'')
                                        and gx.changesperweek = gp.changesperweek
                                        and gx.invoicefrequencynumber = gp.invoicefrequencynumber )
                and   gp.finishingmethod_id = f.finishingmethod_id' || lv_whereclause;
    loop
      begin
        --fetch next row, and stop if no more rows
        fetch x
          into lvrec_generalrentprice;
        exit when x%notfound;
        gv_message := 'update_generalrentprice id / startdate ' ||
                      lvrec_generalrentprice.generalrentprice_id || ' / ' || fp_startdate;
        update_generalrentprice(lvrec_generalrentprice, fp_startdate, fp_updatetype,
                                fp_updatenumber, fp_maxprice);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    commit;
    write_log(to_char(lv_counter) || ' generalrent prices inserted' || fppricelistcode);
  end update_generalrentprices;

  procedure update_generalsalesprice(lvrec_generalsalesprice in out generalsalesprice%rowtype,
                                     fp_startdate            in date,
                                     fp_updatetype           in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                     fp_updatenumber         in number, -- depends on updatetype if it is a percentage or amount
                                     fp_maxprice             in number) is
  begin
    gv_message := 'update_generalsalesprice, copying generalsalesprice id ' ||
                  lvrec_generalsalesprice.generalsalesprice_id;
    select seq_generalsalesprice.nextval
    into   lvrec_generalsalesprice.generalsalesprice_id
    from   dual;
    lvrec_generalsalesprice.startdate     := fp_startdate;
    lvrec_generalsalesprice.systemuser_id := gv_defaultuserid;
    lvrec_generalsalesprice.timestamp     := sysdate;
    if fp_updatetype = 0 then
      if lvrec_generalsalesprice.price + ((fp_updatenumber / 100) * lvrec_generalsalesprice.price) <=
         fp_maxprice then
        --percentage
        lvrec_generalsalesprice.price := round(lvrec_generalsalesprice.price +
                                               ((fp_updatenumber / 100) *
                                               lvrec_generalsalesprice.price), gv_roundfactor);
        insert into generalsalesprice values lvrec_generalsalesprice;
      else
        if fp_maxprice > lvrec_generalsalesprice.price then
          lvrec_generalsalesprice.price := fp_maxprice;
          insert into generalsalesprice values lvrec_generalsalesprice;
        end if;
      end if; -- percentage
    else
      --fixed amount
      if lvrec_generalsalesprice.price + fp_updatenumber <= fp_maxprice then
        lvrec_generalsalesprice.price := round(lvrec_generalsalesprice.price + fp_updatenumber,
                                               gv_roundfactor);
        insert into generalsalesprice values lvrec_generalsalesprice;
      else
        --price > then max, only update if maxprice is more then current price
        if fp_maxprice > lvrec_generalsalesprice.price then
          lvrec_generalsalesprice.price := fp_maxprice;
          insert into generalsalesprice values lvrec_generalsalesprice;
        end if;
      end if;
    end if; --fixed amount
  end update_generalsalesprice;

  procedure update_generalsalesprices(fppricelistcode       generalpricelist.code%type,
                                      fp_generalpricelistid in generalpricelist.generalpricelist_id%type,
                                      fp_startdate          in date,
                                      fp_checkdate          in date, -- prices after this date are NOT to be updated!
                                      fp_updatetype         in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                      fp_updatenumber       in number, -- depends on updatetype if it is a percentage or amount
                                      fp_maxprice           in number,
                                      fp_from_productgroup  in productgroup.code%type,
                                      fp_to___productgroup  in productgroup.code%type,
                                      fp_from_product       in product.code%type,
                                      fp_to___product       in product.code%type,
                                      fp_from_size          in sizedefinition.code%type,
                                      fp_to___size          in sizedefinition.code%type) is
    lv_whereclause varchar2(512) := null;
    type cursor_type is ref cursor;
    x                       cursor_type;
    lvrec_generalsalesprice generalsalesprice%rowtype;
    lv_counter              number := 0;
  begin
    gv_message     := 'update general salesprice lists';
    lv_whereclause := build_where_clause(fp_checkdate, fp_from_productgroup, fp_to___productgroup,
                                         fp_from_product, fp_to___product, fp_from_size, fp_to___size,
                                         null, null);
    --process based on all records from table ptvextid that are selected with where clause
    gv_message := 'loop generalsalesprice';
    open x for 'select gp.*
                from   generalsalesprice gp, product p, sizedefinition s
                where  gp.generalpricelist_id = ' || fp_generalpricelistid || ' and    gp.product_id = p.product_id
                and    gp.sizedefinition_id = s.sizedefinition_id
                and    gp.startdate = ( select max(gx.startdate)
                                        from generalsalesprice gx
                                        where gx.generalpricelist_id = gp.generalpricelist_id
                                        and gx.product_id =gp.product_id
                                        and gx.sizedefinition_id = gp.sizedefinition_id
                                        and gx.finishingmethod_id = gp.finishingmethod_id
                                        and gx.pricetype = gp.pricetype
                                        and gx.startdate < to_date(''' || to_char(fp_startdate,
                                                                                      'dd-mm-yyyy') || ''',''dd-mm-yyyy''))' || lv_whereclause;
    loop
      begin
        --fetch next row, and stop if no more rows
        fetch x
          into lvrec_generalsalesprice;
        exit when x%notfound;
        gv_message := 'update_generalsalesprice id / startdate ' ||
                      lvrec_generalsalesprice.generalsalesprice_id || ' / ' || fp_startdate;
        update_generalsalesprice(lvrec_generalsalesprice, fp_startdate, fp_updatetype,
                                 fp_updatenumber, fp_maxprice);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    commit;
    write_log(to_char(lv_counter) || ' generalsales prices inserted' || fppricelistcode);
  end update_generalsalesprices;

  procedure update_generalwashprice(lvrec_generalwashprice in out generalwashprice%rowtype,
                                    fp_startdate           in date,
                                    fp_updatetype          in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                    fp_updatenumber        in number, -- depends on updatetype if it is a percentage or amount
                                    fp_maxprice            in number) is
  begin
    gv_message := 'update_generalwashprice, copying generalwashprice id ' ||
                  lvrec_generalwashprice.generalwashprice_id;
    select seq_generalwashprice.nextval into lvrec_generalwashprice.generalwashprice_id from dual;
    lvrec_generalwashprice.startdate     := fp_startdate;
    lvrec_generalwashprice.systemuser_id := gv_defaultuserid;
    lvrec_generalwashprice.timestamp     := sysdate;
    if fp_updatetype = 0 then
      if lvrec_generalwashprice.price + ((fp_updatenumber / 100) * lvrec_generalwashprice.price) <=
         fp_maxprice then
        --percentage
        lvrec_generalwashprice.price := round(lvrec_generalwashprice.price +
                                              ((fp_updatenumber / 100) *
                                              lvrec_generalwashprice.price), gv_roundfactor);
        insert into generalwashprice values lvrec_generalwashprice;
      else
        if fp_maxprice > lvrec_generalwashprice.price then
          lvrec_generalwashprice.price := fp_maxprice;
          insert into generalwashprice values lvrec_generalwashprice;
        end if;
      end if; -- percentage
    else
      --fixed amount
      if lvrec_generalwashprice.price + fp_updatenumber <= fp_maxprice then
        lvrec_generalwashprice.price := round(lvrec_generalwashprice.price + fp_updatenumber,
                                              gv_roundfactor);
        insert into generalwashprice values lvrec_generalwashprice;
      else
        --price > then max, only update if maxprice is more then current price
        if fp_maxprice > lvrec_generalwashprice.price then
          lvrec_generalwashprice.price := fp_maxprice;
          insert into generalwashprice values lvrec_generalwashprice;
        end if;
      end if;
    end if; --fixed amount
  end update_generalwashprice;

  procedure update_generalwashprices(fppricelistcode         generalpricelist.code%type,
                                     fp_generalpricelistid   in generalpricelist.generalpricelist_id%type,
                                     fp_startdate            in date,
                                     fp_checkdate            in date, -- prices after this date are NOT to be updated!
                                     fp_updatetype           in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                     fp_updatenumber         in number, -- depends on updatetype if it is a percentage or amount
                                     fp_maxprice             in number,
                                     fp_from_productgroup    in productgroup.code%type,
                                     fp_to___productgroup    in productgroup.code%type,
                                     fp_from_product         in product.code%type,
                                     fp_to___product         in product.code%type,
                                     fp_from_size            in sizedefinition.code%type,
                                     fp_to___size            in sizedefinition.code%type,
                                     fp_from_finishingmethod in finishingmethod.code%type,
                                     fp_to___finishingmethod in finishingmethod.code%type) is
    lv_whereclause varchar2(512) := null;
    type cursor_type is ref cursor;
    x                      cursor_type;
    lvrec_generalwashprice generalwashprice%rowtype;
    lv_counter             number := 0;
  begin
    gv_message     := 'update general washprice lists';
    lv_whereclause := build_where_clause(fp_checkdate, fp_from_productgroup, fp_to___productgroup,
                                         fp_from_product, fp_to___product, fp_from_size, fp_to___size,
                                         fp_from_finishingmethod, fp_to___finishingmethod);
    --process based on all records from table ptvextid that are selected with where clause
    gv_message := 'loop generalwashprice';
    open x for 'select gp.*
                from   generalwashprice gp, product p, sizedefinition s, finishingmethod f
                where  gp.generalpricelist_id = ' || fp_generalpricelistid || ' and    gp.product_id = p.product_id
                and    gp.sizedefinition_id = s.sizedefinition_id
                and    gp.startdate = ( select max(gx.startdate)
                                        from generalwashprice gx
                                        where gx.generalpricelist_id = gp.generalpricelist_id
                                        and gx.product_id =gp.product_id
                                        and gx.sizedefinition_id = gp.sizedefinition_id
                                        and gx.finishingmethod_id = gp.finishingmethod_id
                                        and gx.pricetype = gp.pricetype
                                        and gx.startdate < to_date(''' || to_char(fp_startdate,
                                                                                      'dd-mm-yyyy') || ''',''dd-mm-yyyy''))
                and   gp.finishingmethod_id = f.finishingmethod_id' || lv_whereclause;
    loop
      begin
        --fetch next row, and stop if no more rows
        fetch x
          into lvrec_generalwashprice;
        exit when x%notfound;
        gv_message := 'update_generalwashprice id / startdate ' ||
                      lvrec_generalwashprice.generalwashprice_id || ' / ' || fp_startdate;
        update_generalwashprice(lvrec_generalwashprice, fp_startdate, fp_updatetype,
                                fp_updatenumber, fp_maxprice);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    commit;
    write_log(to_char(lv_counter) || ' generalwash prices inserted for pricelist ' ||
              fppricelistcode);
  end update_generalwashprices;

  procedure update_customerrentprice(lvrec_customerrentprice in out customerrentprice%rowtype,
                                     fp_startdate            in date,
                                     fp_updatetype           in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                     fp_updatenumber         in number, -- depends on updatetype if it is a percentage or amount
                                     fp_maxprice             in number) is
  begin
    gv_message := 'update_customerrentprice, copying customerrentprice id ' ||
                  lvrec_customerrentprice.customerrentprice_id;
    select seq_customerrentprice.nextval
    into   lvrec_customerrentprice.customerrentprice_id
    from   dual;
    lvrec_customerrentprice.startdate     := fp_startdate;
    lvrec_customerrentprice.systemuser_id := gv_defaultuserid;
    lvrec_customerrentprice.timestamp     := sysdate;
    if fp_updatetype = 0 then
      if lvrec_customerrentprice.price + ((fp_updatenumber / 100) * lvrec_customerrentprice.price) <=
         fp_maxprice then
        --percentage
        lvrec_customerrentprice.price := round(lvrec_customerrentprice.price +
                                               ((fp_updatenumber / 100) *
                                               lvrec_customerrentprice.price), gv_roundfactor);
        insert into customerrentprice values lvrec_customerrentprice;
      else
        if fp_maxprice > lvrec_customerrentprice.price then
          lvrec_customerrentprice.price := fp_maxprice;
          insert into customerrentprice values lvrec_customerrentprice;
        end if;
      end if; -- percentage
    else
      --fixed amount
      if lvrec_customerrentprice.price + fp_updatenumber <= fp_maxprice then
        lvrec_customerrentprice.price := round(lvrec_customerrentprice.price + fp_updatenumber,
                                               gv_roundfactor);
        insert into customerrentprice values lvrec_customerrentprice;
      else
        --price > then max, only update if maxprice is more then current price
        if fp_maxprice > lvrec_customerrentprice.price then
          lvrec_customerrentprice.price := fp_maxprice;
          insert into customerrentprice values lvrec_customerrentprice;
        end if;
      end if;
    end if; --fixed amount
  end update_customerrentprice;

  procedure update_customerrentprices(fp_from_customernumber    in customer.customernumber%type,
                                      fp_to___customernumber    in customer.customernumber%type,
                                      fp_from_chaincode         in chain.code%type,
                                      fp_to___chaincode         in chain.code%type,
                                      fp_from_activitycode      in activity.code%type,
                                      fp_to___activitycode      in activity.code%type,
                                      fp_invoicefrequencynumber in number, --0 is no invoice select!
                                      fp_startdate              in date,
                                      fp_checkdate              in date, -- prices after this date are NOT to be updated!
                                      fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                      fp_updatenumber           in number, -- depends on updatetype if it is a percentage or amount
                                      fp_maxprice               in number,
                                      fp_from_productgroup      in productgroup.code%type,
                                      fp_to___productgroup      in productgroup.code%type,
                                      fp_from_product           in product.code%type,
                                      fp_to___product           in product.code%type,
                                      fp_from_size              in sizedefinition.code%type,
                                      fp_to___size              in sizedefinition.code%type,
                                      fp_from_finishingmethod   in finishingmethod.code%type,
                                      fp_to___finishingmethod   in finishingmethod.code%type) is
    lv_whereclause1 varchar2(512) := null;
    lv_whereclause2 varchar2(512) := null;
    type cursor_type is ref cursor;
    x                       cursor_type;
    lvrec_customerrentprice customerrentprice%rowtype;
    lv_counter              number := 0;
  begin
    gv_message      := 'update customer rentprice lists';
    lv_whereclause1 := build_where_clause(fp_checkdate, fp_from_productgroup, fp_to___productgroup,
                                          fp_from_product, fp_to___product, fp_from_size,
                                          fp_to___size, fp_from_finishingmethod,
                                          fp_to___finishingmethod, fp_invoicefrequencynumber);
    lv_whereclause2 := build_where_clause_customer(fp_from_customernumber, fp_to___customernumber,
                                                   fp_from_chaincode, fp_to___chaincode,
                                                   fp_from_activitycode, fp_to___activitycode);
    --process based on all records from table ptvextid that are selected with where clause
    gv_message := 'loop customerrentprice';
    open x for 'select gp.*
         from customerrentprice gp,productlistpercustomer l, product p, sizedefinition s, finishingmethod f, customer c, chain ch
         where gp.productlistpercustomer_id = l.productlistpercustomer_id
           and l.product_id = p.product_id
           and l.sizedefinition_id = s.sizedefinition_id
           and l.finishingmethod_id = f.finishingmethod_id
           and l.customer_id = c.customer_id
           and gp.startdate = ( select max(cx.startdate)
                                from customerrentprice cx
                                where cx.productlistpercustomer_id = gp.productlistpercustomer_id
                                and cx.changesperweek = gp.changesperweek
                                and cx.typeofrent = gp.typeofrent
                                and cx.invoicefrequencynumber = gp.invoicefrequencynumber
                                and cx.startdate <  to_date(''' || to_char(fp_startdate,
                                                                               'dd-mm-yyyy') || ''',''dd-mm-yyyy''))
           and c.chain_id =ch.chain_id' || lv_whereclause1 || lv_whereclause2;
    loop
      begin
        --fetch next row, and stop if no more rows
        fetch x
          into lvrec_customerrentprice;
        exit when x%notfound;
        gv_message := 'update_customerrentprice id / startdate ' ||
                      lvrec_customerrentprice.customerrentprice_id || ' / ' || fp_startdate;
        update_customerrentprice(lvrec_customerrentprice, fp_startdate, fp_updatetype,
                                 fp_updatenumber, fp_maxprice);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    commit;
    write_log(to_char(lv_counter) || ' customer rent prices inserted');
  end update_customerrentprices;

  procedure update_customersalesprice(lvrec_customersalesprice in out customersalesprice%rowtype,
                                      fp_startdate             in date,
                                      fp_updatetype            in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                      fp_updatenumber          in number, -- depends on updatetype if it is a percentage or amount
                                      fp_maxprice              in number) is
  begin
    gv_message := 'update_customersalesprice, copying customersalesprice id ' ||
                  lvrec_customersalesprice.customersalesprice_id;
    select seq_customersalesprice.nextval
    into   lvrec_customersalesprice.customersalesprice_id
    from   dual;
    lvrec_customersalesprice.startdate     := fp_startdate;
    lvrec_customersalesprice.systemuser_id := gv_defaultuserid;
    lvrec_customersalesprice.timestamp     := sysdate;
    if fp_updatetype = 0 then
      if lvrec_customersalesprice.price +
         ((fp_updatenumber / 100) * lvrec_customersalesprice.price) <= fp_maxprice then
        --percentage
        lvrec_customersalesprice.price := round(lvrec_customersalesprice.price +
                                                ((fp_updatenumber / 100) *
                                                lvrec_customersalesprice.price), gv_roundfactor);
        insert into customersalesprice values lvrec_customersalesprice;
      else
        if fp_maxprice > lvrec_customersalesprice.price then
          lvrec_customersalesprice.price := fp_maxprice;
          insert into customersalesprice values lvrec_customersalesprice;
        end if;
      end if; -- percentage
    else
      --fixed amount
      if lvrec_customersalesprice.price + fp_updatenumber <= fp_maxprice then
        lvrec_customersalesprice.price := round(lvrec_customersalesprice.price + fp_updatenumber,
                                                gv_roundfactor);
        insert into customersalesprice values lvrec_customersalesprice;
      else
        --price > then max, only update if maxprice is more then current price
        if fp_maxprice > lvrec_customersalesprice.price then
          lvrec_customersalesprice.price := fp_maxprice;
          insert into customersalesprice values lvrec_customersalesprice;
        end if;
      end if;
    end if; --fixed amount
  end update_customersalesprice;

  procedure update_customersalesprices(fp_from_customernumber in customer.customernumber%type,
                                       fp_to___customernumber in customer.customernumber%type,
                                       fp_from_chaincode      in chain.code%type,
                                       fp_to___chaincode      in chain.code%type,
                                       fp_from_activitycode   in activity.code%type,
                                       fp_to___activitycode   in activity.code%type,
                                       fp_startdate           in date,
                                       fp_checkdate           in date, -- prices after this date are NOT to be updated!
                                       fp_updatetype          in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                       fp_updatenumber        in number, -- depends on updatetype if it is a percentage or amount
                                       fp_maxprice            in number,
                                       fp_from_productgroup   in productgroup.code%type,
                                       fp_to___productgroup   in productgroup.code%type,
                                       fp_from_product        in product.code%type,
                                       fp_to___product        in product.code%type,
                                       fp_from_size           in sizedefinition.code%type,
                                       fp_to___size           in sizedefinition.code%type) is
    lv_whereclause1 varchar2(512) := null;
    lv_whereclause2 varchar2(512) := null;
    type cursor_type is ref cursor;
    x                        cursor_type;
    lvrec_customersalesprice customersalesprice%rowtype;
    lv_counter               number := 0;
  begin
    gv_message      := 'update customer salesprice lists';
    lv_whereclause1 := build_where_clause(fp_checkdate, fp_from_productgroup, fp_to___productgroup,
                                          fp_from_product, fp_to___product, fp_from_size,
                                          fp_to___size, null, null);
    lv_whereclause2 := build_where_clause_customer(fp_from_customernumber, fp_to___customernumber,
                                                   fp_from_chaincode, fp_to___chaincode,
                                                   fp_from_activitycode, fp_to___activitycode);
    --process based on all records from table ptvextid that are selected with where clause
    gv_message := 'loop customersalesprice';
    open x for 'select gp.*
         from customersalesprice gp, product p, sizedefinition s, customer c, chain ch
         where  gp.product_id = p.product_id
           and gp.sizedefinition_id = s.sizedefinition_id
           and gp.customer_id = c.customer_id
           and gp.startdate = ( select max(cx.startdate)
                                from customersalesprice cx
                                where cx.product_id = gp.product_id
                                and cx.sizedefinition_id = gp.sizedefinition_id
                                and cx.customer_id = gp.customer_id
                                and cx.startdate <  to_date(''' || to_char(fp_startdate,
                                                                               'dd-mm-yyyy') || ''',''dd-mm-yyyy''))
               and c.chain_id =ch.chain_id' || lv_whereclause1 || lv_whereclause2;
    loop
      begin
        --fetch next row, and stop if no more rows
        fetch x
          into lvrec_customersalesprice;
        exit when x%notfound;
        gv_message := 'update_customersalesprice id / startdate ' ||
                      lvrec_customersalesprice.customersalesprice_id || ' / ' || fp_startdate;
        update_customersalesprice(lvrec_customersalesprice, fp_startdate, fp_updatetype,
                                  fp_updatenumber, fp_maxprice);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    commit;
    write_log(to_char(lv_counter) || ' customer sales prices inserted');
  end update_customersalesprices;

  procedure update_customerwashprice(lvrec_customerwashprice in out customerwashprice%rowtype,
                                     fp_startdate            in date,
                                     fp_updatetype           in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                     fp_updatenumber         in number, -- depends on updatetype if it is a percentage or amount
                                     fp_maxprice             in number) is
  begin
    gv_message := 'update_customerwashprice, copying customerwashprice id ' ||
                  lvrec_customerwashprice.customerwashprice_id;
    select seq_customerwashprice.nextval
    into   lvrec_customerwashprice.customerwashprice_id
    from   dual;
    lvrec_customerwashprice.startdate     := fp_startdate;
    lvrec_customerwashprice.systemuser_id := gv_defaultuserid;
    lvrec_customerwashprice.timestamp     := sysdate;
    if fp_updatetype = 0 then
      if lvrec_customerwashprice.price + ((fp_updatenumber / 100) * lvrec_customerwashprice.price) <=
         fp_maxprice then
        --percentage
        lvrec_customerwashprice.price := round(lvrec_customerwashprice.price +
                                               ((fp_updatenumber / 100) *
                                               lvrec_customerwashprice.price), gv_roundfactor);
        insert into customerwashprice values lvrec_customerwashprice;
      else
        if fp_maxprice > lvrec_customerwashprice.price then
          lvrec_customerwashprice.price := fp_maxprice;
          insert into customerwashprice values lvrec_customerwashprice;
        end if;
      end if; -- percentage
    else
      --fixed amount
      if lvrec_customerwashprice.price + fp_updatenumber <= fp_maxprice then
        lvrec_customerwashprice.price := round(lvrec_customerwashprice.price + fp_updatenumber,
                                               gv_roundfactor);
        insert into customerwashprice values lvrec_customerwashprice;
      else
        --price > then max, only update if maxprice is more then current price
        if fp_maxprice > lvrec_customerwashprice.price then
          lvrec_customerwashprice.price := fp_maxprice;
          insert into customerwashprice values lvrec_customerwashprice;
        end if;
      end if;
    end if; --fixed amount
  end update_customerwashprice;

  procedure update_customerwashprices(fp_from_customernumber  in customer.customernumber%type,
                                      fp_to___customernumber  in customer.customernumber%type,
                                      fp_from_chaincode       in chain.code%type,
                                      fp_to___chaincode       in chain.code%type,
                                      fp_from_activitycode    in activity.code%type,
                                      fp_to___activitycode    in activity.code%type,
                                      fp_startdate            in date,
                                      fp_checkdate            in date, -- prices after this date are NOT to be updated!
                                      fp_updatetype           in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                                      fp_updatenumber         in number, -- depends on updatetype if it is a percentage or amount
                                      fp_maxprice             in number,
                                      fp_from_productgroup    in productgroup.code%type,
                                      fp_to___productgroup    in productgroup.code%type,
                                      fp_from_product         in product.code%type,
                                      fp_to___product         in product.code%type,
                                      fp_from_size            in sizedefinition.code%type,
                                      fp_to___size            in sizedefinition.code%type,
                                      fp_from_finishingmethod in finishingmethod.code%type,
                                      fp_to___finishingmethod in finishingmethod.code%type) is
    lv_whereclause1 varchar2(512) := null;
    lv_whereclause2 varchar2(512) := null;
    type cursor_type is ref cursor;
    x                       cursor_type;
    lvrec_customerwashprice customerwashprice%rowtype;
    lv_counter              number := 0;
  begin
    gv_message      := 'update customer washprice lists';
    lv_whereclause1 := build_where_clause(fp_checkdate, fp_from_productgroup, fp_to___productgroup,
                                          fp_from_product, fp_to___product, fp_from_size,
                                          fp_to___size, fp_from_finishingmethod,
                                          fp_to___finishingmethod);
    lv_whereclause2 := build_where_clause_customer(fp_from_customernumber, fp_to___customernumber,
                                                   fp_from_chaincode, fp_to___chaincode,
                                                   fp_from_activitycode, fp_to___activitycode);
    --process based on all records from table ptvextid that are selected with where clause
    gv_message := 'loop customerwashprice';
    open x for 'select gp.*
         from customerwashprice gp,productlistpercustomer l, product p, sizedefinition s, finishingmethod f, customer c, chain ch
         where gp.productlistpercustomer_id = l.productlistpercustomer_id
               and l.product_id = p.product_id
               and l.sizedefinition_id = s.sizedefinition_id
               and l.finishingmethod_id = f.finishingmethod_id
               and l.customer_id = c.customer_id
               and gp.startdate = ( select max(cx.startdate)
                                from customerwashprice cx
                                where cx.productlistpercustomer_id = gp.productlistpercustomer_id
                                and cx.pricetype = gp.pricetype
                                and cx.startdate <  to_date(''' || to_char(fp_startdate,
                                                                               'dd-mm-yyyy') || ''',''dd-mm-yyyy''))
               and c.chain_id =ch.chain_id' || lv_whereclause1 || lv_whereclause2;
    loop
      begin
        --fetch next row, and stop if no more rows
        fetch x
          into lvrec_customerwashprice;
        exit when x%notfound;
        gv_message := 'update_customerwashprice id / startdate ' ||
                      lvrec_customerwashprice.customerwashprice_id || ' / ' || fp_startdate;
        update_customerwashprice(lvrec_customerwashprice, fp_startdate, fp_updatetype,
                                 fp_updatenumber, fp_maxprice);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    commit;
    write_log(to_char(lv_counter) || ' customer wash prices inserted');
  end update_customerwashprices;

  procedure check_parameters(fp_pricetype              in out generalpricelist.pricetype%type,
                             fp_pricetypechar          in varchar2,
                             fp_invoicefrequencynumber in number, --0 is no invoice select!
                             fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                             fp_updatenumber           in number,
                             fp_maxprice               in number) is
  begin
    --check input parameters
    gv_message := 'check parameters';
    --check fp_pricetypechar
    case
      when fp_pricetypechar = 'WASH' then
        fp_pricetype := 1;
      when fp_pricetypechar = 'RENT' then
        fp_pricetype := 2;
      when fp_pricetypechar = 'SALES' then
        fp_pricetype := 4;
      else
        gv_message := 'price type must be RENT, WASH or SALES, it is ' ||
                      nvl(fp_pricetypechar, 'NULL');
        raise gv_wrongvalue;
    end case;
    if fp_invoicefrequencynumber not in (null, 10, 40, 110) then
      gv_message := 'invoicefrequencynumber must be NULL,10,40 or 110, it is ' ||
                    nvl(to_char(fp_invoicefrequencynumber), 'NULL');
      raise gv_wrongvalue;
    end if;
    if fp_updatetype not in ('0', '1') then
      gv_message := 'update type must be 0 or 1 it is, ' || fp_updatetype;
      raise gv_wrongvalue;
    end if;
    if fp_updatetype = 0 and not (fp_updatenumber between - 99 and 99) then
      gv_message := 'when update with percentage the percentage must be between -99 and 99, it is ' ||
                    fp_updatenumber;
      raise gv_wrongvalue;
    end if;
    if fp_updatenumber = 0 then
      gv_message := 'if update number = 0, update is not usefull';
      raise gv_wrongvalue;
    end if;
    if fp_maxprice is null or fp_maxprice = 0 then
      gv_message := 'maxprice must be > 0 , and it is ' || nvl(to_char(fp_maxprice), 'NULL');
      raise gv_wrongvalue;
    end if;
  end check_parameters;

  function generalpriceupdate(fp_pricetypechar          in varchar2,
                              fp_from_pricelistcode     in generalpricelist.code%type,
                              fp_to___pricelistcode     in generalpricelist.code%type,
                              fp_invoicefrequencynumber in number, --0 is no invoice select!
                              fp_startdate              in date,
                              fp_checkdate              in date, -- prices after this date are NOT to be updated!
                              fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                              fp_updatenumber           in number, -- depends on updatetype if it is a percentage or amount
                              fp_maxprice               in number,
                              fp_from_productgroup      in productgroup.code%type,
                              fp_to___productgroup      in productgroup.code%type,
                              fp_from_product           in product.code%type,
                              fp_to___product           in product.code%type,
                              fp_from_size              in sizedefinition.code%type,
                              fp_to___size              in sizedefinition.code%type,
                              fp_from_finishingmethod   in finishingmethod.code%type,
                              fp_to___finishingmethod   in finishingmethod.code%type) return number is
    lv_pricetype number;
  begin
    write_log('Start generalpriceupdate');
    --check pricelist codes they cannot be NULL
    if fp_from_pricelistcode is null or fp_to___pricelistcode is null then
      gv_message := 'the from and to pricelist code must both be filled';
      raise gv_wrongvalue;
    end if;
    --check if parameters are ok
    check_parameters(lv_pricetype, fp_pricetypechar, fp_invoicefrequencynumber, fp_updatetype,
                     fp_updatenumber, fp_maxprice);
    --start general price list selection
    gv_message := 'start general price list selection';
    for x in (select gl.generalpricelist_id, gl.code glcode
              from   generalpricelist gl
              where  gl.pricetype = lv_pricetype
              and    gl.code between fp_from_pricelistcode and fp_to___pricelistcode) loop
      begin
        case
          when lv_pricetype = 2 /*RENT*/
           then
            update_generalrentprices(x.glcode, x.generalpricelist_id, fp_invoicefrequencynumber,
                                     fp_startdate, fp_checkdate, fp_updatetype, fp_updatenumber,
                                     fp_maxprice, fp_from_productgroup, fp_to___productgroup,
                                     fp_from_product, fp_to___product, fp_from_size, fp_to___size,
                                     fp_from_finishingmethod, fp_to___finishingmethod);
          when lv_pricetype = 1 /*WASH*/
           then
            update_generalwashprices(x.glcode, x.generalpricelist_id, fp_startdate, fp_checkdate,
                                     fp_updatetype, fp_updatenumber, fp_maxprice,
                                     fp_from_productgroup, fp_to___productgroup, fp_from_product,
                                     fp_to___product, fp_from_size, fp_to___size,
                                     fp_from_finishingmethod, fp_to___finishingmethod);
          when lv_pricetype = 4 /*SALES*/
           then
            update_generalsalesprices(x.glcode, x.generalpricelist_id, fp_startdate, fp_checkdate,
                                      fp_updatetype, fp_updatenumber, fp_maxprice,
                                      fp_from_productgroup, fp_to___productgroup, fp_from_product,
                                      fp_to___product, fp_from_size, fp_to___size);
        end case;
      end;
    end loop;
    --messsage when all is ok
    write_log('Succesfully ran generalpriceupdate');
    --all ok return 0
    return 0;
  exception
    when no_data_found then
      begin
        write_log('Error generalpriceupdate No_Data_Found ' || gv_message, 3);
        rollback;
        return 1;
      end;
    when gv_wrongvalue then
      begin
        write_log('Error generalpriceupdate Wrong value ' || gv_message, 3);
        rollback;
        return 2;
      end;
    when dup_val_on_index then
      begin
        write_log(sqlerrm, 5);
        write_log('Error generalpriceupdate Dup_Val_On_Index ' || gv_message, 3);
        rollback;
        return 3;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error generalpriceupdate Others ' || gv_message, 3);
        rollback;
        return 4;
      end;
  end generalpriceupdate;

  function customerpriceupdate(fp_pricetypechar          in varchar2,
                               fp_from_customernumber    in customer.customernumber%type,
                               fp_to___customernumber    in customer.customernumber%type,
                               fp_from_chaincode         in chain.code%type,
                               fp_to___chaincode         in chain.code%type,
                               fp_from_activitycode      in activity.code%type,
                               fp_to___activitycode      in activity.code%type,
                               fp_invoicefrequencynumber in number, --0 is no invoice select!
                               fp_startdate              in date,
                               fp_checkdate              in date, -- prices after this date are NOT to be updated!
                               fp_updatetype             in varchar2, -- percentage or fixed amount NOT both  0=percentage 1=fixedamount
                               fp_updatenumber           in number, -- depends on updatetype if it is a percentage or amount
                               fp_maxprice               in number,
                               fp_from_productgroup      in productgroup.code%type,
                               fp_to___productgroup      in productgroup.code%type,
                               fp_from_product           in product.code%type,
                               fp_to___product           in product.code%type,
                               fp_from_size              in sizedefinition.code%type,
                               fp_to___size              in sizedefinition.code%type,
                               fp_from_finishingmethod   in finishingmethod.code%type,
                               fp_to___finishingmethod   in finishingmethod.code%type) return number is
    lv_pricetype number;
  begin
    write_log('Start customerpriceupdate');
    --check if parameters are ok
    check_parameters(lv_pricetype, fp_pricetypechar, fp_invoicefrequencynumber, fp_updatetype,
                     fp_updatenumber, fp_maxprice);
    --get the right customer records to be updated!
    case
      when lv_pricetype = 2 /*RENT*/
       then
        update_customerrentprices(fp_from_customernumber, fp_to___customernumber, fp_from_chaincode,
                                  fp_to___chaincode, fp_from_activitycode, fp_to___activitycode,
                                  fp_invoicefrequencynumber, fp_startdate, fp_checkdate,
                                  fp_updatetype, fp_updatenumber, fp_maxprice, fp_from_productgroup,
                                  fp_to___productgroup, fp_from_product, fp_to___product,
                                  fp_from_size, fp_to___size, fp_from_finishingmethod,
                                  fp_to___finishingmethod);
      when lv_pricetype = 1 /*WASH*/
       then
        update_customerwashprices(fp_from_customernumber, fp_to___customernumber, fp_from_chaincode,
                                  fp_to___chaincode, fp_from_activitycode, fp_to___activitycode,
                                  fp_startdate, fp_checkdate, fp_updatetype, fp_updatenumber,
                                  fp_maxprice, fp_from_productgroup, fp_to___productgroup,
                                  fp_from_product, fp_to___product, fp_from_size, fp_to___size,
                                  fp_from_finishingmethod, fp_to___finishingmethod);
      when lv_pricetype = 4 /*SALES*/
       then
        update_customersalesprices(fp_from_customernumber, fp_to___customernumber,
                                   fp_from_chaincode, fp_to___chaincode, fp_from_activitycode,
                                   fp_to___activitycode, fp_startdate, fp_checkdate, fp_updatetype,
                                   fp_updatenumber, fp_maxprice, fp_from_productgroup,
                                   fp_to___productgroup, fp_from_product, fp_to___product,
                                   fp_from_size, fp_to___size);
    end case;
  --messsage when all is ok
    write_log('Succesfully ran customerpriceupdate');
    --all ok return 0
    return 0;
  exception
    when no_data_found then
      begin
        write_log('Error customerpriceupdate No_Data_Found ' || gv_message, 3);
        rollback;
        return 1;
      end;
    when gv_wrongvalue then
      begin
        write_log('Error customerpriceupdate Wrong value ' || gv_message, 3);
        rollback;
        return 2;
      end;
    when dup_val_on_index then
      begin
        write_log(sqlerrm, 5);
        write_log('Error customerpriceupdate Dup_Val_On_Index ' || gv_message, 3);
        rollback;
        return 3;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log('Error customerpriceupdate Others ' || gv_message, 3);
        rollback;
        return 4;
      end;
  end customerpriceupdate;

begin
  -- Initialization
  --get default user
  select s.systemuser_id
  into   gv_defaultuserid
  from   systemuser s
  where  s.username = gv_defaultusrname;
exception
  when no_data_found then
    begin
      select min(s.systemuser_id) into gv_defaultuserid from systemuser s;
      write_log('Error pack_workorder No_Data_Found system user ' || gv_defaultusrname, 3);
    end;
end pack_priceupdate;
/
create or replace package pack_price_contract is
  /***************************************************************************\
    Package Pack_Price_Contract Version 0.5
    Created 12-Jun-2023 ABS-152057 new package Pack_Price_Contract for view
    Updated 28-Sep-2023 ABS-156404 add specialcharge price
            05-May-2024 ABS-164711 add get_specialcharge_record
            18-Sep-2024 ABS-169187 add replacment prices as well
  \***************************************************************************/

  function get_rent_price(fp_contractproductid in contractproduct.contractproduct_id%type,
                          fp_pricedate         in generalrentprice.startdate%type default sysdate)
    return number;

  function get_genspechargeprice_record(fp_contractid      in contract.contract_id%type,
                                        fp_specialchargeid in specialcharge.specialcharge_id%type,
                                        fp_pricedate       in date default sysdate)
    return generalspecialchargeprice%rowtype;

  function get_specialcharge_price(fp_contractid      in contract.contract_id%type,
                                   fp_specialchargeid in specialcharge.specialcharge_id%type,
                                   fp_pricedate       in date default sysdate) return number;

  function get_generalspecialchargeprice_id(fp_contractid      in contract.contract_id%type,
                                            fp_specialchargeid in specialcharge.specialcharge_id%type,
                                            fp_pricedate       in date default sysdate) return number;

  function get_genreplacementprice_record(fp_contractid in contract.contract_id%type,
                                          fp_productid  in product.product_id%type,
                                          fp_sizeid     in sizedefinition.sizedefinition_id%type,
                                          fp_pricedate  in date default sysdate)
    return generalreplacementprice%rowtype;

  function get_replacement_price(fp_contractid in contract.contract_id%type,
                                 fp_productid  in product.product_id%type,
                                 fp_sizeid     in sizedefinition.sizedefinition_id%type,
                                 fp_pricedate  in date default sysdate) return number;

  function get_generalreplacementprice_id(fp_contractid in contract.contract_id%type,
                                          fp_productid  in product.product_id%type,
                                          fp_sizeid     in sizedefinition.sizedefinition_id%type,
                                          fp_pricedate  in date default sysdate) return number;

end pack_price_contract;
/
create or replace package body pack_price_contract is
  /*--------------------------------------------------------------------------------------------------------*/
  --internal functions/procedures
  function getsizestarid return number is
    lv_sizestarid number;
  begin
    select sd.sizedefinition_id into lv_sizestarid from sizedefinition sd where sd.code = '*';
    return lv_sizestarid;
  exception
    when no_data_found then
      return null;
  end getsizestarid;

  -----------------
  function get_rent_price(fp_contractproductid in contractproduct.contractproduct_id%type,
                          fp_pricedate         in generalrentprice.startdate%type default sysdate)
    return number is
    lv_price          number;
    lv_price_found_yn varchar2(1) := 'N';
    lv_rec_cp         contractproduct%rowtype;
    lv_contractcode   contract.code%type;
    lv_typeofrent     generalrentprice.typeofrent%type;
    lv_tom            product.typeofmerchandise%type;

    procedure initialize is
      lv_productgroupid           product.productgroup_id%type;
      lv_underuse_count           number;
      lv_garmentrentspecification number;
      lv_rec_bl                   contractproductbilling%rowtype;
    begin
      --initialize
      --get contractproduct data
      select p.*
      into   lv_rec_cp
      from   contractproduct p
      where  p.contractproduct_id = fp_contractproductid;
      --get contract code
      select ct.code, ccg.garmentrentspecification
      into   lv_contractcode, lv_garmentrentspecification
      from   contract ct
      left   join contractcomponentgrmcharges ccg
      on     ccg.contract_id = ct.contract_id
      where  ct.contract_id = lv_rec_cp.contract_id;
      --get contract product billing
      select cpb.*
      into   lv_rec_bl
      from   contractproductbilling cpb
      where  cpb.contractproduct_id = fp_contractproductid;
      --get type of rent
      --default typeofrent = 1 piece price
      lv_typeofrent := 1;
      --
      if (lv_rec_bl.billingmethod = 3 and lv_rec_bl.priceusage = 3) then
        /*wash only*/
        raise no_data_found; -- Price not relevant, billing method with wash price only
      elsif lv_rec_bl.billingmethod = 4 then
        raise no_data_found; -- Price not relevant, billing method = 4 piece rate only
      elsif (lv_rec_bl.billingmethod = 1 and lv_tom = 2 and lv_garmentrentspecification = 5) then
        -- total wearer price
        raise no_data_found; -- Price not relevant, wearer total price
      elsif (lv_rec_bl.billingmethod = 1 and lv_tom = 2 and lv_garmentrentspecification = 6) then
        -- wearer function price
        raise no_data_found; -- Price not relevant, wearer function price
      else
        begin
          --get type of merchandise product
          select p.typeofmerchandise, p.productgroup_id
          into   lv_tom, lv_productgroupid
          from   product p
          where  p.product_id = lv_rec_cp.product_id;
          --check the other options
          if lv_rec_bl.billingmethod = 1 and lv_tom = 2 -- changes per week
           then
            lv_typeofrent := 2; -- changes per week
          end if;
          if lv_rec_bl.billingmethod = 1 and lv_tom <> 2 and lv_rec_bl.rentpriceperfrequency = 'Y' then
            lv_typeofrent := 4; -- frequency based
          end if; -- frequency based=Y
          if lv_rec_bl.billingmethod = 3 and lv_rec_bl.priceusage = 1 /* split */
           then
            lv_typeofrent := 7; -- split
          end if;
          if lv_rec_bl.billingmethod = 5 then
            lv_typeofrent := 6; -- lease
          end if;
          if lv_rec_bl.billingmethod = 2 and lv_rec_bl.minimumturnaround <> 0 then
            begin
              --check_underuse
              select count(1)
              into   lv_underuse_count
              from   systemsetting st
              join   businessunit bu
              on     bu.plant_id = st.plant_id
              where  st.name = 'UNDERUSEMETHOD'
              and    st.value in ('2', '4');
              if lv_underuse_count > 0 then
                --underuse
                lv_typeofrent := 5;
              end if;
            end;
          end if;
        end;
      end if;
    end initialize;

    procedure get_generalrentprice(fp_generalpricelistid in number, fp_sizeid in number) is
    begin
      --get general rent price
      --GENERALPRICELIST_ID, PRODUCT_ID, SIZEDEFINITION_ID, FINISHINGMETHOD_ID, TYPEOFRENT, STARTDATE,
      --CHANGESPERWEEK, INVOICEFREQUENCYNUMBER, SIZEBILLINGGROUP_ID, MAXINVENTORY
      for y in (select grp.price price
                from   generalrentprice grp
                where  grp.typeofrent = lv_typeofrent
                and    grp.generalpricelist_id = fp_generalpricelistid
                and    grp.product_id = lv_rec_cp.product_id
                and    grp.sizedefinition_id = fp_sizeid
                and    grp.finishingmethod_id = lv_rec_cp.finishingmethod_id
                and    grp.startdate <= nvl(fp_pricedate, sysdate)
                and    nvl(grp.sizebillinggroup_id, 0) = 0 -- not using billing group
                order  by grp.startdate desc, grp.invoicefrequencynumber asc, grp.changesperweek asc) loop
        begin
          lv_price_found_yn := 'Y';
          lv_price          := y.price;
          --price found exit loop
          exit;
        end;
      end loop;
    end get_generalrentprice;
  begin
    --initialize
    initialize;
    --lookup the right prices
    for x in (select case
                       when lv_contractcode = gp.code then
                        0
                       else
                        1
                     end codecheck, csp.generalpricelist_id
              from   contractpricelist csp
              join   generalpricelist gp
              on     gp.generalpricelist_id = csp.generalpricelist_id
              and    gp.pricetype = csp.pricetype
              where  csp.contract_id = lv_rec_cp.contract_id
              and    csp.pricetype = 2 -- rent price
              and    csp.agreed = 'Y'
              and    gp.active = 'Y'
              and    nvl(fp_pricedate, sysdate) between csp.startdate and csp.enddate
              order  by 1 asc, csp.priority asc) loop
      begin
        --look for size equal
        get_generalrentprice(x.generalpricelist_id, lv_rec_cp.sizedefinition_id);
        if (lv_tom = 2 and lv_price_found_yn = 'N' and lv_rec_cp.sizedefinition_id <> getsizestarid) then
          begin
            --look for size star
            get_generalrentprice(x.generalpricelist_id, getsizestarid);
          end;
        end if;
        if lv_price_found_yn = 'Y' then
          begin
            --price found exit loop
            exit;
          end;
        end if;
      end;
    end loop;
    return lv_price;
  exception
    when no_data_found then
      return null;
  end get_rent_price;

  -----------------
  function get_genspechargeprice_record(fp_contractid      in contract.contract_id%type,
                                        fp_specialchargeid in specialcharge.specialcharge_id%type,
                                        fp_pricedate       in date default sysdate)
    return generalspecialchargeprice%rowtype is
    rec_gscp          generalspecialchargeprice%rowtype;
    lv_price_found_yn varchar2(1) := 'N';

    procedure get_specialchargeprice(fp_generalpricelistid in number) is
    begin
      --get_specialchargeprice
      for y in (select gscp.*
                from   generalspecialchargeprice gscp
                join   generalpricelist g
                on     g.generalpricelist_id = gscp.generalpricelist_id
                where  g.generalpricelist_id = fp_generalpricelistid
                and    gscp.specialcharge_id = fp_specialchargeid
                and    gscp.startdate <= nvl(fp_pricedate, sysdate)
                order  by gscp.startdate desc) loop
        begin
          lv_price_found_yn := 'Y';
          rec_gscp          := y;
          --price found exit loop
          exit;
        end;
      end loop; --x
    end get_specialchargeprice;
  begin
    --get_genspechargeprice_record
    for x in (select case
                       when ct.code = gp.code then
                        0
                       else
                        1
                     end codecheck, csp.generalpricelist_id
              from   contract ct
              join   contractpricelist csp
              on     csp.contract_id = ct.contract_id
              join   generalpricelist gp
              on     gp.generalpricelist_id = csp.generalpricelist_id
              and    gp.pricetype = csp.pricetype
              where  csp.contract_id = fp_contractid
              and    csp.pricetype = 10 -- special charge price
              and    csp.agreed = 'Y'
              and    gp.active = 'Y'
              and    nvl(fp_pricedate, sysdate) between csp.startdate and csp.enddate
              order  by 1 asc, csp.priority asc) loop
      begin
        --look for speical charge price
        get_specialchargeprice(x.generalpricelist_id);
        if lv_price_found_yn = 'Y' then
          begin
            --price found exit loop
            exit;
          end;
        end if;
      end;
    end loop;
    return rec_gscp;
  exception
    when no_data_found then
      return null;
  end get_genspechargeprice_record;

  function get_specialcharge_price(fp_contractid      in contract.contract_id%type,
                                   fp_specialchargeid in specialcharge.specialcharge_id%type,
                                   fp_pricedate       in date default sysdate) return number is
    rec_gscp generalspecialchargeprice%rowtype;
  begin
    --get_specialcharge_price
    rec_gscp := get_genspechargeprice_record(fp_contractid, fp_specialchargeid, fp_pricedate);
    return rec_gscp.price;
  end get_specialcharge_price;

  function get_generalspecialchargeprice_id(fp_contractid      in contract.contract_id%type,
                                            fp_specialchargeid in specialcharge.specialcharge_id%type,
                                            fp_pricedate       in date default sysdate) return number is
    rec_gscp generalspecialchargeprice%rowtype;
  begin
    --get_genspechargeprice_record
    rec_gscp := get_genspechargeprice_record(fp_contractid, fp_specialchargeid, fp_pricedate);
    return rec_gscp.generalspecialchargeprice_id;
  end get_generalspecialchargeprice_id;

  -----------------
  --GENERALPRICELIST_ID, PRODUCT_ID, SIZEDEFINITION_ID, STARTDATE, SIZEBILLINGGROUP_ID
  function get_genreplacementprice_record(fp_contractid in contract.contract_id%type,
                                          fp_productid  in product.product_id%type,
                                          fp_sizeid     in sizedefinition.sizedefinition_id%type,
                                          fp_pricedate  in date default sysdate)
    return generalreplacementprice%rowtype is
    rec_gscp          generalreplacementprice%rowtype;
    lv_price_found_yn varchar2(1) := 'N';

    procedure get_replacementprice(fp_generalpricelistid in number) is
    begin
      --get_replacementprice
      for y in (select gscp.*
                from   generalreplacementprice gscp
                join   generalpricelist g
                on     g.generalpricelist_id = gscp.generalpricelist_id
                where  g.generalpricelist_id = fp_generalpricelistid
                and    gscp.product_id = fp_productid
                and    gscp.sizedefinition_id = fp_sizeid
                and    gscp.startdate <= nvl(fp_pricedate, sysdate)
                and    gscp.sizebillinggroup_id is null
                order  by gscp.startdate desc) loop
        begin
          lv_price_found_yn := 'Y';
          rec_gscp          := y;
          --price found exit loop
          exit;
        end;
      end loop; --x
    end get_replacementprice;
  begin
    --get_genreplacementprice_record
    for x in (select case
                       when ct.code = gp.code then
                        0
                       else
                        1
                     end codecheck, csp.generalpricelist_id
              from   contract ct
              join   contractpricelist csp
              on     csp.contract_id = ct.contract_id
              join   generalpricelist gp
              on     gp.generalpricelist_id = csp.generalpricelist_id
              and    gp.pricetype = csp.pricetype
              where  csp.contract_id = fp_contractid
              and    csp.pricetype = 3 -- replacement price
              and    csp.agreed = 'Y'
              and    gp.active = 'Y'
              and    nvl(fp_pricedate, sysdate) between csp.startdate and csp.enddate
              order  by 1 asc, csp.priority asc) loop
      begin
        --look for speical charge price
        get_replacementprice(x.generalpricelist_id);
        if lv_price_found_yn = 'Y' then
          begin
            --price found exit loop
            exit;
          end;
        end if;
      end;
    end loop;
    return rec_gscp;
  exception
    when no_data_found then
      return null;
  end get_genreplacementprice_record;

  function get_replacement_price(fp_contractid in contract.contract_id%type,
                                 fp_productid  in product.product_id%type,
                                 fp_sizeid     in sizedefinition.sizedefinition_id%type,
                                 fp_pricedate  in date default sysdate) return number is
    rec_gscp generalreplacementprice%rowtype;
  begin
    --get_replacement_price
    rec_gscp := get_genreplacementprice_record(fp_contractid, fp_productid, fp_sizeid, fp_pricedate);
    return rec_gscp.price;
  end get_replacement_price;

  function get_generalreplacementprice_id(fp_contractid in contract.contract_id%type,
                                          fp_productid  in product.product_id%type,
                                          fp_sizeid     in sizedefinition.sizedefinition_id%type,
                                          fp_pricedate  in date default sysdate) return number is
    rec_gscp generalreplacementprice%rowtype;
  begin
    --get_genreplacementprice_record
    rec_gscp := get_genreplacementprice_record(fp_contractid, fp_productid, fp_sizeid, fp_pricedate);
    return rec_gscp.generalreplacementprice_id;
  end get_generalreplacementprice_id;

end pack_price_contract;
/
create or replace package pack_price_customer is
  /***************************************************************************\
  Package Pack_Price_Customer Version 1.0
  Created 08-Feb-2021  ABS-114098 new package Pack_Price_Customer
  Updated 09-Feb-2021  ABS-114098
          16-Feb-2021  ABS-114098 No soil YN for f_price_weightprice parameter
          19-Oct-2021  ABS-125823 old price for clientinvoicecat special charge
          19-Nov-2021  ABS-127746 return price decimals depending on currency of customer
  ----------------------------------------------------------------------------
  General rule on that was is being returned in the varchar2 by the function
  Position, Return Value fixed lengths
  ----------------------------------------------------------------------------
  1  price (length 12)
  13 price found Y/N (length 1)
  14 startdatum (length 8)
  22 pricelist type C=Customer specific, G=General price list, or space
  23 pricelist code when used (length 15) (Only used when applicable)
  38 labellayout.code for f_price_labeltype
     null when not applicable
     Soil or Clean for f_price_weightprice
  \***************************************************************************/
  --internal function
  function get_sizestarid return number;
  function f_get_decimals_pattern(fp_customerid in customer.customer_id%type) return varchar2;

  --external functions to be used
  function f_price_repair_details(fp_customerid   in customer.customer_id%type,
                                  fp_repairtypeid in repairtype.repairtype_id%type,
                                  fp_pricedate    in pricelistpercustomer.dateactive%type default trunc(sysdate),
                                  fp_pricetype    in number default 1) --1 piece price, 2 minute price
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific, G=General price list
    23 pricelist code when General price list (length 15)
    */
   return varchar2;

  function f_price_restockingfee(fp_customerid in customer.customer_id%type,
                                 fp_pricedate  in customerrestockingfeeprice.startdate%type default trunc(sysdate))
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  function f_price_enduser(fp_customerid        in customer.customer_id%type,
                           fp_productid         in product.product_id%type,
                           fp_sizeid            in sizedefinition.sizedefinition_id%type,
                           fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                           fp_pricedate         in generalwashprice.startdate%type default trunc(sysdate))
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type G=General price list
    23 pricelist code when used (length 15)
    */
   return varchar2;

  function f_price_stockcharge(fp_customerid in customer.customer_id%type,
                               fp_pricedate  in customerstockcharge.startdate%type default trunc(sysdate))
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  /*
  fp_labeltype options
  1 = Code label LOG
  2 = Name label
  3 = Domestic / Residential label
  4 = Code label COG
  5 = Patch price (residential)
  6 = Name label COG
  */
  function f_price_labeltype(fp_customerid    in customer.customer_id%type,
                             fp_labeltype     in customerlabellayoutprice.labeltype%type default 1,
                             fp_pricedate     in customerlabellayoutprice.startdate%type default trunc(sysdate),
                             fp_labellayoutid in customerlabellayoutprice.labellayout_id%type default null)
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    23 empty
    38 labelcode
    */
   return varchar2;

  function f_price_prepcharge(fp_customerid   in customer.customer_id%type,
                              fp_pricedate    in customerprepcharge.startdate%type default trunc(sysdate),
                              fp_reasoncodeid in customerprepcharge.reasoncode_id%type default null)
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  function f_price_servicecost(fp_customerid in customer.customer_id%type,
                               fp_pricedate  in customerservicecostsprice.startdate%type default trunc(sysdate),
                               fp_pricetype  in number default 0) --0 LOG (laundry), 1 COG (customer)
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  function f_price_plpcservicecost(fp_plpcid    in plpcservicecostsprice.productlistpercustomer_id%type,
                                   fp_pricedate in plpcservicecostsprice.startdate%type default trunc(sysdate),
                                   fp_pricetype in number default 0) --0 LOG (laundry), 1 COG (customer)
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  function f_price_clientinvcatcharge(fp_clientinvoicecategoryid in clientinvoicecategorycharge.clientinvoicecategory_id%type,
                                      fp_specialchargeid         in clientinvoicecategorycharge.specialcharge_id%type,
                                      fp_pricedate               in customerlabellayoutprice.startdate%type default trunc(sysdate))
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  function f_price_budgetdefinition(fp_customerid in customerbudgetdefinition.customer_id%type,
                                    fp_budgetcode in customerbudgetdefinition.code%type,
                                    fp_pricedate  in customerprepcharge.startdate%type default trunc(sysdate))
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
   return varchar2;

  function f_price_weightprice(fp_customerid         in weighingcategpercustomer.customer_id%type,
                               fp_weighingcategoryid in weighingcategpercustomer.weighingcategory_id%type,
                               fp_pricedate          in customerweightprice.startdate%type default trunc(sysdate))
  /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    23 null
    38 SOIL or CLEAN
    */
   return varchar2;

  function f_price_specialcharge(fp_customerid              in customerspecialchargeprice.customer_id%type,
                                 fp_specialchargeid         in customerspecialchargeprice.specialcharge_id%type,
                                 fp_pricedate               in customerspecialchargeprice.startdate%type default trunc(sysdate),
                                 fp_clientinvoicecategoryid in clientinvoicecategorycharge.clientinvoicecategory_id%type default null)
  /*
    1  price or percentage with % in it (length 12)
    13 price or percentage found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific, G=General price list
    23 pricelist code when General price list (length 15)
    38 PRICE or PERCENTAGE
    */
   return varchar2;

end pack_price_customer;
/
create or replace package body pack_price_customer is

  function get_sizestarid return number is
    lv_sizestarid sizedefinition.sizedefinition_id%type;
  begin
    --get size id for size star *
    select s.sizedefinition_id into lv_sizestarid from sizedefinition s where s.code = '*';
    return lv_sizestarid;
  exception
    when no_data_found then
      begin
        return null;
      end;
  end get_sizestarid;

  function f_get_decimals_pattern(fp_customerid in customer.customer_id%type) return varchar2 is
    gv_decimals  number;
    gv_retstring varchar2(12);
  begin
    if fp_customerid is null then
      return '99990D99999';
    end if;
    select max(cur.decimals)
    into   gv_decimals
    from   customer c
    join   currency cur
    on     cur.currency_id = c.currency_id
    where  c.customer_id = fp_customerid;
    case gv_decimals
      when 0 then
        gv_retstring := '99999999990';
      when 1 then
        gv_retstring := '999999990D9';
      when 2 then
        gv_retstring := '99999990D99';
      when 3 then
        gv_retstring := '9999990D999';
      when 4 then
        gv_retstring := '99990D99999';
      else
        gv_retstring := '99990D99999';
    end case;
    return gv_retstring;
  end f_get_decimals_pattern;

  function f_price_repair_details(fp_customerid   in customer.customer_id%type,
                                  fp_repairtypeid in repairtype.repairtype_id%type,
                                  fp_pricedate    in pricelistpercustomer.dateactive%type default trunc(sysdate),
                                  fp_pricetype    in number default 1) -- 1 piece price, 2 minute price
   return varchar2 is
    lv_repair_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific, G=General price list
    23 pricelist code when General price list (length 15)
    */
  begin
    --f_price_repair_details
    if fp_customerid is null or fp_repairtypeid is null then
      begin
        return lv_repair_details;
      end;
    end if;
    for x in (select plc.generalpricelist_id, plc.priceindexcode
              from   pricelistpercustomer plc
              where  plc.customer_id = fp_customerid
              and    plc.pricetype = 6
              and    nvl(fp_pricedate, sysdate) between plc.dateactive and plc.dateinactive
              order  by plc.priority asc) loop
      begin
        if x.generalpricelist_id is null then
          begin
            select to_char(case nvl(fp_pricetype, 1)
                              when 1 then
                               crp.price
                              when 2 then
                               crp.priceperminute
                            end, f_get_decimals_pattern(crp.customer_id)) || 'Y' ||
                    to_char(crp.startdate, 'YYYYMMDD') || 'C'
            into   lv_repair_details
            from   customerrepairprice crp
            where  crp.customer_id = fp_customerid
            and    crp.repairtype_id = fp_repairtypeid
            and    crp.startdate =
                   (select max(crp2.startdate)
                     from   customerrepairprice crp2
                     where  crp2.customer_id = crp.customer_id
                     and    crp2.repairtype_id = crp.repairtype_id
                     and    crp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
          end;
        else
          begin
            select to_char(case nvl(fp_pricetype, 1)
                              when 1 then
                               grp.price
                              when 2 then
                               grp.priceperminute
                            end, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                    to_char(grp.startdate, 'YYYYMMDD') || 'G' || rpad(gp.code, 15, ' ')
            into   lv_repair_details
            from   generalpricelist gp
            join   generalrepairprice grp
            on     grp.generalpricelist_id = gp.generalpricelist_id
            where  gp.active = 'Y'
            and    gp.pricetype = 6
            and    gp.generalpricelist_id = x.generalpricelist_id
            and    grp.repairtype_id = fp_repairtypeid
            and    grp.startdate =
                   (select max(grp2.startdate)
                     from   generalrepairprice grp2
                     where  grp2.generalpricelist_id = grp.generalpricelist_id
                     and    grp2.repairtype_id = grp.repairtype_id
                     and    grp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
          end;
        end if;
        return lv_repair_details;
      exception
        when no_data_found then
          null; --get next one
      end;
    end loop; --x
    return lv_repair_details;
  end f_price_repair_details;

  function f_price_restockingfee(fp_customerid in customer.customer_id%type,
                                 fp_pricedate  in customerrestockingfeeprice.startdate%type default trunc(sysdate))
    return varchar2 is
    lv_restock_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    --f_price_restockingfee
    if fp_customerid is null then
      begin
        return lv_restock_details;
      end;
    end if;
    select to_char(crf.price, f_get_decimals_pattern(crf.customer_id)) || 'Y' ||
            to_char(crf.startdate, 'YYYYMMDD') || 'C'
    into   lv_restock_details
    from   customerrestockingfeeprice crf
    where  crf.customer_id = fp_customerid
    and    crf.startdate =
           (select max(crf2.startdate)
             from   customerrestockingfeeprice crf2
             where  crf2.customer_id = crf.customer_id
             and    crf2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_restock_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_restockingfee;

  function f_price_enduser(fp_customerid        in customer.customer_id%type,
                           fp_productid         in product.product_id%type,
                           fp_sizeid            in sizedefinition.sizedefinition_id%type,
                           fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                           fp_pricedate         in generalwashprice.startdate%type default trunc(sysdate))
    return varchar2 is
    lv_enduser_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type G=General price list
    23 pricelist code when used (length 15)
    */
  begin
    --f_price_enduser
    select to_char(gw.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
            to_char(gw.startdate, 'YYYYMMDD') || 'G' || rpad(g.code, 15, ' ')
    into   lv_enduser_details
    from   customerresidentialsettings u
    join   generalpricelist g
    on     g.generalpricelist_id = u.enduserpricelist_id
    join   generalwashprice gw
    on     gw.generalpricelist_id = u.enduserpricelist_id
    where  gw.pricetype = 1 --All items
    and    g.pricetype = 1 --Wash
    and    u.customer_id = fp_customerid
    and    gw.product_id = fp_productid
    and    gw.sizedefinition_id = fp_sizeid
    and    gw.finishingmethod_id = fp_finishingmethodid
    and    gw.startdate =
           (select max(gw2.startdate)
             from   generalwashprice gw2
             where  gw2.generalpricelist_id = gw.generalpricelist_id
             and    gw2.product_id = gw.product_id
             and    gw2.sizedefinition_id = gw.sizedefinition_id
             and    gw2.finishingmethod_id = gw.finishingmethod_id
             and    gw2.pricetype = gw.pricetype
             and    gw2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_enduser_details;
  exception
    when no_data_found then
      begin
        --do same select but with size star *
        select to_char(gw.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                to_char(gw.startdate, 'YYYYMMDD') || 'G' || rpad(g.code, 15, ' ')
        into   lv_enduser_details
        from   customerresidentialsettings u
        join   generalpricelist g
        on     g.generalpricelist_id = u.enduserpricelist_id
        join   generalwashprice gw
        on     gw.generalpricelist_id = u.enduserpricelist_id
        where  gw.pricetype = 1 --All items
        and    g.pricetype = 1 --Wash
        and    u.customer_id = fp_customerid
        and    gw.product_id = fp_productid
        and    gw.sizedefinition_id = get_sizestarid
        and    gw.finishingmethod_id = fp_finishingmethodid
        and    gw.startdate =
               (select max(gw2.startdate)
                 from   generalwashprice gw2
                 where  gw2.generalpricelist_id = gw.generalpricelist_id
                 and    gw2.product_id = gw.product_id
                 and    gw2.sizedefinition_id = gw.sizedefinition_id
                 and    gw2.finishingmethod_id = gw.finishingmethod_id
                 and    gw2.pricetype = gw.pricetype
                 and    gw2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
        return lv_enduser_details;
      exception
        when no_data_found then
          return '            N'; --price found N
      end;
  end f_price_enduser;

  function f_price_stockcharge(fp_customerid in customer.customer_id%type,
                               fp_pricedate  in customerstockcharge.startdate%type default trunc(sysdate))
    return varchar2 is
    lv_stockcharge_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    --f_price_stockcharge
    select to_char(csc.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
            to_char(csc.startdate, 'YYYYMMDD') || 'C'
    into   lv_stockcharge_details
    from   customerstockcharge csc
    where  csc.customer_id = fp_customerid
    and    csc.startdate =
           (select max(csc2.startdate)
             from   customerstockcharge csc2
             where  csc2.customer_id = csc.customer_id
             and    csc2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_stockcharge_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_stockcharge;

  function f_price_labeltype(fp_customerid    in customer.customer_id%type,
                             fp_labeltype     in customerlabellayoutprice.labeltype%type default 1,
                             fp_pricedate     in customerlabellayoutprice.startdate%type default trunc(sysdate),
                             fp_labellayoutid in customerlabellayoutprice.labellayout_id%type default null)
    return varchar2 is
    lv_labellayout_details varchar2(1000) := '            N'; --price found N
    lv_labellayoutcode     labellayout.code%type;
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    23 empty
    38 labelcode
    */
  begin
    --f_price_labeltype
    /*
    1 = Code label LOG
    2 = Name label
    3 = Domestic / Residential label
    4 = Code label COG
    5 = Patch price (residential)
    6 = Name label COG
    */
    if fp_labellayoutid is not null then
      begin
        select ll.code
        into   lv_labellayoutcode
        from   labellayout ll
        where  ll.labellayout_id = fp_labellayoutid;
      exception
        when no_data_found then
          begin
            lv_labellayoutcode := null;
          end;
      end;
    else
      begin
        lv_labellayoutcode := null;
      end;
    end if;
    select to_char(clp.price, f_get_decimals_pattern(clp.customer_id)) || 'Y' ||
            to_char(clp.startdate, 'YYYYMMDD') || 'C' || '               ' ||
            nvl(lv_labellayoutcode,
                case clp.labeltype
                   when 1 then
                    (select max(ll.code)
                     from   customer c
                     join   labellayout ll
                     on     ll.labellayout_id = c.codelabellayout_id
                     where  c.customer_id = clp.customer_id)
                   when 2 then
                    (select max(ll.code)
                     from   customer c
                     join   labellayout ll
                     on     ll.labellayout_id = c.namelabellayout_id
                     where  c.customer_id = clp.customer_id)
                   when 3 then
                    (select max(ll.code)
                     from   customerresidentialsettings crs
                     join   labellayout ll
                     on     ll.labellayout_id = crs.labellayout_id
                     where  crs.customer_id = clp.customer_id)
                   when 4 then
                    (select max(ll.code)
                     from   customer c
                     join   labellayout ll
                     on     ll.labellayout_id = c.codelabellayout_id
                     where  c.customer_id = clp.customer_id)
                   when 5 then
                    (select max(ll.code)
                     from   customerresidentialsettings crs
                     join   labellayout ll
                     on     ll.labellayout_id = crs.labellayout_id
                     where  crs.customer_id = clp.customer_id)
                   when 6 then
                    (select max(ll.code)
                     from   customer c
                     join   labellayout ll
                     on     ll.labellayout_id = c.namelabellayout_id
                     where  c.customer_id = clp.customer_id)
                   else
                    null
                 end)
    into   lv_labellayout_details
    from   customerlabellayoutprice clp
    where  clp.labeltype = nvl(fp_labeltype, 1)
    and    nvl(clp.labellayout_id, 0) = nvl(fp_labellayoutid, 0)
    and    clp.customer_id = fp_customerid
    and    clp.startdate =
           (select max(clp2.startdate)
             from   customerlabellayoutprice clp2
             where  clp2.labeltype = clp.labeltype
             and    nvl(clp2.labellayout_id, 0) = nvl(clp.labellayout_id, 0)
             and    clp2.customer_id = clp.customer_id
             and    clp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_labellayout_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_labeltype;

  function f_price_prepcharge(fp_customerid   in customer.customer_id%type,
                              fp_pricedate    in customerprepcharge.startdate%type default trunc(sysdate),
                              fp_reasoncodeid in customerprepcharge.reasoncode_id%type default null)
    return varchar2 is
    lv_prepcharge_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    --f_price_prepcharge
    if fp_reasoncodeid is null then
      begin
        select to_char(cpc.price, f_get_decimals_pattern(cpc.customer_id)) || 'Y' ||
                to_char(cpc.startdate, 'YYYYMMDD') || 'C'
        into   lv_prepcharge_details
        from   customerprepcharge cpc
        where  cpc.customer_id = fp_customerid
        and    cpc.reasoncode_id is null
        and    cpc.startdate =
               (select max(cpc2.startdate)
                 from   customerprepcharge cpc2
                 where  cpc2.customer_id = cpc.customer_id
                 and    cpc2.reasoncode_id is null
                 and    cpc2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
      end;
    else
      begin
        select to_char(cpc.price, f_get_decimals_pattern(cpc.customer_id)) || 'Y' ||
                to_char(cpc.startdate, 'YYYYMMDD') || 'C'
        into   lv_prepcharge_details
        from   customerprepcharge cpc
        where  cpc.customer_id = fp_customerid
        and    cpc.reasoncode_id = fp_reasoncodeid
        and    cpc.startdate =
               (select max(cpc2.startdate)
                 from   customerprepcharge cpc2
                 where  cpc2.customer_id = cpc.customer_id
                 and    cpc2.reasoncode_id = cpc.reasoncode_id
                 and    cpc2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
      end;
    end if;
    return lv_prepcharge_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_prepcharge;

  function f_price_servicecost(fp_customerid in customer.customer_id%type,
                               fp_pricedate  in customerservicecostsprice.startdate%type default trunc(sysdate),
                               fp_pricetype  in number default 0) --0 LOG (laundry), 1 COG (customer)
   return varchar2 is
    lv_servicecost_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    --f_price_servicecost
    select to_char(csp.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
            to_char(csp.startdate, 'YYYYMMDD') || 'C'
    into   lv_servicecost_details
    from   customerservicecostsprice csp
    where  csp.customer_id = fp_customerid
    and    csp.pricetype = nvl(fp_pricetype, 0)
    and    csp.startdate =
           (select max(csp2.startdate)
             from   customerservicecostsprice csp2
             where  csp2.customer_id = csp.customer_id
             and    csp2.pricetype = csp.pricetype
             and    csp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_servicecost_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_servicecost;

  function f_price_plpcservicecost(fp_plpcid    in plpcservicecostsprice.productlistpercustomer_id%type,
                                   fp_pricedate in plpcservicecostsprice.startdate%type default trunc(sysdate),
                                   fp_pricetype in number default 0) --0 LOG (laundry), 1 COG (customer)
   return varchar2 is
    lv_servicecost_details varchar2(1000) := '            N'; --price found N
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    select to_char(psc.price, f_get_decimals_pattern(plpc.customer_id)) || 'Y' ||
            to_char(psc.startdate, 'YYYYMMDD') || 'C'
    into   lv_servicecost_details
    from   plpcservicecostsprice psc
    join   productlistpercustomer plpc
    on     psc.productlistpercustomer_id = plpc.productlistpercustomer_id
    where  psc.productlistpercustomer_id = fp_plpcid
    and    psc.pricetype = nvl(fp_pricetype, 0)
    and    psc.startdate =
           (select max(psc2.startdate)
             from   plpcservicecostsprice psc2
             where  psc2.productlistpercustomer_id = psc.productlistpercustomer_id
             and    psc2.pricetype = psc.pricetype
             and    psc2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_servicecost_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_plpcservicecost;

  function f_price_clientinvcatcharge(fp_clientinvoicecategoryid in clientinvoicecategorycharge.clientinvoicecategory_id%type,
                                      fp_specialchargeid         in clientinvoicecategorycharge.specialcharge_id%type,
                                      fp_pricedate               in customerlabellayoutprice.startdate%type default trunc(sysdate))
    return varchar2 is
    lv_newamount  number;
    lv_oldamount  number;
    lv_startdate  date;
    lv_customerid number;
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    --f_price_clientinvcatcharge
    select cic.startdate, cic.newamount, cic.oldamount, cli.customer_id
    into   lv_startdate, lv_newamount, lv_oldamount, lv_customerid
    from   clientinvoicecategorycharge cic
    join   clientinvoicecategory cli
    on     cli.clientinvoicecategory_id = cic.clientinvoicecategory_id
    where  cic.clientinvoicecategory_id = fp_clientinvoicecategoryid
    and    cic.specialcharge_id = fp_specialchargeid;
    if fp_pricedate >= lv_startdate then
      return to_char(lv_newamount, f_get_decimals_pattern(lv_customerid)) || 'Y' || to_char(lv_startdate,
                                                                                            'YYYYMMDD') || 'C';
    else
      --startdate unknown we take 2000 jan 01
      return to_char(lv_oldamount, f_get_decimals_pattern(lv_customerid)) || 'Y' || '20000101' || 'C';
    end if;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_clientinvcatcharge;

  function f_price_budgetdefinition(fp_customerid in customerbudgetdefinition.customer_id%type,
                                    fp_budgetcode in customerbudgetdefinition.code%type,
                                    fp_pricedate  in customerprepcharge.startdate%type default trunc(sysdate))
    return varchar2 is
    lv_budgetdefinition_details   varchar2(1000) := '            N'; --price found N
    lv_customerbudgetdefinitionid customerbudgetdefinition.customerbudgetdefinition_id%type;
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    */
  begin
    --f_price_budgetdefinition
    --get customerbudgetdefinition
    select cb.customerbudgetdefinition_id
    into   lv_customerbudgetdefinitionid
    from   customerbudgetdefinition cb
    where  cb.customer_id = fp_customerid
    and    cb.code = fp_budgetcode;
    --get price
    select to_char(cbp.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
            to_char(cbp.startdate, 'YYYYMMDD') || 'C'
    into   lv_budgetdefinition_details
    from   customerbudgetprice cbp
    where  cbp.customerbudgetdefinition_id = lv_customerbudgetdefinitionid
    and    cbp.startdate =
           (select max(cbp2.startdate)
             from   customerbudgetprice cbp2
             where  cbp2.customerbudgetdefinition_id = cbp.customerbudgetdefinition_id
             and    cbp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
    return lv_budgetdefinition_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_budgetdefinition;

  function f_price_weightprice(fp_customerid         in weighingcategpercustomer.customer_id%type,
                               fp_weighingcategoryid in weighingcategpercustomer.weighingcategory_id%type,
                               fp_pricedate          in customerweightprice.startdate%type default trunc(sysdate))
    return varchar2 is
    lv_weightprice_details        varchar2(1000) := '            N'; --price found N
    lv_weighingcategpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    /*
    1  price (length 12)
    13 price found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific
    23 null
    38 SOIL or CLEAN
    */
  begin
    --f_price_weightprice
    if fp_customerid is null or fp_weighingcategoryid is null then
      begin
        return lv_weightprice_details;
      end;
    end if;
    --loop pricelists customer
    for y in (select plc.generalpricelist_id, plc.priceindexcode
              from   pricelistpercustomer plc
              where  plc.customer_id = fp_customerid
              and    plc.pricetype = 5
              and    nvl(fp_pricedate, sysdate) between plc.dateactive and plc.dateinactive
              order  by plc.priority asc) loop
      begin
        if y.generalpricelist_id is null then
          begin
            --get lv_weighingcategpercustomerid
            select max(wcc.weighingcategpercustomer_id)
            into   lv_weighingcategpercustomerid
            from   weighingcategpercustomer wcc
            where  wcc.customer_id = fp_customerid
            and    wcc.weighingcategory_id = fp_weighingcategoryid
            and    trunc(nvl(fp_pricedate, sysdate)) between wcc.dateactive and wcc.dateinactive;
            --get customerweightprice
            for x in (select to_char(cwp.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                              to_char(cwp.startdate, 'YYYYMMDD') || 'C' details, cwp.soil
                      from   customerweightprice cwp
                      where  cwp.weighingcategpercustomer_id = lv_weighingcategpercustomerid
                      and    cwp.startdate =
                             (select max(cwp2.startdate)
                               from   customerweightprice cwp2
                               where  cwp2.weighingcategpercustomer_id =
                                      cwp.weighingcategpercustomer_id
                               and    cwp2.soil = cwp.soil
                               and    cwp2.startdate <= trunc(nvl(fp_pricedate, sysdate)))
                      order  by cwp.startdate desc) loop
              begin
                if x.soil = 'Y' then
                  lv_weightprice_details := x.details || '               ' || 'SOIL';
                else
                  lv_weightprice_details := x.details || '               ' || 'CLEAN';
                end if;
                exit;
              end;
            end loop;
          end;
        else
          begin
            --get generalweightprice
            for x in (select to_char(cwp.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                              to_char(cwp.startdate, 'YYYYMMDD') || 'G' details, cwp.soil,
                             rpad(g.code, 15, ' ') generalpricelistcode
                      from   generalweightprice cwp
                      join   generalpricelist g
                      on     g.generalpricelist_id = cwp.generalpricelist_id
                      where  cwp.generalpricelist_id = y.generalpricelist_id
                      and    cwp.weighingcategory_id = fp_weighingcategoryid
                      and    cwp.startdate =
                             (select max(cwp2.startdate)
                               from   generalweightprice cwp2
                               where  cwp2.generalpricelist_id = cwp.generalpricelist_id
                               and    cwp2.weighingcategory_id = cwp.weighingcategory_id
                               and    cwp2.soil = cwp.soil
                               and    cwp2.startdate <= trunc(nvl(fp_pricedate, sysdate)))
                      order  by cwp.startdate desc) loop
              begin
                if x.soil = 'Y' then
                  lv_weightprice_details := x.details || x.generalpricelistcode || 'SOIL';
                else
                  lv_weightprice_details := x.details || x.generalpricelistcode || 'CLEAN';
                end if;
                exit;
              end;
            end loop;
          end;
        end if;
      end;
    end loop; --y
    return lv_weightprice_details;
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_weightprice;

  function f_price_specialcharge(fp_customerid              in customerspecialchargeprice.customer_id%type,
                                 fp_specialchargeid         in customerspecialchargeprice.specialcharge_id%type,
                                 fp_pricedate               in customerspecialchargeprice.startdate%type default trunc(sysdate),
                                 fp_clientinvoicecategoryid in clientinvoicecategorycharge.clientinvoicecategory_id%type default null)
    return varchar2 is
    lv_specialcharge_details varchar2(1000) := '            N'; --price found N
    lv_fixedamount           specialcharge.fixedamount%type;
    /*
    1  price or percentage with % in it (length 12)
    13 price or percentage found Y/N (length 1)
    14 startdatum (length 8)
    22 pricelist type C=Customer specific, G=General price list
    23 pricelist code when General price list (length 15)
    38 PRICE or PERCENTAGE
    */
  begin
    --f_price_specialcharge
    if (fp_customerid is null and fp_clientinvoicecategoryid is not null) then
      begin
        return lv_specialcharge_details;
      end;
    end if;
    select sp.fixedamount
    into   lv_fixedamount
    from   specialcharge sp
    where  sp.specialcharge_id = fp_specialchargeid;
    if fp_clientinvoicecategoryid is not null then
      begin
        select to_char((case
                         when cic.startdate <= fp_pricedate then
                          cic.newamount
                         else
                          cic.oldamount
                       end), f_get_decimals_pattern(fp_customerid)) || 'Y' ||
               to_char(cic.startdate, 'YYYYMMDD') || 'C' || rpad(' ', 15, ' ') || 'PRICE'
        into   lv_specialcharge_details
        from   clientinvoicecategorycharge cic
        where  cic.clientinvoicecategory_id = fp_clientinvoicecategoryid
        and    cic.specialcharge_id = fp_specialchargeid;
      end;
    else
      begin
        for x in (select plc.generalpricelist_id, plc.priceindexcode
                  from   pricelistpercustomer plc
                  where  plc.customer_id = fp_customerid
                  and    plc.pricetype = 10
                  and    nvl(fp_pricedate, sysdate) between plc.dateactive and plc.dateinactive
                  order  by plc.priority asc) loop
          begin
            if x.generalpricelist_id is null then
              begin
                select case
                         when lv_fixedamount = 'Y' then
                          to_char(csp.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                          to_char(csp.startdate, 'YYYYMMDD') || 'C' || rpad(' ', 15, ' ') || 'PRICE'
                         else
                          to_char(csp.percentage, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                          to_char(csp.startdate, 'YYYYMMDD') || 'C' || rpad(' ', 15, ' ') ||
                          'PERCENTAGE'
                       end
                into   lv_specialcharge_details
                from   customerspecialchargeprice csp
                where  csp.customer_id = fp_customerid
                and    csp.specialcharge_id = fp_specialchargeid
                and    ((csp.price is not null and lv_fixedamount = 'Y') or
                      (lv_fixedamount <> 'Y' and csp.percentage is not null))
                and    csp.startdate =
                       (select max(csp2.startdate)
                         from   customerspecialchargeprice csp2
                         where  csp2.customer_id = csp.customer_id
                         and    csp2.specialcharge_id = csp.specialcharge_id
                         and    csp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
              end;
            else
              begin
                select case
                         when lv_fixedamount = 'Y' then
                          to_char(gsp.price, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                          to_char(gsp.startdate, 'YYYYMMDD') || 'G' || rpad(gp.code, 15, ' ') ||
                          'PRICE'
                         else
                          to_char(gsp.percentage, f_get_decimals_pattern(fp_customerid)) || 'Y' ||
                          to_char(gsp.startdate, 'YYYYMMDD') || 'G' || rpad(gp.code, 15, ' ') ||
                          'PERCENTAGE'
                       end
                into   lv_specialcharge_details
                from   generalspecialchargeprice gsp
                join   generalpricelist gp
                on     gp.generalpricelist_id = gsp.generalpricelist_id
                where  gsp.generalpricelist_id = x.generalpricelist_id
                and    gsp.specialcharge_id = fp_specialchargeid
                and    ((gsp.price is not null and lv_fixedamount = 'Y') or
                      (lv_fixedamount <> 'Y' and gsp.percentage is not null))
                and    gsp.startdate =
                       (select max(gsp2.startdate)
                         from   generalspecialchargeprice gsp2
                         where  gsp2.generalpricelist_id = gsp.generalpricelist_id
                         and    gsp2.specialcharge_id = gsp.specialcharge_id
                         and    gsp2.startdate <= trunc(nvl(fp_pricedate, sysdate)));
              end;
            end if;
            return lv_specialcharge_details;
          exception
            when no_data_found then
              null; --get next one
          end;
        end loop; --x
      end;
    end if;
    return nvl(lv_specialcharge_details, '            N');
  exception
    when no_data_found then
      return '            N'; --price found N
  end f_price_specialcharge;

end pack_price_customer;
/
create or replace package pack_price_new is
  /* ----------------------------------------------------------------------------------------------
   Package pack_price version 0.9d
  /* ---------------------------------------------------------------------------------------------- */
  /*
    18/11/2009 (502831) HVH New developed.
    08/01/2010          HVH Issue fixed with rent price for changes per week.
                            When exact# of changes was passed for size <> * in some cases wrong price was returned
    12/02/2010          HVH Added Weight Price and Weight Discount
    19/02/2010          HVH Added Rent and Wash Discount + performance improvement on all price search proc's
    22/03/2011          SSB Added Special Charge functions
    29/04/2011          HVH Improved Special Charge procedure and extended return string of SpecialCharge_Details
    21/11/2012          SSB Added Residential Rent functions
    13/02/2013          HVH Added Wash_Price_PT for washprices with specific pricetype (i.e. heavy soil)
                            Also added Loan_Price functions.
    01/03/2013          PVD Update for unrelated loan and changes before for general price determination
    17/09/2013          RVI Update for under/overuse wash prices
    25/02/2014          HVH Return replacement price when inventorybillingtype = 5
    27/02/2016          HVH Extended pricelistcode from 6 to 15 chars in xxx_price_details functions
    4/08/2017           DLA Updated for size billing group
    11/01/2018          DLA Fix for size billing group
    15/01/2018          SSB Fix for UK weekly underuse method
    19/05/2021          DLA ABS-117421 Size billing group NULL causing issues with display and invoicing
    19/08/2021          APA ABS-119993 Customer coefficient for replacement price
    13/09/2021          ABS-123845 PACK_PRICE call takes alot of time and get stuck
    16/11/2021          LAC ABS-118827 Replacement price for loss for pool with BM4 is not calculated
    21-01-2022          ABS-130035 Replacement price, redone for, Bill Loss Now Global Loss Price
    08/03/2022          ABS-130035 besides replacement price now also wash price calculated in right way
    10/03/2022          ABS-130035 besides replacement/wash price now also rent price calculated in right way
    15/03/2022          ABS-130035 besides replacement/wash/rent price now also sales price recalculated
  */

  /* ----------------------------------------------------------------------------------------------
  /* General remarks Rent price procedures/functions.
  
     This procedure and functions return the rent price (and other price details) for a given
     customer, product, size and finishingmethod, that is valid on the date that is passed in the
     parameter pricedate. If this optional parameter is omited, it will return the price valid on the sysdate.
  
     The procedure and functions can be used in 2 ways:
     a) To retrieve a price for a product list per customer line.
        (so without a specific # of changes or specific delivery frequency)
        For this purpose omit, or pass 0 to chgperwk_or_freq parameter.
        It will try to find the most recent valid price for any number of changes or any frequency.
  
     b) To retrieve a price for a product with a specific # of changes or specific delivery frequency.
        For this purpose pass a value <> 0 to chgperwk_or_freq parameter.
        For garments with billingmethod 1 a specific number of changes can be passed.
        If there is no price defined for that specific number of changes, it will try
        to find the price for number of changes *
        For delivery frequency based pricing it is possible to pass a specific frequency.
        The frequency is defined in # of weeks:
        Example: for delivery scheme EOW (Every other week) frequency = 2. (weekly=1)
  */

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Rent_Price_Details
  
    This is the base procedure used by the Rent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure get_rent_price_details(fp_customerid             in customer.customer_id%type,
                                   fp_productid              in product.product_id%type,
                                   fp_sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate              in pricelistpercustomer.dateactive%type,
                                   fp_chgperwk_or_freq       in generalrentprice.changesperweek%type,
                                   fp_price                  out customerrentprice.price%type,
                                   fp_price_found_yn         out varchar2,
                                   fp_price_start_date       out customerrentprice.startdate%type,
                                   fp_result_code            out number,
                                   fp_result_desc            out varchar2,
                                   fp_price_list_type        out varchar2,
                                   fp_price_list_code        out generalpricelist.code%type,
                                   fp_price_list_desc        out generalpricelist.description%type,
                                   fp_changesperwkfoundprice out customerrentprice.changesperweek%type,
                                   fp_price_type_code        out customerrentprice.typeofrent%type,
                                   fp_price_type_desc        out varchar2,
                                   fp_inv_freq_code          out customerrentprice.invoicefrequencynumber%type,
                                   fp_inv_freq_desc          out varchar2,
                                   fp_customerrentpriceid    out customerrentprice.customerrentprice_id%type);

  /* ----------------------------------------------------------------------------------------------
    Function Rent_Price_Details
  
    Returns all price details, like procedure Get_Rent_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181       ( 1): invoice freq code
    pos 182 - 191 (10): invoice freq description
    pos 192 - 201 (10): found price is defined for this number of changes per week
    pos 202 - 210 ( 9): price list code part 2 char 7-15
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    Y 1     Multiple prices applicable for different # of changes.
    Y 2     Multiple prices applicable for different frequencies.
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method with wash price only
    N 3     Price not relevant, billing method = 4 piece rate only
    N 4     Price not relevant, defined on wearer level as wearer total price.
    N 5     Price not relevant, defined at wearer function level
    N 8     Error in parameters
    N 9     ORA Error
  */
  function rent_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Rent_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function rent_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function CustomerRent_PriceID
     Use this function in calculations. It will return customer rent price id determined in Get_Rent_price_Details procedure.
  */
  function customerrent_priceid(customerid        in customer.customer_id%type,
                                productid         in product.product_id%type,
                                sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                finishingmethodid in finishingmethod.finishingmethod_id%type,
                                pricedate         in pricelistpercustomer.dateactive%type default null,
                                chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function Rent_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function rent_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;

  /* ---------------------------------------------------------------------------------------------- */
  /* General remarks Wash price procedures/functions.
  
     This procedure and functions return the wash price (and other price details) for a given
     customer, product, size and finishingmethod, that is valid on the date that is passed in the
     parameter pricedate. If this optional parameter is omited, it will return the price valid on the sysdate.
  
     The procedure and functions can be used in 2 ways:
     a) To retrieve a price for a product list per customer line.
        (so without indication if the price is for a LOG (Laundry Owned Goods) or COG (Customer Owned Goods) item)
        For this purpose omit, or pass 0 to pricetype parameter.
        It will try to find the most recent valid price for any number of changes or any frequency.
  
     b) To retrieve a price for a product for which it is known if it is a LOG or COG item.
        Pass 1 for LOG, pass 2 for COG to parameter pricetype
  
     c) To retrieve a price for a product for for a specific known price type (PT) use the Wash_Price_PT functions
        For example for price type Heavy Soil. Possible price types are described under Get_Wash_Price_Details_PT
  
  */

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Wash_Price_Details
  
    This is the base procedure used by the Wash_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */

  procedure get_wash_price_details(fp_customerid        in customer.customer_id%type,
                                   fp_productid         in product.product_id%type,
                                   fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate         in pricelistpercustomer.dateactive%type,
                                   fp_pricetype         in number, -- 0=all, 1=LOG, 2=COG
                                   fp_price             out customerwashprice.price%type,
                                   fp_price_found_yn    out varchar2,
                                   fp_price_start_date  out customerwashprice.startdate%type,
                                   fp_result_code       out number,
                                   fp_result_desc       out varchar2,
                                   fp_price_list_type   out varchar2,
                                   fp_price_list_code   out generalpricelist.code%type,
                                   fp_price_list_desc   out generalpricelist.description%type,
                                   fp_price_type_code   out customerwashprice.pricetype%type,
                                   fp_price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Price_Details
  
    Returns all price details, like procedure Get_Wash_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 189 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    Y 1     Distinct prices can be applicable LOG and COG
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method 3 with rent price only
    N 3     Price not relevant, billing method = 1 flat rated rent
    N 4     Price not relevant, billing method = 2 rent based on minimum
    N 5     Price not relevant, disposable / sales only item
    N 6     Price not relevant, billing method = 4 with price for LOG only
    N 7     Price not relevant, billing method = 4 with price for COG only
    N 8     Error in parameters
    N 9     ORA Error
  */
  function wash_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function wash_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      pricetype         in number default 0) return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function wash_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Wash_Price_Details_PT
  
    This is the base procedure used by the Wash_Price_PT functions.
    This procedure can be used to know all details about a wash price for a specified price type (PT)
  
    Possible price types are:
    1 = All items
    2 = COG items only
    3 = Price on client delivery note
    4 = Wash part of Split price
    5 = Heavy Soil
  */

  procedure get_wash_price_details_pt(customerid        in customer.customer_id%type,
                                      productid         in product.product_id%type,
                                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                                      pricedate         in pricelistpercustomer.dateactive%type,
                                      pricetype         in number,
                                      price             out customerwashprice.price%type,
                                      price_found_yn    out varchar2,
                                      price_start_date  out customerwashprice.startdate%type,
                                      result_code       out number,
                                      result_desc       out varchar2,
                                      price_list_type   out varchar2,
                                      price_list_code   out generalpricelist.code%type,
                                      price_list_desc   out generalpricelist.description%type,
                                      price_type_code   out customerwashprice.pricetype%type,
                                      price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Price_Details_PT
  
    Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
    Returns all price details, like procedure Get_Wash_Price_Details_PT,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 189 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function wash_price_details_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_PT
     Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function wash_price_pt(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         pricedate         in pricelistpercustomer.dateactive%type default null,
                         pricetype         in number) return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_Display_PT
     Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function wash_price_display_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return number;

  /* ----------------------------------------------------------------------------------------------
     Procedure Get_Replacement_Price_Details
  
     This is the base procedure used by the Replacement_PriceXXX functions.
     This procedure can be used to know all details about a price.
  */
  procedure get_replacement_price_details(fp_customerid        in customer.customer_id%type,
                                          fp_productid         in product.product_id%type,
                                          fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                          fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                          fp_pricedate         in pricelistpercustomer.dateactive%type,
                                          fp_price             out customerreplacementprice.price%type,
                                          fp_price_found_yn    out varchar2,
                                          fp_price_start_date  out customerreplacementprice.startdate%type,
                                          fp_result_code       out number,
                                          fp_result_desc       out varchar2,
                                          fp_price_list_type   out varchar2,
                                          fp_price_list_code   out generalpricelist.code%type,
                                          fp_price_list_desc   out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Replacement_Price_Details
  
    Returns all price details, like procedure Get_Replacement_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method = 4 piece rate only
    N 3     Price not relevant, disposable / sales only item
    N 8     Error in parameters
    N 9     ORA Error
  */
  function replacement_price_details(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Replacement_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function replacement_price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Replacement_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function replacement_price_display(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Procedure Get_Sales_Price_Details
  
     This is the base procedure used by the Sales_PriceXXX functions.
     This procedure can be used to know all details about a price.
  */
  procedure get_sales_price_details(fp_customerid       in customer.customer_id%type,
                                    fp_productid        in product.product_id%type,
                                    fp_sizedefinitionid in sizedefinition.sizedefinition_id%type,
                                    fp_pricedate        in pricelistpercustomer.dateactive%type,
                                    fp_price            out customersalesprice.price%type,
                                    fp_price_found_yn   out varchar2,
                                    fp_price_start_date out customersalesprice.startdate%type,
                                    fp_result_code      out number,
                                    fp_result_desc      out varchar2,
                                    fp_price_list_type  out varchar2,
                                    fp_price_list_code  out generalpricelist.code%type,
                                    fp_price_list_desc  out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Sales_Price_Details
  
    Returns all price details, like procedure Get_Sales_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function sales_price_details(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Sales_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function sales_price(customerid       in customer.customer_id%type,
                       productid        in product.product_id%type,
                       sizedefinitionid in sizedefinition.sizedefinition_id%type,
                       pricedate        in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Sales_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function sales_price_display(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_price_details(customerid         in customer.customer_id%type,
                                     weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                     soil_yn            in customerweightprice.soil%type,
                                     pricedate          in pricelistpercustomer.dateactive%type,
                                     price              out customerweightprice.price%type,
                                     price_found_yn     out varchar2,
                                     price_start_date   out customerweightprice.startdate%type,
                                     result_code        out number,
                                     result_desc        out varchar2,
                                     price_list_type    out varchar2,
                                     price_list_code    out generalpricelist.code%type,
                                     price_list_desc    out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Weight_Price_Details
  
    Returns all price details, like procedure Get_Weight_Price_Details,
    This function returns them all concatenated in a fixed length return string.
    Parameter soil_yn should be populated with 'Y' for soil weight price or 'N' for clean weight price.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, weights not invoiced
    N 3     Price not defined, weights invoiced soil, not clean
    N 4     Price not defined, weights invoiced clean, not soil
    N 8     Error in parameters
    N 9     ORA Error
  */

  function weight_price_details(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function weight_price(customerid         in customer.customer_id%type,
                        weighingcategoryid in weighingcategory.weighingcategory_id%type,
                        soil_yn            in customerweightprice.soil%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function weight_price_display(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_speccharge_details(customerid        in customer.customer_id%type,
                                   specialchargeid   in specialcharge.specialcharge_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerspecialchargeprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerspecialchargeprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type,
                                   specialchargecode out specialcharge.code%type,
                                   percentage        out customerspecialchargeprice.percentage%type,
                                   minimumamount     out specialcharge.minimumamount%type,
                                   maximumamount     out specialcharge.maximumamount%type);

  /* ----------------------------------------------------------------------------------------------
    Function SpecialCharge_Details
  
    Returns all price details, like procedure Get_SpecialCharge_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price format: 99999.99999 ,  spaces when no price found or not applicable.
    pos  13       ( 1): price or percentage returned Y / N
    pos  14 - 21  ( 8): price or percentage start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, B=Base table price, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69 - 74  ( 6): special charge code
    pos  75       ( 1): price result code , see list below.
    pos  76 - 155 (80): price result description
    pos 156 - 162 ( 7): percentage fromat: 999.99, spaces when not found or not applicable.
    pos 163 - 172 (10): minimum amount fromat: 999999.99, spaces when not found or not applicable.
    pos 173 - 182 (10): maximum amount fromat: 999999.99, spaces when not found or not applicable.
    pos 183 - 191 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price or percentage found, no remark
    N 1     Price or percentage not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */

  function specialcharge_details(customerid      in customer.customer_id%type,
                                 specialchargeid in specialcharge.specialcharge_id%type,
                                 pricedate       in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function specialcharge_price(customerid      in customer.customer_id%type,
                               specialchargeid in specialcharge.specialcharge_id%type,
                               pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function specialcharge_price_display(customerid      in customer.customer_id%type,
                                       specialchargeid in specialcharge.specialcharge_id%type,
                                       pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Percentage
     Use this function in calculations. It will return percentage 0.00 in case the percentage could not be found.
  */
  function specialcharge_percentage(customerid      in customer.customer_id%type,
                                    specialchargeid in specialcharge.specialcharge_id%type,
                                    pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Perc_Display
     Use this function for display or print purposes. It will return null in case the percentage could not be found.
  */
  function specialcharge_percentage_disp(customerid      in customer.customer_id%type,
                                         specialchargeid in specialcharge.specialcharge_id%type,
                                         pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MinAmount
     Use this function in calculations. It will return MinAmount 0.00 in case the MinAmount could not be found.
  */
  function specialcharge_minamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MinAmount_Disp
     Use this function for display or print purposes. It will return null in case the MinAmount could not be found.
  */
  function specialcharge_minamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MaxAmount
     Use this function in calculations. It will return MaxAmount 0.00 in case the MaxAmount could not be found.
  */
  function specialcharge_maxamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MaxAmount_Disp
     Use this function for display or print purposes. It will return null in case the MaxAmount could not be found.
  */
  function specialcharge_maxamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_rent_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerrentdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerrentdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Rent_Discount_Details
  
    Returns all Discount details, like procedure Get_Rent_Discount_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description
  
    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, billing method with wash price only
    N 3     Discount not relevant, billing method = 4 piece rate only
    N 4     Discount not applicable, price defined on wearer level as wearer total price.
    N 5     Discount not applicable, price defined at wearer function level
    N 8     Discount in parameters
    N 9     ORA Error
  */

  function rent_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */

  function rent_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */

  function rent_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerwashdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerwashdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Discount_Details
  
    Returns all Discount details, like procedure Get_Wash_Discount_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description
  
    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, billing method 3 with rent price only
    N 3     Discount not defined, billing method = 1 flat rated rent
    N 4     Discount not defined, billing method = 2 rent based on minimum
    N 5     Discount not relevant, disposable / sales only item
    N 8     Error in parameters
    N 9     ORA Error
  */

  function wash_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */

  function wash_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */

  function wash_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_discount_details(customerid          in customer.customer_id%type,
                                        weighingcategoryid  in weighingcategory.weighingcategory_id%type,
                                        soil_yn             in customerweightdiscount.soil%type,
                                        discountdate        in discountlistpercustomer.dateactive%type,
                                        discount            out customerweightdiscount.discount%type,
                                        discount_found_yn   out varchar2,
                                        discount_start_date out customerweightdiscount.startdate%type,
                                        result_code         out number,
                                        result_desc         out varchar2,
                                        discount_list_type  out varchar2,
                                        discount_list_code  out generaldiscountlist.code%type,
                                        discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Weight_Discount_Details
  
    Returns all Discount details, like procedure Get_Weight_Discount_Details,
    This function returns them all concatenated in a fixed length return string.
    Parameter soil_yn should be populated with 'Y' for soil weight Discount or 'N' for clean weight Discount.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description
  
    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, weights not invoiced
    N 3     Discount not defined, weights invoiced soil, not clean
    N 4     Discount not defined, weights invoiced clean, not soil
    N 8     Error in parameters
    N 9     ORA Error
  */

  function weight_discount_details(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */
  function weight_discount(customerid         in customer.customer_id%type,
                           weighingcategoryid in weighingcategory.weighingcategory_id%type,
                           soil_yn            in customerweightdiscount.soil%type,
                           discountdate       in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */
  function weight_discount_display(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_ResidentialRent_Price_Details
  
    This is the base procedure used by the ResidentialRent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure get_residrent_price_details(customerid        in customer.customer_id%type,
                                        productid         in product.product_id%type,
                                        sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                        finishingmethodid in finishingmethod.finishingmethod_id%type,
                                        pricedate         in pricelistpercustomer.dateactive%type,
                                        price             out customerrentprice.price%type,
                                        price_found_yn    out varchar2,
                                        price_start_date  out customerrentprice.startdate%type,
                                        result_code       out number,
                                        result_desc       out varchar2,
                                        price_list_type   out varchar2,
                                        price_list_code   out generalpricelist.code%type,
                                        price_list_desc   out generalpricelist.description%type,
                                        price_type_code   out customerrentprice.typeofrent%type,
                                        price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function ResidentialRent_Price_Details
  
    Returns all price details, like procedure Get_ResidentialRent_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 190 (10): found price is defined for this number of changes per week
    pos 191 - 199 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method with wash price only
    N 3     Price not relevant, billing method = 4 piece rate only
    N 4     Price not relevant, defined on wearer level as wearer total price.
    N 5     Price not relevant, defined at wearer function level
    N 8     Error in parameters
    N 9     ORA Error
  */
  function residentialrent_price_details(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function ResidentialRent_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function residentialrent_price(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function ResidentialRent_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function residentialrent_price_display(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Loan_Price_Details
  
    This is the base procedure used by the Rent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure get_loan_price_details(customerid        in customer.customer_id%type,
                                   productid         in product.product_id%type,
                                   sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerrentprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerrentprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Loan_Price_Details
  
    Returns all price details, like procedure Get_Loan_Price_Details,
    This function returns them all concatenated in a fixed length return string.
  
    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15
  
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function loan_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Loan_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function loan_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Loan_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function loan_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Budget_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function budget_price(fpcustomerid    customerbudgetdefinition.customer_id%type,
                        fpcode          customerbudgetdefinition.code%type,
                        fpreferencedate date) return number;

  function customer_uses_specialprices(customerid in customer.customer_id%type) return boolean;
  function get_standard_szbillinggroup return number;
  function get_product_size_billinggroup(productid in product.product_id%type,
                                         sizeid    in sizedefinition.sizedefinition_id%type)
    return number;
  procedure get_size_billing_groups(customerid                     in customer.customer_id%type,
                                    productid                      in product.product_id%type,
                                    sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                    pricetype                      number,
                                    lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                    lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type);
end pack_price_new;

/
create or replace package body pack_price_new is
  /*--------------------------------------------------------------------------------------------------------*/
  --internal functions/procedures
  function getsizestarid return number is
    lv_sizestarid number;
  begin
    select sd.sizedefinition_id into lv_sizestarid from sizedefinition sd where sd.code = '*';
    return lv_sizestarid;
  exception
    when no_data_found then
      return null;
  end getsizestarid;

  function get_product_size_billinggroup(productid     in product.product_id%type,
                                         sizeid        in sizedefinition.sizedefinition_id%type,
                                         fp_sizestarid in number) return number is
    sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
  begin
    select ps.sizebillinggroup_id
    into   sizebillinggroupid
    from   productsize ps
    where  ps.product_id = productid
    and    ps.sizedefinition_id = sizeid;
    if (sizebillinggroupid is null) then
      begin
        if (sizeid = fp_sizestarid) then
          select sd.sizebillinggroup_id
          into   sizebillinggroupid
          from   sizedefinition sd
          where  sd.sizedefinition_id = fp_sizestarid;
        end if;
      end;
    end if;
    return nvl(sizebillinggroupid, 0);
  exception
    when no_data_found then
      begin
        select sd.sizebillinggroup_id
        into   sizebillinggroupid
        from   sizedefinition sd
        where  sd.sizedefinition_id = sizeid;
        return sizebillinggroupid;
      exception
        when no_data_found then
          return 0;
      end;
  end get_product_size_billinggroup;

  procedure get_size_billing_groups2(customerid                     in customer.customer_id%type,
                                     productid                      in product.product_id%type,
                                     sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                     fp_sizestarid                  in number,
                                     pricetype                      number,
                                     lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                     lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type) is
    lv_customer_uses_sz_billing    boolean;
    lv_ss_sizespecialchargeoptions int;
    lv_is_special_size_price_used  boolean;
  begin
    begin
      select value
      into   lv_ss_sizespecialchargeoptions
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'SIZESPECIALCHARGEOPTIONS'
      and    c.customer_id = customerid;
    exception
      when no_data_found then
        lv_ss_sizespecialchargeoptions := 0;
    end;
    if lv_ss_sizespecialchargeoptions <> 0 then
      begin
        if pricetype = 2 then
          lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 1 or
                                           lv_ss_sizespecialchargeoptions = 4 or
                                           lv_ss_sizespecialchargeoptions = 5 or
                                           lv_ss_sizespecialchargeoptions = 7;
        end if;
        if pricetype = 3 then
          lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 3 or
                                           lv_ss_sizespecialchargeoptions = 5 or
                                           lv_ss_sizespecialchargeoptions = 6 or
                                           lv_ss_sizespecialchargeoptions = 7;
        end if;
        if pricetype = 4 then
          lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 2 or
                                           lv_ss_sizespecialchargeoptions = 4 or
                                           lv_ss_sizespecialchargeoptions = 6 or
                                           lv_ss_sizespecialchargeoptions = 7;
        end if;
        --when used first exact, then standard then NULL (0)
        lv_customer_uses_sz_billing    := customer_uses_specialprices(customerid);
        lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
        if lv_customer_uses_sz_billing and lv_is_special_size_price_used then
          lv_specific_sizebillinggroupid := get_product_size_billinggroup(productid,
                                                                          sizedefinitionid,
                                                                          fp_sizestarid);
        else
          lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
        end if;
      end;
    else
      begin
        --when not used first NULL (0) then standard billinggroup
        lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
        lv_specific_sizebillinggroupid := 0;
      end;
    end if;
  end get_size_billing_groups2;
  --  
  procedure get_plpc_info(fp_customerid                  in number,
                          fp_productid                   in number,
                          fp_sizeid                      in number,
                          fp_sizestarid                  in number,
                          fp_finishingmethodid           in number,
                          fp_date                        in out date,
                          fp_plpcid                      out number,
                          fp_billingmethod               out number,
                          fp_inventorybillingtype        out number,
                          fp_chargelossforpool           out varchar2,
                          fp_priceusage                  out number,
                          fp_tom                         out number,
                          fp_garmentrentspecification    out number,
                          fp_businessunitid              out number,
                          fp_chargewashesonlyforcog      out productlistpercustomer.chargewashesonlyforcog%type,
                          fp_minimumturnaround           out productlistpercustomer.minimumturnaround%type,
                          fp_rentpriceperfrequency       out productlistpercustomer.rentpriceperfrequency%type,
                          fp_invoicefreqrelatedrentprice out productlistpercustomer.invoicefreqrelatedrentprice%type,
                          fp_splitinvoicesperactivity    out customer.splitinvoicesperactivity%type,
                          fp_productgroupid              out productgroup.productgroup_id%type) is
    lv_price_lookupdate date;
  
    procedure lookup_plpc is
    begin
      --lookup_plpc
      select l.productlistpercustomer_id, l.billingmethod, l.inventorybillingtype,
             l.chargelossforpool, l.priceusage, p.typeofmerchandise, c.garmentrentspecification,
             c.defaultbusinessunit_id, l.chargewashesonlyforcog, l.minimumturnaround,
             l.rentpriceperfrequency, l.invoicefreqrelatedrentprice, c.splitinvoicesperactivity,
             p.productgroup_id
      into   fp_plpcid, fp_billingmethod, fp_inventorybillingtype, fp_chargelossforpool,
             fp_priceusage, fp_tom, fp_garmentrentspecification, fp_businessunitid,
             fp_chargewashesonlyforcog, fp_minimumturnaround, fp_rentpriceperfrequency,
             fp_invoicefreqrelatedrentprice, fp_splitinvoicesperactivity, fp_productgroupid
      from   productlistpercustomer l
      join   product p
      on     p.product_id = l.product_id
      join   customer c
      on     c.customer_id = l.customer_id
      where  l.customer_id = fp_customerid
      and    l.product_id = fp_productid
      and    l.sizedefinition_id = fp_sizeid
      and    l.finishingmethod_id = fp_finishingmethodid
      and    (lv_price_lookupdate >= l.dateactive and lv_price_lookupdate <= l.dateinactive);
    exception
      when no_data_found then
        begin
          --search size star
          select l.productlistpercustomer_id, l.billingmethod, l.inventorybillingtype,
                 l.chargelossforpool, l.priceusage, p.typeofmerchandise, c.garmentrentspecification,
                 c.defaultbusinessunit_id, l.chargewashesonlyforcog, l.minimumturnaround,
                 l.rentpriceperfrequency, l.invoicefreqrelatedrentprice, c.splitinvoicesperactivity,
                 p.productgroup_id
          into   fp_plpcid, fp_billingmethod, fp_inventorybillingtype, fp_chargelossforpool,
                 fp_priceusage, fp_tom, fp_garmentrentspecification, fp_businessunitid,
                 fp_chargewashesonlyforcog, fp_minimumturnaround, fp_rentpriceperfrequency,
                 fp_invoicefreqrelatedrentprice, fp_splitinvoicesperactivity, fp_productgroupid
          from   productlistpercustomer l
          join   product p
          on     p.product_id = l.product_id
          join   customer c
          on     c.customer_id = l.customer_id
          where  l.customer_id = fp_customerid
          and    l.product_id = fp_productid
          and    l.sizedefinition_id = fp_sizestarid
          and    l.finishingmethod_id = fp_finishingmethodid
          and    (lv_price_lookupdate >= l.dateactive and lv_price_lookupdate <= l.dateinactive);
        exception
          when no_data_found then
            begin
              --no data found
              fp_plpcid                      := null;
              fp_billingmethod               := null;
              fp_inventorybillingtype        := null;
              fp_chargelossforpool           := null;
              fp_priceusage                  := null;
              fp_tom                         := null;
              fp_garmentrentspecification    := null;
              fp_businessunitid              := null;
              fp_chargewashesonlyforcog      := null;
              fp_minimumturnaround           := null;
              fp_rentpriceperfrequency       := null;
              fp_invoicefreqrelatedrentprice := null;
              fp_splitinvoicesperactivity    := null;
              fp_productgroupid              := null;
            end;
        end;
    end lookup_plpc;
  begin
    lv_price_lookupdate := nvl(fp_date, trunc(sysdate));
    --get_plpc_info
    lookup_plpc;
    --not found lookup inactive PLPC
    if fp_plpcid is null and fp_date is null then
      begin
        --look for old PLPC
        select max(l.dateinactive)
        into   lv_price_lookupdate
        from   productlistpercustomer l
        join   product p
        on     p.product_id = l.product_id
        join   customer c
        on     c.customer_id = l.customer_id
        where  l.customer_id = fp_customerid
        and    l.product_id = fp_productid
        and    l.sizedefinition_id = fp_sizeid
        and    l.finishingmethod_id = fp_finishingmethodid
        and    l.dateinactive < nvl(fp_date, trunc(sysdate));
        if lv_price_lookupdate is null then
          begin
            --look for old PLPC size star
            select max(l.dateinactive)
            into   lv_price_lookupdate
            from   productlistpercustomer l
            join   product p
            on     p.product_id = l.product_id
            join   customer c
            on     c.customer_id = l.customer_id
            where  l.customer_id = fp_customerid
            and    l.product_id = fp_productid
            and    l.sizedefinition_id = fp_sizestarid
            and    l.finishingmethod_id = fp_finishingmethodid
            and    l.dateinactive < nvl(fp_date, trunc(sysdate));
          end;
        end if;
        if lv_price_lookupdate is not null then
          begin
            fp_date := lv_price_lookupdate;
            --get_plpc_info
            lookup_plpc;
          end;
        else
          begin
            --might not need a PLPC
            fp_date := nvl(fp_date, trunc(sysdate));
          end;
        end if;
      end;
    else
      fp_date := lv_price_lookupdate;
    end if;
  end get_plpc_info;
  /*--------------------------------------------------------------------------------------------------------*/

  procedure get_rent_price_details(fp_customerid             in customer.customer_id%type,
                                   fp_productid              in product.product_id%type,
                                   fp_sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate              in pricelistpercustomer.dateactive%type,
                                   fp_chgperwk_or_freq       in generalrentprice.changesperweek%type,
                                   fp_price                  out customerrentprice.price%type,
                                   fp_price_found_yn         out varchar2,
                                   fp_price_start_date       out customerrentprice.startdate%type,
                                   fp_result_code            out number,
                                   fp_result_desc            out varchar2,
                                   fp_price_list_type        out varchar2,
                                   fp_price_list_code        out generalpricelist.code%type,
                                   fp_price_list_desc        out generalpricelist.description%type,
                                   fp_changesperwkfoundprice out customerrentprice.changesperweek%type,
                                   fp_price_type_code        out customerrentprice.typeofrent%type,
                                   fp_price_type_desc        out varchar2,
                                   fp_inv_freq_code          out customerrentprice.invoicefrequencynumber%type,
                                   fp_inv_freq_desc          out varchar2,
                                   fp_customerrentpriceid    out customerrentprice.customerrentprice_id%type) is
    --locale variables
    lv_databasecode                        databasesettings.code%type;
    lv_pricedate                           date;
    lv_plpcid                              number;
    lv_billingmethod                       number;
    lv_inventorybillingtype                number;
    lv_chargelossforpool                   varchar2(1);
    lv_priceusage                          number;
    lv_tom                                 number;
    lv_garmentrentspecification            number;
    lv_sizestarid                          sizedefinition.sizedefinition_id%type;
    lv_businessunitid                      number;
    lv_underuse_count                      number := 0;
    lv_typeofrent                          customerrentprice.typeofrent%type;
    lv_chargewashesonlyforcog              productlistpercustomer.chargewashesonlyforcog%type;
    lv_minimumturnaround                   productlistpercustomer.minimumturnaround%type;
    lv_standard_sizebillinggroupid         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizebillinggroupid         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizebillinggroupid sizebillinggroup.systemuser_id%type;
    lv_rentpriceperfrequency               productlistpercustomer.rentpriceperfrequency%type;
    lv_invoicefreqrelatedrentprice         productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_changesperweek                      customerrentprice.changesperweek%type;
    lv_splitinvoicesperactivity            customer.splitinvoicesperactivity%type;
    lv_invoice_freq                        customerrentprice.invoicefrequencynumber%type;
    lv_productgroupid                      product.productgroup_id%type;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'Y1',
                     'Multiple prices can be applicable for different # of changes', 'Y2',
                     'Multiple prices can be applicable for different frequencies', 'N1',
                     'Price not defined', 'N2',
                     'Price not relevant, billing method 3 with wash price only', 'N3',
                     'Price not relevant, billing method = 4 piece rate only', 'N4',
                     'Price not relevant, defined at wearer level as wearer total price', 'N5',
                     'Price not relevant, defined at wearer function level', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end decode_error;
  
    function decode_inv_freq(fpfreq_code in varchar2) return varchar2 is
    begin
      case fpfreq_code
        when '40' then
          return('4 Weekly');
        when '110' then
          return('Monthly');
        else
          return('Weekly');
      end case;
    end decode_inv_freq;
  
    function decode_type_of_rent(fptypeofrent in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fptypeofrent, 1, 'Price per Piece', 2, 'Changes per Week', 3, 'Overuse Price', 4,
                     'Frequency Based Price', 5, 'Underuse Price', 6, 'Lease Price', 7, 'Split Price',
                     8, 'Price per Invoice Freq.', 'Unknown type of rent')
      into   r
      from   dual;
      return r;
    end decode_type_of_rent;
  
    procedure initialize is
    begin
      --initialize
      lv_pricedate       := fp_pricedate;
      fp_price_found_yn  := 'N';
      fp_price_list_type := 2;
      lv_invoice_freq    := 10; -- default is weekly
      lv_sizestarid      := getsizestarid;
      lv_changesperweek  := fp_chgperwk_or_freq;
      --get_plpc_info
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
      --
      get_size_billing_groups2(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid, 3,
                               lv_standard_sizebillinggroupid,
                               lv_initial_specific_sizebillinggroupid);
      --get db code  
      select db.code into lv_databasecode from databasesettings db;
    end initialize;
  
    procedure lookforprice is
      procedure get_generalrentprice(fp_generalpricelistid in number,
                                     fp_sizeid             in number,
                                     fp_changesperweek     in number) is
      begin
        if fp_changesperweek = 0 then
          begin
            --get general rent price, no check changes per week
            for y in (select grp.price price, grp.startdate, g.code, g.description,
                             grp.changesperweek
                      from   generalrentprice grp
                      join   generalpricelist g
                      on     g.generalpricelist_id = grp.generalpricelist_id
                      where  g.pricetype = 2 -- rent price
                      and    grp.typeofrent = lv_typeofrent
                      and    g.active = 'Y'
                      and    g.generalpricelist_id = fp_generalpricelistid
                      and    grp.product_id = fp_productid
                      and    grp.sizedefinition_id = fp_sizeid
                      and    grp.finishingmethod_id = fp_finishingmethodid
                      and    grp.startdate <= lv_pricedate
                      and    (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by grp.startdate desc, grp.changesperweek asc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := y.price;
                fp_price_start_date       := y.startdate;
                fp_price_list_type        := 'G'; -- general
                fp_price_list_code        := y.code;
                fp_price_list_desc        := y.description;
                fp_changesperwkfoundprice := y.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        else
          begin
            --get general rent price, check changes per week
            for y in (select grp.price price, grp.startdate, g.code, g.description,
                             grp.changesperweek
                      from   generalrentprice grp
                      join   generalpricelist g
                      on     g.generalpricelist_id = grp.generalpricelist_id
                      where  g.pricetype = 2 -- rent price
                      and    grp.typeofrent = lv_typeofrent
                      and    g.active = 'Y'
                      and    g.generalpricelist_id = fp_generalpricelistid
                      and    grp.product_id = fp_productid
                      and    grp.sizedefinition_id = fp_sizeid
                      and    grp.finishingmethod_id = fp_finishingmethodid
                      and    grp.changesperweek = lv_changesperweek
                      and    grp.startdate <= lv_pricedate
                      and    (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by grp.startdate desc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := y.price;
                fp_price_start_date       := y.startdate;
                fp_price_list_type        := 'G'; -- general
                fp_price_list_code        := y.code;
                fp_price_list_desc        := y.description;
                fp_changesperwkfoundprice := y.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        end if;
      end get_generalrentprice;
    
      procedure get_customerentprice(fp_changesperweek in number) is
      begin
        if fp_changesperweek = 0 then
          begin
            --get customer rent price, no check changes per week
            for z in (select curp.price, curp.startdate, curp.customerrentprice_id,
                             curp.changesperweek
                      from   customerrentprice curp
                      where  curp.productlistpercustomer_id = lv_plpcid
                      and    curp.typeofrent = lv_typeofrent
                      and    curp.startdate <= lv_pricedate
                      and    (curp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(curp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by curp.startdate desc, curp.changesperweek asc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := z.price;
                fp_price_start_date       := z.startdate;
                fp_price_list_type        := 'C'; -- customer specific
                fp_price_list_code        := null;
                fp_price_list_desc        := 'Customer Specific.';
                fp_customerrentpriceid    := z.customerrentprice_id;
                fp_changesperwkfoundprice := z.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        else
          begin
            --get customer replacement price, check changes per week
            for z in (select curp.price, curp.startdate, curp.customerrentprice_id,
                             curp.changesperweek
                      from   customerrentprice curp
                      where  curp.productlistpercustomer_id = lv_plpcid
                      and    curp.typeofrent = lv_typeofrent
                      and    curp.changesperweek = lv_changesperweek
                      and    curp.startdate <= lv_pricedate
                      and    (curp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent <> 8)
                      and    nvl(curp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                      order  by curp.startdate desc) loop
              begin
                fp_price_found_yn         := 'Y';
                fp_price                  := z.price;
                fp_price_start_date       := z.startdate;
                fp_price_list_type        := 'C'; -- customer specific
                fp_price_list_code        := null;
                fp_price_list_desc        := 'Customer Specific.';
                fp_customerrentpriceid    := z.customerrentprice_id;
                fp_changesperwkfoundprice := z.changesperweek;
                --price found exit loop
                exit;
              end;
            end loop;
          end;
        end if;
      end get_customerentprice;
    
      procedure lookpricefor_sgb(fp_generalpricelistid in number) is
      begin
        if fp_generalpricelistid is not null then
          begin
            --look for size equal
            get_generalrentprice(fp_generalpricelistid, fp_sizedefinitionid, lv_changesperweek);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_generalrentprice(fp_generalpricelistid, lv_sizestarid, lv_changesperweek);
              end;
            end if;
            --look for change per week -1
            if lv_typeofrent = 2 and lv_changesperweek <> 0 and lv_changesperweek <> -1 and
               fp_price_found_yn = 'N' then
              begin
                get_generalrentprice(fp_generalpricelistid, fp_sizedefinitionid, -1);
                if fp_price_found_yn = 'N' then
                  begin
                    --look for size star, changes per week -1
                    get_generalrentprice(fp_generalpricelistid, lv_sizestarid, -1);
                  end;
                end if;
              end;
            end if;
          end;
        else
          begin
            --look for size equal
            get_customerentprice(lv_changesperweek);
            --look for change per week -1
            if lv_typeofrent = 2 and lv_changesperweek <> 0 and lv_changesperweek <> -1 and
               fp_price_found_yn = 'N' then
              begin
                get_customerentprice(-1);
              end;
            end if;
          end;
        end if;
      end lookpricefor_sgb;
    begin
      --lookforprice rentprice
      for x in (select plc.generalpricelist_id
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 2 -- rent price
                and    plc.dateactive <= lv_pricedate
                and    plc.dateinactive >= lv_pricedate
                order  by plc.priority) loop
        begin
          lv_specific_sizebillinggroupid := lv_initial_specific_sizebillinggroupid;
          lookpricefor_sgb(x.generalpricelist_id);
          if fp_price_found_yn = 'N' then
            begin
              --start look for different sizebillinggroup
              if lv_specific_sizebillinggroupid <> lv_standard_sizebillinggroupid then
                begin
                  --standard sizebillinggroup
                  lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
              if fp_price_found_yn = 'N' and lv_specific_sizebillinggroupid <> 0 then
                begin
                  --no sizebillinggroup
                  lv_specific_sizebillinggroupid := 0;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
            end;
          end if; --price found N
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --initialize
    initialize;
    lv_typeofrent := 1;
    --
    if lv_billingmethod = 3 and lv_priceusage = 3 then
      /*wash only*/
      fp_result_code := 2; -- Price not relevant, billing method with wash price only
    elsif lv_billingmethod = 4 then
      fp_result_code := 3; -- Price not relevant, billing method = 4 piece rate only
    elsif lv_billingmethod = 1 and lv_tom = 2 and lv_garmentrentspecification = 5 then
      -- total wearer price
      fp_result_code := 4; -- Price not relevant, wearer total price
    elsif lv_billingmethod = 1 and lv_tom = 2 and lv_garmentrentspecification = 6 then
      -- wearer function price
      fp_result_code := 5; -- Price not relevant, wearer function price
    else
      begin
        if lv_billingmethod = 1 and lv_tom = 2 -- changes per week
         then
          lv_typeofrent := 2; -- changes per week
        else
          if lv_billingmethod = 1 and lv_tom <> 2 and lv_rentpriceperfrequency = 'Y' then
            lv_typeofrent := 4; -- frequency based
          else
            lv_changesperweek := 0;
          end if; -- frequency based=Y
        end if; -- changes/week
        if lv_billingmethod = 3 and lv_priceusage = 1 /* split */
         then
          lv_typeofrent := 7; -- split
        end if;
        if lv_billingmethod = 5 then
          lv_typeofrent := 6; -- lease
        end if;
        if lv_billingmethod = 2 and lv_minimumturnaround <> 0 and lv_databasecode <> 'AMM' then
          begin
            --check_underuse
            select count(1)
            into   lv_underuse_count
            from   systemsetting st
            join   businessunit bu
            on     bu.plant_id = st.plant_id
            where  st.name = 'UNDERUSEMETHOD'
            and    st.value in ('2', '4')
            and    bu.businessunit_id = lv_businessunitid;
            if lv_underuse_count > 0 then
              --underuse
              lv_typeofrent := 5;
            end if;
          end;
        end if;
        --
        if lv_billingmethod = 3 and lv_invoicefreqrelatedrentprice = 'Y' and
           lv_splitinvoicesperactivity = 'Y' then
          begin
            lv_typeofrent := 8;
            -- determine invoice frequency. Take lowest frequency,(to avoid BU determination) assuming that
            -- an activity for a customer is processed in only 1 plant,
            -- or if in multiple they have the same invoice frequency.
            select min(freq.invoicefrequencynumber) -- take lowest freq.
            into   lv_invoice_freq
            from   customeractivities ca, invoicefrequency freq, productgroup pg
            where  ca.customer_id = fp_customerid
            and    ca.activity_id = pg.activity_id
            and    pg.productgroup_id = lv_productgroupid
            and    freq.invoicefrequency_id = ca.invoicefrequency_id;
            if lv_invoice_freq < 100 and lv_invoice_freq <> 40 then
              lv_invoice_freq := 10;
            end if;
            if lv_invoice_freq > 100 then
              lv_invoice_freq := 110;
            end if;
          end;
        end if;
        --lookforprice
        lookforprice;
      end;
    end if;
    if fp_price_found_yn = 'Y' then
      begin
        if fp_chgperwk_or_freq = 0 then
          case lv_typeofrent
            when 2 then
              fp_result_code := '1'; -- when typeofrent is chgsperweek return result code about multiple prices possible
            when 4 then
              fp_result_code := '2'; -- when typeofrent is frequency return result code about multiple prices possible
            else
              fp_result_code := '0';
          end case;
        else
          fp_result_code := '0';
        end if;
        fp_result_desc     := decode_error('Y' || to_char(fp_result_code));
        fp_price_type_code := lv_typeofrent;
        fp_price_type_desc := decode_type_of_rent(fp_price_type_code);
        fp_inv_freq_code   := lv_invoice_freq;
        fp_inv_freq_desc   := decode_inv_freq(fp_inv_freq_code);
      end;
    else
      begin
        if fp_result_code is null then
          -- no price found
          fp_result_code := 1;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_rent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(to_char(inv_freq_code), ' '), 1) ||
           rpad(nvl(inv_freq_desc, ' '), 10) ||
           lpad(nvl(to_char(changesperwkfoundprice), ' '), 10) ||
           rpad(nvl(to_char(customerrentpriceid), ' '), 1) ||
           rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end rent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(nvl(price, 0));
  end rent_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function customerrent_priceid(customerid        in customer.customer_id%type,
                                productid         in product.product_id%type,
                                sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                finishingmethodid in finishingmethod.finishingmethod_id%type,
                                pricedate         in pricelistpercustomer.dateactive%type default null,
                                chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(nvl(customerrentpriceid, 0));
  end customerrent_priceid;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
  
    price                  customerrentprice.price%type;
    price_found_yn         varchar2(1);
    price_start_date       customerrentprice.startdate%type;
    result_code            number;
    result_desc            varchar2(80);
    price_list_type        varchar2(1);
    price_list_code        generalpricelist.code%type;
    price_list_desc        generalpricelist.description%type;
    changesperwkfoundprice customerrentprice.changesperweek%type;
    price_type_code        customerrentprice.typeofrent%type;
    price_type_desc        varchar2(30);
    inv_freq_code          customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc          varchar2(10);
    customerrentpriceid    customerrentprice.customerrentprice_id%type;
  
  begin
    get_rent_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           chgperwk_or_freq, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           changesperwkfoundprice, price_type_code, price_type_desc, inv_freq_code,
                           inv_freq_desc, customerrentpriceid);
    return(price);
  end rent_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_price_details(fp_customerid        in customer.customer_id%type,
                                   fp_productid         in product.product_id%type,
                                   fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   fp_pricedate         in pricelistpercustomer.dateactive%type,
                                   fp_pricetype         in number, -- 0=all, 1=LOG, 2=COG
                                   fp_price             out customerwashprice.price%type,
                                   fp_price_found_yn    out varchar2,
                                   fp_price_start_date  out customerwashprice.startdate%type,
                                   fp_result_code       out number,
                                   fp_result_desc       out varchar2,
                                   fp_price_list_type   out varchar2,
                                   fp_price_list_code   out generalpricelist.code%type,
                                   fp_price_list_desc   out generalpricelist.description%type,
                                   fp_price_type_code   out customerwashprice.pricetype%type,
                                   fp_price_type_desc   out varchar2) is
    --locale variables
    lv_pricedate                   date;
    lv_plpcid                      number;
    lv_billingmethod               number;
    lv_inventorybillingtype        number;
    lv_chargelossforpool           varchar2(1);
    lv_priceusage                  number;
    lv_tom                         number;
    lv_garmentrentspecification    number;
    lv_sizestarid                  sizedefinition.sizedefinition_id%type;
    lv_businessunitid              number;
    lv_underuse_count              number := 0;
    lv_chargewashesonlyforcog      productlistpercustomer.chargewashesonlyforcog%type;
    lv_minimumturnaround           productlistpercustomer.minimumturnaround%type;
    lv_pricetype                   customerwashprice.pricetype%type;
    lv_pricetype_gen_prlist        generalwashprice.pricetype%type;
    lv_rentpriceperfrequency       productlistpercustomer.rentpriceperfrequency%type;
    lv_invoicefreqrelatedrentprice productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_splitinvoicesperactivity    customer.splitinvoicesperactivity%type;
    lv_productgroupid              product.productgroup_id%type;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'Y1',
                     'Distinct prices can be applicable LOG and COG', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, billing method 3 with rent price only', 'N3',
                     'Price not relevant, billing method = 1 flat rated rent', 'N4',
                     'Price not relevant, billing method = 2 rent based on minimum', 'N5',
                     'Price not relevant, disposable / sales only item', 'N6',
                     'Price not relevant, billing method = 4 with price for LOG only', 'N7',
                     'Price not relevant, billing method = 4 with price for COG only', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end decode_error;
  
    function decode_price_type(fppricetype in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fppricetype, 1, 'All (COG or LOG)', 2, 'COG Only', 4, 'Split Price',
                     'Unknown price type')
      into   r
      from   dual;
      return r;
    end decode_price_type;
  
    procedure initialize is
    begin
      --initialize
      lv_pricedate       := fp_pricedate;
      fp_price_found_yn  := 'N';
      fp_price_list_type := 1;
      lv_sizestarid      := getsizestarid;
      --get_plpc_info on size level
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
    end initialize;
  
    procedure lookforprice is
      procedure get_generalwhprice(fp_generalpricelistid in number, fp_sizeid in number) is
      begin
        --get_generalwhprice
        if fp_pricetype = 0 -- not specified LOG or COG take most recent active price
           and lv_pricetype_gen_prlist <> 4 -- for split price always look for split prices
           and not (lv_billingmethod = 4 and lv_chargewashesonlyforcog = 3) -- for COG only look only for COG prices
         then
          begin
            for a in (select gwp.price, gwp.startdate, gwp.pricetype, g.code, g.description
                      from   generalwashprice gwp
                      join   generalpricelist g
                      on     g.generalpricelist_id = gwp.generalpricelist_id
                      where  g.generalpricelist_id = fp_generalpricelistid
                      and    g.pricetype = 1 -- Wash
                      and    g.active = 'Y'
                      and    gwp.product_id = fp_productid
                      and    gwp.sizedefinition_id = fp_sizeid
                      and    gwp.finishingmethod_id = fp_finishingmethodid
                      and    gwp.startdate <= lv_pricedate
                      and    (gwp.pricetype <> 4 or lv_billingmethod <> 4) -- don't select split prices for BM 4
                      order  by gwp.startdate desc, gwp.pricetype asc) loop
              begin
                fp_price_found_yn   := 'Y';
                fp_price            := a.price;
                fp_price_start_date := a.startdate;
                fp_price_list_type  := 'G'; -- general
                fp_price_list_code  := a.code;
                fp_price_list_desc  := a.description;
                --price found exit loop
                exit;
              end;
            end loop; --a
          end;
        else
          begin
            for b in (select gwp.price, gwp.startdate, gwp.pricetype, g.code, g.description
                      from   generalwashprice gwp
                      join   generalpricelist g
                      on     g.generalpricelist_id = gwp.generalpricelist_id
                      where  g.generalpricelist_id = fp_generalpricelistid
                      and    g.pricetype = 1 -- Wash
                      and    g.active = 'Y'
                      and    gwp.product_id = fp_productid
                      and    gwp.sizedefinition_id = fp_sizeid
                      and    gwp.finishingmethod_id = fp_finishingmethodid
                      and    gwp.startdate <= lv_pricedate
                      and    gwp.pricetype = lv_pricetype_gen_prlist
                      order  by gwp.startdate desc) loop
              begin
                fp_price_found_yn   := 'Y';
                fp_price            := b.price;
                fp_price_start_date := b.startdate;
                fp_price_list_type  := 'G'; -- general
                fp_price_list_code  := b.code;
                fp_price_list_desc  := b.description;
                --price found exit loop
                exit;
              end;
            end loop; --b
          end;
        end if;
      end get_generalwhprice;
    
      procedure get_customerwhprice(fp_prodlistid in number) is
      begin
        --get_customerwhprice
        for c in (select cupri.price, cupri.startdate, cupri.pricetype
                  from   customerwashprice cupri
                  where  cupri.productlistpercustomer_id = fp_prodlistid
                  and    cupri.startdate <= lv_pricedate
                  and    cupri.pricetype = lv_pricetype
                  order  by cupri.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := c.price;
            fp_price_start_date := c.startdate;
            fp_price_list_type  := 'C'; -- customer specific
            fp_price_list_code  := null;
            fp_price_list_desc  := 'Customer Specific.';
            --price found exit loop
            exit;
          end;
        end loop; --c
      end get_customerwhprice;
    begin
      --lookforprice washprice
      for x in (select plc.generalpricelist_id
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 1 -- Wash
                and    plc.dateactive <= lv_pricedate
                and    plc.dateinactive >= lv_pricedate
                order  by plc.priority) loop
        begin
          if x.generalpricelist_id is not null then
            begin
              --look for size equal
              get_generalwhprice(x.generalpricelist_id, fp_sizedefinitionid);
              if fp_price_found_yn = 'N' then
                begin
                  --look for size star
                  get_generalwhprice(x.generalpricelist_id, lv_sizestarid);
                end;
              end if;
            end;
          else
            begin
              --look for size equal
              get_customerwhprice(lv_plpcid);
              --do NOT look on star level
            end;
          end if;
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --initialize
    initialize;
    --
    if lv_billingmethod = 3 and lv_priceusage = 2 then
      begin
        /* rent price only*/
        fp_result_code := 2; -- Price not relevant, billing method 3 with rent price only
      end;
    elsif lv_billingmethod = 1 and not (lv_chargewashesonlyforcog = 3 and fp_pricetype = 2) then
      begin
        fp_result_code := 3; -- Price not relevant, billing method = 1 flat rated rent only
      end;
    elsif lv_tom = 3 then
      begin
        fp_result_code := 5; -- Price not relevant, disposable or sales only item.
      end;
    elsif lv_billingmethod = 4 and lv_tom <> 3 and lv_chargewashesonlyforcog = 2 /*LOG Only*/
          and fp_pricetype = 2 /*COG Only*/
     then
      begin
        fp_result_code := 6; -- Price not relevant, billing method = 4 with for LOG only
      end;
    elsif lv_billingmethod = 4 and lv_tom <> 3 and lv_chargewashesonlyforcog = 3 /*COG Only*/
          and fp_pricetype = 1 /*LOG Only*/
     then
      begin
        fp_result_code := 7; -- Price not relevant, billing method = 4 with for COG only
      end;
    else
      begin
        if lv_billingmethod = 2 then
          begin
            -- Determine system setting UNDERUSEMETHOD
            select count(1)
            into   lv_underuse_count
            from   systemsetting st
            join   businessunit bu
            on     bu.plant_id = st.plant_id
            where  st.name = 'UNDERUSEMETHOD'
            and    st.value = '2'
            and    bu.businessunit_id = lv_businessunitid;
          end;
        end if;
        -- Only for UNDERUSEMETHOD = 2 the MinimumTurnaround must be > 0
        if lv_billingmethod = 2 and lv_underuse_count > 0 and lv_minimumturnaround = 0 then
          begin
            fp_result_code := 4; -- Price not relevant, billing method = 2 rent based on minimum
          end;
        else
          begin
            lv_pricetype := 1; -- All
            if fp_pricetype = 2 and -- COG
               lv_billingmethod in (3, 4) and lv_chargewashesonlyforcog in (1, 3) and /* separate price for COG/LOG,  or COG only */
               lv_priceusage <> 1 /* split */
             then
              begin
                lv_pricetype := 2; -- COG only
              end;
            end if;
            if fp_pricetype = 0 and -- all
               lv_billingmethod = 4 and lv_chargewashesonlyforcog = 3 then
              begin
                lv_pricetype := 2; -- COG only
              end;
            end if;
            if lv_billingmethod = 1 and lv_chargewashesonlyforcog = 3 and fp_pricetype = 2 then
              begin
                lv_pricetype := 2; -- COG only
              end;
            end if;
            if lv_billingmethod = 3 and lv_priceusage = 1 -- split
             then
              begin
                lv_pricetype_gen_prlist := 4;
              end;
            else
              begin
                lv_pricetype_gen_prlist := lv_pricetype;
              end;
            end if;
            --lookforprice
            lookforprice;
          end;
        end if;
      end;
    end if;
    ----
    if fp_price_found_yn = 'Y' then
      begin
        if fp_pricetype = 0 and lv_chargewashesonlyforcog = 1 -- separate price LOG/COG
         then
          fp_result_code := '1';
        else
          fp_result_code := '0';
        end if;
        fp_result_desc     := decode_error('Y' || to_char(fp_result_code));
        fp_price_type_desc := decode_price_type(fp_price_type_code);
      end;
    else
      begin
        if fp_result_code is null then
          begin
            -- no price found
            fp_result_code := 1;
          end;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_wash_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return varchar2 is
  
    /* See package header for description of return string.   */
  
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  
  begin
    get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           pricetype, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           price_type_code, price_type_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end wash_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      pricetype         in number default 0) return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  
  begin
    get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           pricetype, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           price_type_code, price_type_desc);
    return(nvl(price, 0));
  end wash_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0) return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
  
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  
  begin
    get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           pricetype, price, price_found_yn, price_start_date, result_code,
                           result_desc, price_list_type, price_list_code, price_list_desc,
                           price_type_code, price_type_desc);
    return(price);
  end wash_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_price_details_pt(customerid        in customer.customer_id%type,
                                      productid         in product.product_id%type,
                                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                                      pricedate         in pricelistpercustomer.dateactive%type,
                                      pricetype         in number,
                                      price             out customerwashprice.price%type,
                                      price_found_yn    out varchar2,
                                      price_start_date  out customerwashprice.startdate%type,
                                      result_code       out number,
                                      result_desc       out varchar2,
                                      price_list_type   out varchar2,
                                      price_list_code   out generalpricelist.code%type,
                                      price_list_desc   out generalpricelist.description%type,
                                      price_type_code   out customerwashprice.pricetype%type,
                                      price_type_desc   out varchar2) is
  
  begin
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) or (pricetype is null) or (pricetype = 0) then
      result_code := 8; -- error in parameters
    else
      get_wash_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                             pricetype, price, price_found_yn, price_start_date, result_code,
                             result_desc, price_list_type, price_list_code, price_list_desc,
                             price_type_code, price_type_desc);
    end if;
  end get_wash_price_details_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_details_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return varchar2 is
  
    /* See package header for description of return string.   */
  
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  
  begin
    get_wash_price_details_pt(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                              pricetype, price, price_found_yn, price_start_date, result_code,
                              result_desc, price_list_type, price_list_code, price_list_desc,
                              price_type_code, price_type_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end wash_price_details_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_pt(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         pricedate         in pricelistpercustomer.dateactive%type default null,
                         pricetype         in number) return number is
    /* Returns the wash price for the specified pricetype, if not found, returns 0.  For use in calculations.  */
  
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  
  begin
    get_wash_price_details_pt(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                              pricetype, price, price_found_yn, price_start_date, result_code,
                              result_desc, price_list_type, price_list_code, price_list_desc,
                              price_type_code, price_type_desc);
    return(nvl(price, 0));
  end wash_price_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_price_display_pt(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number) return number is
    /* Returns the wash price for the specified pricetype, if not found, returns null. For display/print purposes. */
  
    price            customerwashprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerwashprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerwashprice.pricetype%type;
    price_type_desc  varchar2(30);
  
  begin
    get_wash_price_details_pt(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                              pricetype, price, price_found_yn, price_start_date, result_code,
                              result_desc, price_list_type, price_list_code, price_list_desc,
                              price_type_code, price_type_desc);
    return(price);
  end wash_price_display_pt;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_replacement_price_details(fp_customerid        in customer.customer_id%type,
                                          fp_productid         in product.product_id%type,
                                          fp_sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                          fp_finishingmethodid in finishingmethod.finishingmethod_id%type,
                                          fp_pricedate         in pricelistpercustomer.dateactive%type,
                                          fp_price             out customerreplacementprice.price%type,
                                          fp_price_found_yn    out varchar2,
                                          fp_price_start_date  out customerreplacementprice.startdate%type,
                                          fp_result_code       out number,
                                          fp_result_desc       out varchar2,
                                          fp_price_list_type   out varchar2,
                                          fp_price_list_code   out generalpricelist.code%type,
                                          fp_price_list_desc   out generalpricelist.description%type) is
    --locale variables
    lv_pricedate                           date;
    lv_plpcid                              number;
    lv_billingmethod                       number;
    lv_inventorybillingtype                number;
    lv_chargelossforpool                   varchar2(1);
    lv_priceusage                          number;
    lv_tom                                 number;
    lv_garmentrentspecification            number;
    lv_sizestarid                          sizedefinition.sizedefinition_id%type;
    lv_standard_sizebillinggroupid         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizebillinggroupid         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizebillinggroupid sizebillinggroup.systemuser_id%type;
    lv_businessunitid                      number;
    lv_chargewashesonlyforcog              productlistpercustomer.chargewashesonlyforcog%type;
    lv_minimumturnaround                   productlistpercustomer.minimumturnaround%type;
    lv_rentpriceperfrequency               productlistpercustomer.rentpriceperfrequency%type;
    lv_invoicefreqrelatedrentprice         productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_splitinvoicesperactivity            customer.splitinvoicesperactivity%type;
    lv_productgroupid                      product.productgroup_id%type;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      lv_message varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, billingmethod is 4 piece rate only', 'N3',
                     'Price not relevant, disposable / sales only item', 'N8', 'Error in parameters',
                     'N9', 'ORA Error', 'Unknown error code')
      into   lv_message
      from   dual;
      return lv_message;
    end decode_error;
  
    procedure initialize is
    begin
      --initialize
      lv_pricedate       := fp_pricedate;
      fp_price_found_yn  := 'N';
      fp_price_list_type := 3;
      lv_sizestarid      := getsizestarid;
      --get_plpc_info
      get_plpc_info(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid,
                    fp_finishingmethodid, lv_pricedate, lv_plpcid, lv_billingmethod,
                    lv_inventorybillingtype, lv_chargelossforpool, lv_priceusage, lv_tom,
                    lv_garmentrentspecification, lv_businessunitid, lv_chargewashesonlyforcog,
                    lv_minimumturnaround, lv_rentpriceperfrequency, lv_invoicefreqrelatedrentprice,
                    lv_splitinvoicesperactivity, lv_productgroupid);
      --
      get_size_billing_groups2(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid, 3,
                               lv_standard_sizebillinggroupid,
                               lv_initial_specific_sizebillinggroupid);
    end initialize;
  
    procedure lookforprice is
      procedure get_generalrpprice(fp_generalpricelistid in number,
                                   fp_pricecoefficient   in number,
                                   fp_sizeid             in number) is
      begin
        --get general replacement price
        for y in (select fp_pricecoefficient * grp.price price, grp.startdate, g.code, g.description
                  from   generalreplacementprice grp
                  join   generalpricelist g
                  on     g.generalpricelist_id = grp.generalpricelist_id
                  where  g.pricetype = 3 -- replacement price
                  and    g.active = 'Y'
                  and    g.generalpricelist_id = fp_generalpricelistid
                  and    grp.product_id = fp_productid
                  and    grp.sizedefinition_id = fp_sizeid
                  and    grp.startdate <= lv_pricedate
                  and    nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by grp.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := y.price;
            fp_price_start_date := y.startdate;
            fp_price_list_type  := 'G'; -- general
            fp_price_list_code  := y.code;
            fp_price_list_desc  := y.description;
            --price found exit loop
            exit;
          end;
        end loop;
      end get_generalrpprice;
    
      procedure get_customerrpprice(fp_sizeid in number) is
      begin
        --get customer replacement price
        for z in (select cupri.price, cupri.startdate
                  from   customerreplacementprice cupri
                  where  cupri.customer_id = fp_customerid
                  and    cupri.product_id = fp_productid
                  and    cupri.sizedefinition_id = fp_sizeid
                  and    cupri.startdate <= lv_pricedate
                  and    nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by cupri.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := z.price;
            fp_price_start_date := z.startdate;
            fp_price_list_type  := 'C'; -- customer specific
            fp_price_list_code  := null;
            fp_price_list_desc  := 'Customer Specific.';
            --price found exit loop
            exit;
          end;
        end loop;
      end get_customerrpprice;
    
      procedure lookpricefor_sgb(fp_generalpricelistid in number, fp_pricecoefficient in number) is
      begin
        if fp_generalpricelistid is not null then
          begin
            --look for size equal
            get_generalrpprice(fp_generalpricelistid, fp_pricecoefficient, fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_generalrpprice(fp_generalpricelistid, fp_pricecoefficient, lv_sizestarid);
              end;
            end if;
          end;
        else
          begin
            --look for size equal
            get_customerrpprice(fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_customerrpprice(lv_sizestarid);
              end;
            end if;
          end;
        end if;
      end lookpricefor_sgb;
    begin
      --lookforprice replacement
      for x in (select plc.generalpricelist_id, plc.pricecoefficient
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 3 -- replacement price
                and    plc.dateactive <= lv_pricedate
                and    plc.dateinactive >= lv_pricedate
                order  by plc.priority) loop
        begin
          lv_specific_sizebillinggroupid := lv_initial_specific_sizebillinggroupid;
          lookpricefor_sgb(x.generalpricelist_id, x.pricecoefficient);
          if fp_price_found_yn = 'N' then
            begin
              --start look for different sizebillinggroup
              if lv_specific_sizebillinggroupid <> lv_standard_sizebillinggroupid then
                begin
                  --standard sizebillinggroup
                  lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
                  lookpricefor_sgb(x.generalpricelist_id, x.pricecoefficient);
                end;
              end if;
              if fp_price_found_yn = 'N' and lv_specific_sizebillinggroupid <> 0 then
                begin
                  --no sizebillinggroup
                  lv_specific_sizebillinggroupid := 0;
                  lookpricefor_sgb(x.generalpricelist_id, x.pricecoefficient);
                end;
              end if;
            end;
          end if; --price found N
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --initialize
    initialize;
    --
    if (lv_billingmethod = 4 and lv_chargelossforpool <> 'Y') then
      begin
        /*piece rate only and no loss charges*/
        fp_result_code := 2; -- Price not relevant, billing method piece rate only
      end;
    elsif lv_tom = 3 then
      begin
        /* disposable / sales only*/
        fp_result_code := 3; -- Price not relevant, disposable or sales only product
      end;
    else
      begin
        --lookforprice, even if no plpc found lookup
        lookforprice;
      end;
    end if;
    if fp_price_found_yn = 'Y' then
      begin
        fp_result_desc     := decode_error('Y0');
        fp_price_list_desc := nvl(fp_price_list_desc, 'Customer Specific.');
      end;
    else
      begin
        -- no price found
        if fp_result_code is null then
          fp_result_code := 1;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error    
      end;
  end get_replacement_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  /*--------------------------------------------------------------------------------------------------------*/
  function replacement_price_details(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price            customerreplacementprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerreplacementprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_replacement_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                  pricedate, price, price_found_yn, price_start_date, result_code,
                                  result_desc, price_list_type, price_list_code, price_list_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end replacement_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function replacement_price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             finishingmethodid in finishingmethod.finishingmethod_id%type,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
    price            customerreplacementprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerreplacementprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_replacement_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                  pricedate, price, price_found_yn, price_start_date, result_code,
                                  result_desc, price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end replacement_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function replacement_price_display(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
    price            customerreplacementprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerreplacementprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_replacement_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                  pricedate, price, price_found_yn, price_start_date, result_code,
                                  result_desc, price_list_type, price_list_code, price_list_desc);
    return(price);
  end replacement_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_sales_price_details(fp_customerid       in customer.customer_id%type,
                                    fp_productid        in product.product_id%type,
                                    fp_sizedefinitionid in sizedefinition.sizedefinition_id%type,
                                    fp_pricedate        in pricelistpercustomer.dateactive%type,
                                    fp_price            out customersalesprice.price%type,
                                    fp_price_found_yn   out varchar2,
                                    fp_price_start_date out customersalesprice.startdate%type,
                                    fp_result_code      out number,
                                    fp_result_desc      out varchar2,
                                    fp_price_list_type  out varchar2,
                                    fp_price_list_code  out generalpricelist.code%type,
                                    fp_price_list_desc  out generalpricelist.description%type) is
    --locale variables
    lv_sizestarid                          sizedefinition.sizedefinition_id%type;
    lv_standard_sizebillinggroupid         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizebillinggroupid         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizebillinggroupid sizebillinggroup.systemuser_id%type;
  
    procedure initialize is
    begin
      --initialize
      fp_price_found_yn  := 'N';
      fp_price_list_type := 4;
      lv_sizestarid      := getsizestarid;
      --
      get_size_billing_groups2(fp_customerid, fp_productid, fp_sizedefinitionid, lv_sizestarid, 3,
                               lv_standard_sizebillinggroupid,
                               lv_initial_specific_sizebillinggroupid);
    end initialize;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end decode_error;
  
    procedure lookforprice is
      procedure get_generalsalesprice(fp_generalpricelistid in number, fp_sizeid in number) is
      begin
        --get general sales price
        for y in (select gsp.price price, gsp.startdate, g.code, g.description
                  from   generalsalesprice gsp
                  join   generalpricelist g
                  on     g.generalpricelist_id = gsp.generalpricelist_id
                  where  g.pricetype = 4 -- sales price
                  and    g.active = 'Y'
                  and    g.generalpricelist_id = fp_generalpricelistid
                  and    gsp.product_id = fp_productid
                  and    gsp.sizedefinition_id = fp_sizeid
                  and    gsp.startdate <= fp_pricedate
                  and    nvl(gsp.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by gsp.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := y.price;
            fp_price_start_date := y.startdate;
            fp_price_list_type  := 'G'; -- general
            fp_price_list_code  := y.code;
            fp_price_list_desc  := y.description;
            --price found exit loop
            exit;
          end;
        end loop;
      end get_generalsalesprice;
    
      procedure get_customersalesprice(fp_sizeid in number) is
      begin
        --get customer sales price
        for z in (select cusal.price, cusal.startdate
                  from   customersalesprice cusal
                  where  cusal.customer_id = fp_customerid
                  and    cusal.product_id = fp_productid
                  and    cusal.sizedefinition_id = fp_sizeid
                  and    cusal.startdate <= fp_pricedate
                  and    nvl(cusal.sizebillinggroup_id, 0) = lv_specific_sizebillinggroupid
                  order  by cusal.startdate desc) loop
          begin
            fp_price_found_yn   := 'Y';
            fp_price            := z.price;
            fp_price_start_date := z.startdate;
            fp_price_list_type  := 'C'; -- customer specific
            fp_price_list_code  := null;
            fp_price_list_desc  := 'Customer Specific.';
            --price found exit loop
            exit;
          end;
        end loop;
      end get_customersalesprice;
    
      procedure lookpricefor_sgb(fp_generalpricelistid in number) is
      begin
        if fp_generalpricelistid is not null then
          begin
            --look for size equal
            get_generalsalesprice(fp_generalpricelistid, fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_generalsalesprice(fp_generalpricelistid, lv_sizestarid);
              end;
            end if;
          end;
        else
          begin
            --look for size equal
            get_customersalesprice(fp_sizedefinitionid);
            if fp_price_found_yn = 'N' then
              begin
                --look for size star
                get_customersalesprice(lv_sizestarid);
              end;
            end if;
          end;
        end if;
      end lookpricefor_sgb;
    begin
      --lookforprice sales
      for x in (select plc.generalpricelist_id
                from   pricelistpercustomer plc
                where  plc.customer_id = fp_customerid
                and    plc.pricetype = 4 -- sales price
                and    plc.dateactive <= fp_pricedate
                and    plc.dateinactive >= fp_pricedate
                order  by plc.priority) loop
        begin
          lv_specific_sizebillinggroupid := lv_initial_specific_sizebillinggroupid;
          lookpricefor_sgb(x.generalpricelist_id);
          if fp_price_found_yn = 'N' then
            begin
              --start look for different sizebillinggroup
              if lv_specific_sizebillinggroupid <> lv_standard_sizebillinggroupid then
                begin
                  --standard sizebillinggroup
                  lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
              if fp_price_found_yn = 'N' and lv_specific_sizebillinggroupid <> 0 then
                begin
                  --no sizebillinggroup
                  lv_specific_sizebillinggroupid := 0;
                  lookpricefor_sgb(x.generalpricelist_id);
                end;
              end if;
            end;
          end if; --price found N
          if fp_price_found_yn = 'Y' then
            exit;
          end if;
        end;
      end loop; --x
    end lookforprice;
  begin
    --main sales
    --initialize
    initialize;
    --lookforprice
    lookforprice;
    if fp_price_found_yn = 'Y' then
      begin
        fp_result_desc     := decode_error('Y0');
        fp_price_list_desc := nvl(fp_price_list_desc, 'Customer Specific.');
      end;
    else
      begin
        -- no price found
        if fp_result_code is null then
          fp_result_code := 1;
        end if;
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    end if;
  exception
    when no_data_found then
      begin
        fp_result_code := 1; -- no price found (often because fin method * not defined)
        fp_result_desc := decode_error('N' || fp_result_code);
      end;
    when others then
      begin
        fp_result_code := 9;
        fp_result_desc := decode_error('N' || fp_result_code) || sqlerrm; -- ora error
      end;
  end get_sales_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function sales_price_details(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price            customersalesprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customersalesprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_sales_price_details(customerid, productid, sizedefinitionid, pricedate, price,
                            price_found_yn, price_start_date, result_code, result_desc,
                            price_list_type, price_list_code, price_list_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end sales_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function sales_price(customerid       in customer.customer_id%type,
                       productid        in product.product_id%type,
                       sizedefinitionid in sizedefinition.sizedefinition_id%type,
                       pricedate        in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price            customersalesprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customersalesprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_sales_price_details(customerid, productid, sizedefinitionid, pricedate, price,
                            price_found_yn, price_start_date, result_code, result_desc,
                            price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end sales_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function sales_price_display(customerid       in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
  
    price            customersalesprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customersalesprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_sales_price_details(customerid, productid, sizedefinitionid, pricedate, price,
                            price_found_yn, price_start_date, result_code, result_desc,
                            price_list_type, price_list_code, price_list_desc);
    return(price);
  end sales_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_price_details(customerid         in customer.customer_id%type,
                                     weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                     soil_yn            in customerweightprice.soil%type,
                                     pricedate          in pricelistpercustomer.dateactive%type,
                                     price              out customerweightprice.price%type,
                                     price_found_yn     out varchar2,
                                     price_start_date   out customerweightprice.startdate%type,
                                     result_code        out number,
                                     result_desc        out varchar2,
                                     price_list_type    out varchar2,
                                     price_list_code    out generalpricelist.code%type,
                                     price_list_desc    out generalpricelist.description%type) is
  
    price_found                 boolean;
    price_not_relevant          boolean;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_pricelist_type           varchar2(1);
    lv_price                    customerweightprice.price%type;
    lv_price_start_date         customerweightprice.startdate%type;
    lv_generalpricelistid       generalweightprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    lv_weighingcatpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    lv_invoice_method           weighingcategpercustomer.invoicemethod%type;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, weights not invoiced', 'N3',
                     'Price not defined, weights invoiced soil, not clean ', 'N4',
                     'Price not defined, weights invoiced clean, not soil ', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
  begin
    -- main Weight
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found        := false;
    price_not_relevant := false;
    price              := null;
    price_found_yn     := 'N';
    price_start_date   := null;
    result_code        := null;
    result_desc        := null;
    price_list_type    := null;
    price_list_code    := null;
    price_list_desc    := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    if (customerid is null) or (weighingcategoryid is null) or (soil_yn not in ('Y', 'N')) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not price_found) and (not price_not_relevant) loop
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 5 -- this means weight price
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid;
      -- load weighingcategpercustomer etc to determine price usage
      lv_weighingcatpercustomerid := null;
      lv_invoice_method           := null;
      open vcsr for
        select wcpc.weighingcategpercustomer_id, wcpc.invoicemethod
        from   weighingcategpercustomer wcpc
        where  wcpc.customer_id = customerid
        and    wcpc.weighingcategory_id = weighingcategoryid
        and    ((lv_pricedate >= wcpc.dateactive and lv_pricedate <= wcpc.dateinactive) or i > 1)
        order  by wcpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_weighingcatpercustomerid, lv_invoice_method;
        if lv_invoice_method = 1 then
          /* no invoicing based on weight */
          price_not_relevant := true;
          result_code        := 2; -- Price not relevant, customer is not invoiced based on weight
        end if;
        if lv_invoice_method in (2, 4) and soil_yn = 'N' then
          /* configured soil, requested clean */
          price_not_relevant := true;
          result_code        := 3; -- Price not relevant, customer is invoiced based on soil weight
        end if;
        if lv_invoice_method = 3 and soil_yn = 'Y' then
          /* configured clean, requested soil */
          price_not_relevant := true;
          result_code        := 4; -- Price not relevant, customer is invoiced based on clean weight
        end if;
      end if;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) and (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gwp.price, gwp.startdate, g.code, g.description
                       from   generalweightprice gwp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 5 -- weight price
                       and    g.active = 'Y'
                       and    gwp.generalpricelist_id = g.generalpricelist_id
                       and    gwp.weighingcategory_id = weighingcategoryid
                       and    gwp.soil = soil_yn
                       and    gwp.startdate <= lv_pricedate
                       order  by gwp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.price, cupri.startdate
                       from   customerweightprice cupri
                       where  cupri.weighingcategpercustomer_id = lv_weighingcatpercustomerid
                       and    cupri.soil = soil_yn
                       and    cupri.startdate <= lv_pricedate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:  1 = try to find for active weighingcategorypercustomer
        2 = try to find for any weighingcategorypercustomer */
        i := i + 1;
        if lv_weighingcatpercustomerid is not null then
          -- active wcpc already found, so do not perform extra loop
          i := i + 1;
        end if;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G' then
        price_list_desc := lv_pricelist_desc;
      else
        price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_weight_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_price_details(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price            customerweightprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerweightprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_weight_price_details(customerid, weighingcategoryid, soil_yn, pricedate, price,
                             price_found_yn, price_start_date, result_code, result_desc,
                             price_list_type, price_list_code, price_list_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end weight_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_price(customerid         in customer.customer_id%type,
                        weighingcategoryid in weighingcategory.weighingcategory_id%type,
                        soil_yn            in customerweightprice.soil%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price            customerweightprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerweightprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_weight_price_details(customerid, weighingcategoryid, soil_yn, pricedate, price,
                             price_found_yn, price_start_date, result_code, result_desc,
                             price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end weight_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_price_display(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
  
    price            customerweightprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerweightprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_weight_price_details(customerid, weighingcategoryid, soil_yn, pricedate, price,
                             price_found_yn, price_start_date, result_code, result_desc,
                             price_list_type, price_list_code, price_list_desc);
    return(price);
  end weight_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_speccharge_details(customerid        in customer.customer_id%type,
                                   specialchargeid   in specialcharge.specialcharge_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerspecialchargeprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerspecialchargeprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type,
                                   specialchargecode out specialcharge.code%type,
                                   percentage        out customerspecialchargeprice.percentage%type,
                                   minimumamount     out specialcharge.minimumamount%type,
                                   maximumamount     out specialcharge.maximumamount%type) is
  
    price_found           boolean;
    dummy                 number;
    lv_fixedamount_yn     specialcharge.fixedamount%type;
    lv_fixedamount_str    varchar2(10);
    lv_pricedate          date;
    lv_pricelist_type     varchar2(1);
    lv_price              customerspecialchargeprice.price%type;
    lv_price_start_date   customerspecialchargeprice.startdate%type;
    lv_generalpricelistid generalpricelist.generalpricelist_id%type;
    lv_pricelist_code     generalpricelist.code%type;
    lv_pricelist_desc     generalpricelist.description%type;
    lv_percentage         customerspecialchargeprice.percentage%type;
    lv_minimumamount      customerspecialchargeprice.minimumamount%type;
    lv_maximumamount      customerspecialchargeprice.maximumamount%type;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;
  
    function decode_error(errorcode in varchar2, type_str in varchar2 default null) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', type_str || ' found', 'N1', type_str || ' not defined', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
  begin
    -- main SpecialCharge
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found       := false;
    price             := null;
    price_found_yn    := 'N';
    price_start_date  := null;
    result_code       := null;
    result_desc       := null;
    price_list_type   := null;
    price_list_code   := null;
    price_list_desc   := null;
    lv_fixedamount_yn := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    select c.fixedamount, decode(c.fixedamount, 'Y', 'Price', 'Percentage')
    into   lv_fixedamount_yn, lv_fixedamount_str
    from   specialcharge c
    where  c.specialcharge_id = specialchargeid;
    if ((customerid is null) or (specialchargeid is null) or (lv_fixedamount_yn is null)) then
      result_code := 8; -- error in parameters
    end if;
    if result_code is null then
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 10 -- this means special charge price
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid;
      -- start loop on pricelistpercustomer
      /* --------------------- L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_percentage       := null;
            lv_minimumamount    := null;
            lv_maximumamount    := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gscp.price, gscp.startdate, g.code, g.description, gscp.percentage,
                              gscp.minimumamount, gscp.maximumamount
                       from   generalspecialchargeprice gscp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 10 -- special charge price
                       and    g.active = 'Y'
                       and    gscp.generalpricelist_id = g.generalpricelist_id
                       and    gscp.specialcharge_id = specialchargeid
                       and    gscp.startdate <= lv_pricedate
                       order  by gscp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc,
                   lv_percentage, lv_minimumamount, lv_maximumamount, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_percentage       := null;
            lv_minimumamount    := null;
            lv_maximumamount    := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.price, cupri.startdate, cupri.percentage, cupri.minimumamount,
                              cupri.maximumamount
                       from   customerspecialchargeprice cupri
                       where  cupri.specialcharge_id = specialchargeid
                       and    cupri.customer_id = customerid
                       and    cupri.startdate <= lv_pricedate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_percentage, lv_minimumamount, lv_maximumamount,
                   dummy;
            close vcsr;
            if ((lv_price is not null) or (lv_percentage is not null)) then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   L O O P ----------------------------------------------------------*/
      -- if no price found then take from special charge base table
      if (not price_found) then
        open vcsr for
          select x.*, rownum
          from   (select sc.newamount, sc.startdate, sc.newpercentage, sc.minimumamount,
                          sc.maximumamount
                   from   specialcharge sc
                   where  sc.specialcharge_id = specialchargeid
                   order  by sc.startdate desc) x
          where  rownum = 1; -- take first
        fetch vcsr
          into lv_price, lv_price_start_date, lv_percentage, lv_minimumamount, lv_maximumamount,
               dummy;
        close vcsr;
        if ((lv_price is not null) or (lv_percentage is not null)) then
          price_found       := true;
          lv_pricelist_type := 'B'; -- base table
        end if;
      end if;
    end if; -- result_code is null
    if price_found then
      if lv_fixedamount_yn = 'Y' then
        price      := lv_price;
        percentage := null;
      else
        price      := null;
        percentage := lv_percentage;
      end if; -- lv_fixedamount_yn ='Y'
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := '0';
      select s.code
      into   specialchargecode
      from   specialcharge s
      where  s.specialcharge_id = specialchargeid;
      result_desc     := decode_error('Y' || to_char(result_code), lv_fixedamount_str);
      price_list_type := lv_pricelist_type;
      price_list_code := lv_pricelist_code;
      minimumamount   := lv_minimumamount;
      maximumamount   := lv_maximumamount;
      case lv_pricelist_type
        when 'G' then
          price_list_desc := lv_pricelist_desc;
        when 'B' then
          price_list_desc := 'Base ' || lv_fixedamount_str;
        else
          price_list_desc := 'Customer Specific.';
      end case;
    else
      if result_code is null then
        -- no price/percentage found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code, lv_fixedamount_str);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price/percentage found
      result_desc := decode_error('N' || result_code, lv_fixedamount_str);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_speccharge_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_details(customerid      in customer.customer_id%type,
                                 specialchargeid in specialcharge.specialcharge_id%type,
                                 pricedate       in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(specialchargecode, ' '), 6) ||
           rpad(nvl(to_char(result_code), ' '), 1) || rpad(nvl(result_desc, ' '), 80) ||
           rpad(nvl(to_char(percentage, '999D99'), ' '), 7) ||
           rpad(nvl(to_char(minimumamount, '999999D99'), ' '), 10) ||
           rpad(nvl(to_char(maximumamount, '999999D99'), ' '), 10) ||
           rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end specialcharge_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_price(customerid      in customer.customer_id%type,
                               specialchargeid in specialcharge.specialcharge_id%type,
                               pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(price, 0));
  end specialcharge_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_price_display(customerid      in customer.customer_id%type,
                                       specialchargeid in specialcharge.specialcharge_id%type,
                                       pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(price);
  end specialcharge_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_percentage(customerid      in customer.customer_id%type,
                                    specialchargeid in specialcharge.specialcharge_id%type,
                                    pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the percentage, if not found, returns 0.  For use in calculations.  */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(percentage, 0));
  end specialcharge_percentage;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_percentage_disp(customerid      in customer.customer_id%type,
                                         specialchargeid in specialcharge.specialcharge_id%type,
                                         pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the percentage, if not found, returns null.  For display/print purposes. */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(percentage);
  end specialcharge_percentage_disp;
  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_minamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the MinAmount, if not found, returns 0.  For use in calculations.  */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(minimumamount, 0));
  end specialcharge_minamount;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_minamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the MinAmount, if not found, returns null.  For display/print purposes. */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(minimumamount);
  end specialcharge_minamount_disp;
  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_maxamount(customerid      in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the MaxAmount, if not found, returns 0.  For use in calculations.  */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(nvl(maximumamount, 0));
  end specialcharge_maxamount;

  /*--------------------------------------------------------------------------------------------------------*/
  function specialcharge_maxamount_disp(customerid      in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the MaxAmount, if not found, returns null.  For display/print purposes. */
  
    price             customerspecialchargeprice.price%type;
    price_found_yn    varchar2(1);
    price_start_date  customerspecialchargeprice.startdate%type;
    result_code       number;
    result_desc       varchar2(80);
    price_list_type   varchar2(1);
    price_list_code   generalpricelist.code%type;
    price_list_desc   generalpricelist.description%type;
    specialchargecode specialcharge.code%type;
    percentage        customerspecialchargeprice.percentage%type;
    minimumamount     specialcharge.minimumamount%type;
    maximumamount     specialcharge.maximumamount%type;
  
  begin
    get_speccharge_details(customerid, specialchargeid, pricedate, price, price_found_yn,
                           price_start_date, result_code, result_desc, price_list_type,
                           price_list_code, price_list_desc, specialchargecode, percentage,
                           minimumamount, maximumamount);
    return(maximumamount);
  end specialcharge_maxamount_disp;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_rent_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerrentdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerrentdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type) is
  
    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerrentdiscount.discount%type;
    lv_discount_start_date      customerrentdiscount.startdate%type;
    lv_generaldiscountlistid    generalrentdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_customergarmrentspec     customer.garmentrentspecification%type;
    lv_size                     sizedefinition.sizedefinition_id%type;
    type tcsr is ref cursor;
    vcsr                 tcsr;
    vdiscountlistpercust tcsr;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Discount found', 'N1', 'Discount not defined', 'N2',
                     'Discount not relevant, billing method 3 with wash price only', 'N3',
                     'Discount not relevant, billing method = 4 piece rate only', 'N4',
                     'Discount not applicable, price defined at wearer level as wearer total price',
                     'N5', 'Discount not applicable, price defined at wearer function level', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
  begin
    -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found        := false;
    discount_not_relevant := false;
    discount              := null;
    discount_found_yn     := 'N';
    discount_start_date   := null;
    result_code           := null;
    result_desc           := null;
    discount_list_type    := null;
    discount_list_code    := null;
    discount_list_desc    := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    lv_size := sizedefinitionid;
    i       := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open vdiscountlistpercust for
        select discountlistpercustomer.generaldiscountlist_id
        from   discountlistpercustomer
        where  discountlistpercustomer.customer_id = customerid
        and    discountlistpercustomer.pricetype = 2 -- this means rent discount
        and    discountlistpercustomer.dateactive <= lv_discountdate
        and    discountlistpercustomer.dateinactive >= lv_discountdate
        order  by discountlistpercustomer.priority;
      fetch vdiscountlistpercust
        into lv_generaldiscountlistid;
      -- load weighingcategpercustomer etc to determine discount usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_typeofmerchandize        := null;
      lv_priceusage               := null;
      lv_customergarmrentspec     := null;
      open vcsr for
        select plpc.productlistpercustomer_id, plpc.billingmethod, plpc.priceusage,
               p.typeofmerchandise, c.garmentrentspecification
        from   productlistpercustomer plpc, product p, customer c
        where  plpc.customer_id = customerid
        and    plpc.product_id = productid
        and    plpc.sizedefinition_id = lv_size
        and    plpc.finishingmethod_id = finishingmethodid
        and    p.product_id = plpc.product_id
        and    c.customer_id = plpc.customer_id
        and    ((lv_discountdate >= plpc.dateactive and lv_discountdate <= plpc.dateinactive) or
              i > 1)
        order  by plpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_typeofmerchandize,
               lv_customergarmrentspec;
        if lv_billingmethod = 3 and lv_priceusage = 3 then
          /*wash only*/
          discount_not_relevant := true;
          result_code           := 2; -- Price not relevant, billing method 3 with wash price only
        end if;
        if lv_billingmethod = 4 then
          discount_not_relevant := true;
          result_code           := 3; -- Price not relevant, billing method = 4 piece rate only
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize = 2 and lv_customergarmrentspec = 5 then
          -- total wearer price
          discount_not_relevant := true;
          result_code           := 4; -- Price not relevant, wearer total price
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize = 2 and lv_customergarmrentspec = 6 then
          -- wearer function price
          discount_not_relevant := true;
          result_code           := 5; -- Price not relevant, wearer function price
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vdiscountlistpercust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select grp.discount, grp.startdate, g.code, g.description
                       from   generalrentdiscount grp, generaldiscountlist g
                       where  g.generaldiscountlist_id = lv_generaldiscountlistid
                       and    g.pricetype = 2 -- rent discount
                       and    g.active = 'Y'
                       and    grp.generaldiscountlist_id = g.generaldiscountlist_id
                       and    grp.product_id = productid
                       and    grp.sizedefinition_id = lv_size
                       and    grp.finishingmethod_id = finishingmethodid
                       and    grp.startdate <= lv_discountdate
                       order  by grp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc,
                   dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.discount, cupri.startdate
                       from   customerrentdiscount cupri
                       where  cupri.productlistpercustomer_id = lv_productlistpercustomerid
                       and    cupri.startdate <= lv_discountdate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch vdiscountlistpercust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when activ plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code         := '0';
      result_desc         := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G' then
        discount_list_desc := lv_discountlist_desc;
      else
        discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_rent_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_rent_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) || discount_found_yn ||
           rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(discount_list_type, ' '), 1) || rpad(nvl(discount_list_code, ' '), 6) ||
           rpad(nvl(discount_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80));
  end rent_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    /* Returns the discount, if not found, returns 0.  For use in calculations.  */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_rent_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(nvl(discount, 0));
  end rent_discount;

  /*--------------------------------------------------------------------------------------------------------*/
  function rent_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    /* Returns the discount, if not found, returns null.  For display/print purposes. */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_rent_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(discount);
  end rent_discount_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_wash_discount_details(customerid          in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate        in discountlistpercustomer.dateactive%type,
                                      discount            out customerwashdiscount.discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerwashdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type) is
  
    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerwashdiscount.discount%type;
    lv_discount_start_date      customerwashdiscount.startdate%type;
    lv_generaldiscountlistid    generalwashdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_size                     sizedefinition.sizedefinition_id%type;
    type tcsr is ref cursor;
    vcsr                 tcsr;
    vdiscountlistpercust tcsr;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Discount found', 'N1', 'Discount not defined', 'N2',
                     'Discount not relevant, billing method 3 with rent price only', 'N3',
                     'Discount not relevant, billing method = 1 flat rated rent', 'N4',
                     'Discount not relevant, billing method = 2 rent based on minimum', 'N5',
                     'Discount not relevant, disposable / sales only item', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
  begin
    -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found        := false;
    discount_not_relevant := false;
    discount              := null;
    discount_found_yn     := 'N';
    discount_start_date   := null;
    result_code           := null;
    result_desc           := null;
    discount_list_type    := null;
    discount_list_code    := null;
    discount_list_desc    := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    lv_size := sizedefinitionid;
    i       := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open vdiscountlistpercust for
        select discountlistpercustomer.generaldiscountlist_id
        from   discountlistpercustomer
        where  discountlistpercustomer.customer_id = customerid
        and    discountlistpercustomer.pricetype = 1 -- this means wash discount
        and    discountlistpercustomer.dateactive <= lv_discountdate
        and    discountlistpercustomer.dateinactive >= lv_discountdate
        order  by discountlistpercustomer.priority;
      fetch vdiscountlistpercust
        into lv_generaldiscountlistid;
      -- load weighingcategpercustomer etc to determine discount usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_typeofmerchandize        := null;
      lv_priceusage               := null;
      open vcsr for
        select plpc.productlistpercustomer_id, plpc.billingmethod, plpc.priceusage,
               p.typeofmerchandise
        from   productlistpercustomer plpc, product p
        where  plpc.customer_id = customerid
        and    plpc.product_id = productid
        and    plpc.sizedefinition_id = lv_size
        and    plpc.finishingmethod_id = finishingmethodid
        and    p.product_id = plpc.product_id
        and    ((lv_discountdate >= plpc.dateactive and lv_discountdate <= plpc.dateinactive) or
              i > 1)
        order  by plpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_typeofmerchandize;
        if lv_billingmethod = 3 and lv_priceusage = 2 then
          /* rent price only*/
          discount_not_relevant := true;
          result_code           := 2; -- Price not relevant, billing method 3 with rent price only
        end if;
        if lv_billingmethod = 1 /*and pricetype<>2*/
         then
          discount_not_relevant := true;
          result_code           := 3; -- Price not relevant, billing method = 1 flat rated rent only
        end if;
        if lv_billingmethod = 2 then
          discount_not_relevant := true;
          result_code           := 4; -- Price not relevant, billing method = 2 rent based on minimum
        end if;
        if lv_typeofmerchandize = 3 then
          discount_not_relevant := true;
          result_code           := 5; -- Price not relevant, disposable or sales only item.
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vdiscountlistpercust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gwp.discount, gwp.startdate, g.code, g.description
                       from   generalwashdiscount gwp, generaldiscountlist g
                       where  g.generaldiscountlist_id = lv_generaldiscountlistid
                       and    g.pricetype = 1 -- wash discount
                       and    g.active = 'Y'
                       and    gwp.generaldiscountlist_id = g.generaldiscountlist_id
                       and    gwp.product_id = productid
                       and    gwp.sizedefinition_id = lv_size
                       and    gwp.finishingmethod_id = finishingmethodid
                       and    gwp.startdate <= lv_discountdate
                       order  by gwp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc,
                   dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.discount, cupri.startdate
                       from   customerwashdiscount cupri
                       where  cupri.productlistpercustomer_id = lv_productlistpercustomerid
                       and    cupri.startdate <= lv_discountdate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch vdiscountlistpercust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when activ plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code         := '0';
      result_desc         := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G' then
        discount_list_desc := lv_discountlist_desc;
      else
        discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_wash_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_discount_details(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_wash_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) || discount_found_yn ||
           rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(discount_list_type, ' '), 1) || rpad(nvl(discount_list_code, ' '), 6) ||
           rpad(nvl(discount_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80));
  end wash_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_discount(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    /* Returns the discount, if not found, returns 0.  For use in calculations.  */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_wash_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(nvl(discount, 0));
  end wash_discount;

  /*--------------------------------------------------------------------------------------------------------*/
  function wash_discount_display(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number is
    /* Returns the discount, if not found, returns null.  For display/print purposes. */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_wash_discount_details(customerid, productid, sizedefinitionid, finishingmethodid,
                              discountdate, discount, discount_found_yn, discount_start_date,
                              result_code, result_desc, discount_list_type, discount_list_code,
                              discount_list_desc);
    return(discount);
  end wash_discount_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_weight_discount_details(customerid          in customer.customer_id%type,
                                        weighingcategoryid  in weighingcategory.weighingcategory_id%type,
                                        soil_yn             in customerweightdiscount.soil%type,
                                        discountdate        in discountlistpercustomer.dateactive%type,
                                        discount            out customerweightdiscount.discount%type,
                                        discount_found_yn   out varchar2,
                                        discount_start_date out customerweightdiscount.startdate%type,
                                        result_code         out number,
                                        result_desc         out varchar2,
                                        discount_list_type  out varchar2,
                                        discount_list_code  out generaldiscountlist.code%type,
                                        discount_list_desc  out generaldiscountlist.description%type) is
  
    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerweightdiscount.discount%type;
    lv_discount_start_date      customerweightdiscount.startdate%type;
    lv_generaldiscountlistid    generalwashdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_weighingcatpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    lv_invoice_method           weighingcategpercustomer.invoicemethod%type;
    type tcsr is ref cursor;
    vcsr                 tcsr;
    vdiscountlistpercust tcsr;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Discount found', 'N1', 'Discount not defined', 'N2',
                     'Discount not relevant, weights not invoiced', 'N3',
                     'Discount not defined, weights invoiced soil, not clean ', 'N4',
                     'Discount not defined, weights invoiced clean, not soil ', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
  begin
    -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found        := false;
    discount_not_relevant := false;
    discount              := null;
    discount_found_yn     := 'N';
    discount_start_date   := null;
    result_code           := null;
    result_desc           := null;
    discount_list_type    := null;
    discount_list_code    := null;
    discount_list_desc    := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) or (weighingcategoryid is null) or (soil_yn not in ('Y', 'N')) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open vdiscountlistpercust for
        select discountlistpercustomer.generaldiscountlist_id
        from   discountlistpercustomer
        where  discountlistpercustomer.customer_id = customerid
        and    discountlistpercustomer.pricetype = 5 -- this means weight discount
        and    discountlistpercustomer.dateactive <= lv_discountdate
        and    discountlistpercustomer.dateinactive >= lv_discountdate
        order  by discountlistpercustomer.priority;
      fetch vdiscountlistpercust
        into lv_generaldiscountlistid;
      -- load weighingcategpercustomer etc to determine discount usage
      lv_weighingcatpercustomerid := null;
      lv_invoice_method           := null;
      open vcsr for
        select wcpc.weighingcategpercustomer_id, wcpc.invoicemethod
        from   weighingcategpercustomer wcpc
        where  wcpc.customer_id = customerid
        and    wcpc.weighingcategory_id = weighingcategoryid
        and    ((lv_discountdate >= wcpc.dateactive and lv_discountdate <= wcpc.dateinactive) or
              i > 1)
        order  by wcpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_weighingcatpercustomerid, lv_invoice_method;
        if lv_invoice_method = 1 then
          /* no invoicing based on weight */
          discount_not_relevant := true;
          result_code           := 2; -- discount not relevant, customer is not invoiced based on weight
        end if;
        if lv_invoice_method in (2, 4) and soil_yn = 'N' then
          /* configured soil, requested clean */
          discount_not_relevant := true;
          result_code           := 3; -- discount not relevant, customer is invoiced based on soil weight
        end if;
        if lv_invoice_method = 3 and soil_yn = 'Y' then
          /* configured clean, requested soil */
          discount_not_relevant := true;
          result_code           := 4; -- discount not relevant, customer is invoiced based on clean weight
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vdiscountlistpercust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select gwp.discount, gwp.startdate, g.code, g.description
                       from   generalweightdiscount gwp, generaldiscountlist g
                       where  g.generaldiscountlist_id = lv_generaldiscountlistid
                       and    g.pricetype = 5 -- weight discount
                       and    g.active = 'Y'
                       and    gwp.generaldiscountlist_id = g.generaldiscountlist_id
                       and    gwp.weighingcategory_id = weighingcategoryid
                       and    gwp.soil = soil_yn
                       and    gwp.startdate <= lv_discountdate
                       order  by gwp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc,
                   dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.discount, cupri.startdate
                       from   customerweightdiscount cupri
                       where  cupri.weighingcategpercustomer_id = lv_weighingcatpercustomerid
                       and    cupri.soil = soil_yn
                       and    cupri.startdate <= lv_discountdate
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch vdiscountlistpercust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:  1 = try to find for active weighingcategorypercustomer
        2 = try to find for any weighingcategorypercustomer */
        i := i + 1;
        if lv_weighingcatpercustomerid is not null then
          -- active wcpc already found, so do not perform extra loop
          i := i + 1;
        end if;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code         := '0';
      result_desc         := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G' then
        discount_list_desc := lv_discountlist_desc;
      else
        discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_weight_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_discount_details(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_weight_discount_details(customerid, weighingcategoryid, soil_yn, discountdate, discount,
                                discount_found_yn, discount_start_date, result_code, result_desc,
                                discount_list_type, discount_list_code, discount_list_desc);
    return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) || discount_found_yn ||
           rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(discount_list_type, ' '), 1) || rpad(nvl(discount_list_code, ' '), 6) ||
           rpad(nvl(discount_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80));
  end weight_discount_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_discount(customerid         in customer.customer_id%type,
                           weighingcategoryid in weighingcategory.weighingcategory_id%type,
                           soil_yn            in customerweightdiscount.soil%type,
                           discountdate       in discountlistpercustomer.dateactive%type default null)
    return number is
    /* Returns the discount, if not found, returns 0.  For use in calculations.  */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_weight_discount_details(customerid, weighingcategoryid, soil_yn, discountdate, discount,
                                discount_found_yn, discount_start_date, result_code, result_desc,
                                discount_list_type, discount_list_code, discount_list_desc);
    return(nvl(discount, 0));
  end weight_discount;

  /*--------------------------------------------------------------------------------------------------------*/
  function weight_discount_display(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return number is
    /* Returns the discount, if not found, returns null.  For display/print purposes. */
  
    discount            customerweightdiscount.discount%type;
    discount_found_yn   varchar2(1);
    discount_start_date customerweightdiscount.startdate%type;
    result_code         number;
    result_desc         varchar2(80);
    discount_list_type  varchar2(1);
    discount_list_code  generaldiscountlist.code%type;
    discount_list_desc  generaldiscountlist.description%type;
  
  begin
    get_weight_discount_details(customerid, weighingcategoryid, soil_yn, discountdate, discount,
                                discount_found_yn, discount_start_date, result_code, result_desc,
                                discount_list_type, discount_list_code, discount_list_desc);
    return(discount);
  end weight_discount_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_residrent_price_details(customerid        in customer.customer_id%type,
                                        productid         in product.product_id%type,
                                        sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                        finishingmethodid in finishingmethod.finishingmethod_id%type,
                                        pricedate         in pricelistpercustomer.dateactive%type,
                                        price             out customerrentprice.price%type,
                                        price_found_yn    out varchar2,
                                        price_start_date  out customerrentprice.startdate%type,
                                        result_code       out number,
                                        result_desc       out varchar2,
                                        price_list_type   out varchar2,
                                        price_list_code   out generalpricelist.code%type,
                                        price_list_desc   out generalpricelist.description%type,
                                        price_type_code   out customerrentprice.typeofrent%type,
                                        price_type_desc   out varchar2) is
  
    price_found                boolean;
    price_not_relevant         boolean;
    lv_size                    sizedefinition.sizedefinition_id%type;
    lv_finmethod               finishingmethod.finishingmethod_id%type;
    i                          number;
    dummy                      number;
    lv_pricedate               date;
    lv_residentialrentid       residentialrent.residentialrent_id%type;
    lv_customergarmrentspec    customer.garmentrentspecification%type;
    lv_pricelist_type          varchar2(1);
    lv_custsplitinvperactivity customer.splitinvoicesperactivity%type;
    lv_typeofmerchandize       product.typeofmerchandise%type;
    lv_typeofrent              generalrentprice.typeofrent%type;
    lv_typeofrent_general      generalrentprice.typeofrent%type;
    lv_typeofrent_specific     generalrentprice.typeofrent%type;
    lv_productgroup_id         product.productgroup_id%type;
    lv_price                   customerresidentialrentprice.price%type;
    lv_price_start_date        customerresidentialrentprice.startdate%type;
    lv_generalpricelistid      generalrentprice.generalpricelist_id%type;
    lv_pricelist_code          generalpricelist.code%type;
    lv_pricelist_desc          generalpricelist.description%type;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N2',
                     'Price not relevant, billing method 3 with wash price only', 'N3',
                     'Price not relevant, billing method = 4 piece rate only', 'N4',
                     'Price not relevant, defined at wearer level as wearer total price', 'N5',
                     'Price not relevant, defined at wearer function level', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
    function decode_type_of_rent(fptypeofrent in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fptypeofrent, 9, 'Residential Rent', 'Unknown type of rent') into r from dual;
      return r;
    end;
  
  begin
    -- main rent price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found        := false;
    price_not_relevant := false;
    price              := null;
    price_found_yn     := 'N';
    price_start_date   := null;
    result_code        := null;
    result_desc        := null;
    price_list_type    := null;
    price_list_code    := null;
    price_list_desc    := null;
    price_type_code    := null;
    price_type_desc    := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size      := sizedefinitionid;
    lv_finmethod := finishingmethodid;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and (not price_not_relevant) loop
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 2
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid;
      lv_residentialrentid       := null;
      lv_custsplitinvperactivity := null;
      open vcsr for
        select rr.residentialrent_id, p.typeofmerchandise, p.productgroup_id,
               c.garmentrentspecification, c.splitinvoicesperactivity
        from   residentialrent rr, product p, customer c --productlistpercustomer plpc
        where  rr.customer_id = customerid
        and    rr.product_id = productid
        and    p.product_id = productid
        and    c.customer_id = customerid
        and    rr.sizedefinition_id = lv_size
        and    rr.finishingmethod_id = lv_finmethod
        and    ((lv_pricedate >= rr.startdate and lv_pricedate <= rr.enddate) or i > 2)
        -- only filter on active in iteration 3 and 4
        order  by rr.startdate desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_residentialrentid, lv_typeofmerchandize, lv_productgroup_id,
               lv_customergarmrentspec, lv_custsplitinvperactivity;
        lv_typeofrent          := 9;
        lv_typeofrent_general  := lv_typeofrent;
        lv_typeofrent_specific := lv_typeofrent;
      end if;
      close vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) and (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select grp.price, grp.startdate, g.code, g.description
                       from   generalrentprice grp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 2
                       and    g.active = 'Y'
                       and    grp.generalpricelist_id = g.generalpricelist_id
                       and    grp.product_id = productid
                       and    grp.sizedefinition_id = lv_size
                       and    grp.finishingmethod_id = lv_finmethod
                       and    grp.startdate <= lv_pricedate
                       and    grp.typeofrent = lv_typeofrent_general
                       order  by grp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- select original size again and try for an inactive plpc
          if lv_residentialrentid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if not price_found then
      open vcsr for
        select x.*, rownum
        from   (select cupri.price, cupri.startdate
                 from   customerresidentialrentprice cupri
                 where  cupri.customer_id = customerid
                 and    cupri.product_id = productid
                 and    cupri.sizedefinition_id = sizedefinitionid
                 and    cupri.finishingmethod_id = finishingmethodid
                 and    cupri.startdate <= lv_pricedate
                 order  by cupri.startdate desc) x
        where  rownum = 1; -- take first
      fetch vcsr
        into lv_price, lv_price_start_date, dummy;
      close vcsr;
      if lv_price is not null then
        price_found := true;
      end if;
    end if;
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G' then
        price_list_desc := lv_pricelist_desc;
      else
        price_list_desc := 'Customer Specific.';
      end if;
      price_type_code := lv_typeofrent;
      price_type_desc := decode_type_of_rent(price_type_code);
    else
      if result_code is null then
        -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_residrent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function residentialrent_price_details(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(100);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerrentprice.typeofrent%type;
    price_type_desc  varchar2(30);
  
  begin
    get_residrent_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                pricedate, price, price_found_yn, price_start_date, result_code,
                                result_desc, price_list_type, price_list_code, price_list_desc,
                                price_type_code, price_type_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(to_char(price_type_code), ' '), 1) ||
           rpad(nvl(price_type_desc, ' '), 30) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end residentialrent_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function residentialrent_price(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns 0.  For use in calculations.  */
  
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(100);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerrentprice.typeofrent%type;
    price_type_desc  varchar2(30);
  
  begin
    get_residrent_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                pricedate, price, price_found_yn, price_start_date, result_code,
                                result_desc, price_list_type, price_list_code, price_list_desc,
                                price_type_code, price_type_desc);
    return(nvl(price, 0));
  end residentialrent_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function residentialrent_price_display(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the price, if not found, returns null.  For display/print purposes. */
  
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(100);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
    price_type_code  customerrentprice.typeofrent%type;
    price_type_desc  varchar2(30);
  
  begin
    get_residrent_price_details(customerid, productid, sizedefinitionid, finishingmethodid,
                                pricedate, price, price_found_yn, price_start_date, result_code,
                                result_desc, price_list_type, price_list_code, price_list_desc,
                                price_type_code, price_type_desc);
    return(price);
  end residentialrent_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure get_loan_price_details(customerid        in customer.customer_id%type,
                                   productid         in product.product_id%type,
                                   sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   price             out customerrentprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerrentprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type) is
  
    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_pricelist_type           varchar2(1);
    lv_typeofrent               customerrentprice.typeofrent%type;
    lv_price                    customerrentprice.price%type;
    lv_price_start_date         customerrentprice.startdate%type;
    lv_generalpricelistid       generalrentprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type tcsr is ref cursor;
    vcsr              tcsr;
    vpricelistpercust tcsr;
  
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode, 'Y0', 'Price found', 'N1', 'Price not defined', 'N8',
                     'Error in parameters', 'N9', 'ORA Error', 'Unknown error code')
      into   r
      from   dual;
      return r;
    end;
  
  begin
    -- main loan price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    lv_typeofrent      := 10; -- Loan
    price_found        := false;
    price_not_relevant := false;
    price              := null;
    price_found_yn     := 'N';
    price_start_date   := null;
    result_code        := null;
    result_desc        := null;
    price_list_type    := null;
    price_list_code    := null;
    price_list_desc    := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size      := sizedefinitionid;
    lv_finmethod := finishingmethodid;
    if (customerid is null) or (productid is null) or (sizedefinitionid is null) or
       (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and (not price_not_relevant) loop
      open vpricelistpercust for
        select pricelistpercustomer.generalpricelist_id
        from   pricelistpercustomer
        where  pricelistpercustomer.customer_id = customerid
        and    pricelistpercustomer.pricetype = 2
        and    pricelistpercustomer.dateactive <= lv_pricedate
        and    pricelistpercustomer.dateinactive >= lv_pricedate
        order  by pricelistpercustomer.priority;
      fetch vpricelistpercust
        into lv_generalpricelistid;
      -- load plpc
      lv_productlistpercustomerid := null;
      open vcsr for
        select plpc.productlistpercustomer_id
        from   productlistpercustomer plpc
        where  plpc.customer_id = customerid
        and    plpc.product_id = productid
        and    plpc.sizedefinition_id = lv_size
        and    plpc.finishingmethod_id = lv_finmethod
        and    ((lv_pricedate >= plpc.dateactive and lv_pricedate <= plpc.dateinactive) or i > 2)
        -- only filter on active in iteration 3 and 4
        order  by plpc.dateactive desc;
      if vcsr%notfound then
        null;
      else
        fetch vcsr
          into lv_productlistpercustomerid;
      end if;
      close vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not vpricelistpercust%notfound) and (not price_found) and (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open vcsr for
              select x.*, rownum
              from   (select grp.price, grp.startdate, g.code, g.description
                       from   generalrentprice grp, generalpricelist g
                       where  g.generalpricelist_id = lv_generalpricelistid
                       and    g.pricetype = 2
                       and    g.active = 'Y'
                       and    grp.generalpricelist_id = g.generalpricelist_id
                       and    grp.product_id = productid
                       and    grp.sizedefinition_id = lv_size
                       and    grp.finishingmethod_id = lv_finmethod
                       and    grp.typeofrent = lv_typeofrent
                       and    grp.startdate <= lv_pricedate
                       order  by grp.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else
          --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open vcsr for
              select x.*, rownum
              from   (select cupri.price, cupri.startdate
                       from   customerrentprice cupri
                       where  cupri.productlistpercustomer_id = lv_productlistpercustomerid
                       and    cupri.startdate <= lv_pricedate
                       and    cupri.typeofrent = lv_typeofrent
                       order  by cupri.startdate desc) x
              where  rownum = 1; -- take first
            fetch vcsr
              into lv_price, lv_price_start_date, dummy;
            close vcsr;
          
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch vpricelistpercust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then
          --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 2
          end if;
        end if;
        if i = 3 then
          -- select original size again and try for an inactive plpc
          if lv_productlistpercustomerid is not null then
            i := 5; -- don't search further
          else
            lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then
          --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
          into   lv_size
          from   sizedefinition
          where  sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
           then
            i := i + 1; -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := 0;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G' then
        price_list_desc := lv_pricelist_desc;
      else
        price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then
        -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end get_loan_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function loan_price_details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2 is
    /* See package header for description of return string.   */
  
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_loan_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           price, price_found_yn, price_start_date, result_code, result_desc,
                           price_list_type, price_list_code, price_list_desc);
    return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) || price_found_yn ||
           rpad(nvl(to_char(price_start_date, 'YYYYMMDD'), ' '), 8) ||
           rpad(nvl(price_list_type, ' '), 1) || rpad(nvl(substr(price_list_code, 1, 6), ' '), 6) || -- part 1  pos 1-6
           rpad(nvl(price_list_desc, ' '), 40) || rpad(nvl(to_char(result_code), ' '), 1) ||
           rpad(nvl(result_desc, ' '), 80) || rpad(nvl(substr(price_list_code, 7, 9), ' '), 9) -- part 2  pos 7-15
           );
  end loan_price_details;

  /*--------------------------------------------------------------------------------------------------------*/
  function loan_price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the loan price, if not found, returns 0.  For use in calculations.  */
  
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_loan_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           price, price_found_yn, price_start_date, result_code, result_desc,
                           price_list_type, price_list_code, price_list_desc);
    return(nvl(price, 0));
  end loan_price;

  /*--------------------------------------------------------------------------------------------------------*/
  function loan_price_display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
    return number is
    /* Returns the loan price, if not found, returns null.  For display/print purposes. */
  
    price            customerrentprice.price%type;
    price_found_yn   varchar2(1);
    price_start_date customerrentprice.startdate%type;
    result_code      number;
    result_desc      varchar2(80);
    price_list_type  varchar2(1);
    price_list_code  generalpricelist.code%type;
    price_list_desc  generalpricelist.description%type;
  
  begin
    get_loan_price_details(customerid, productid, sizedefinitionid, finishingmethodid, pricedate,
                           price, price_found_yn, price_start_date, result_code, result_desc,
                           price_list_type, price_list_code, price_list_desc);
    return(price);
  end loan_price_display;

  /*--------------------------------------------------------------------------------------------------------*/
  function budget_price(fpcustomerid    customerbudgetdefinition.customer_id%type,
                        fpcode          customerbudgetdefinition.code%type,
                        fpreferencedate date) return number is
    /* Returns the budget price, if not found, returns 0.  For use in calculations.  */
    vcustbudgetdefid customerbudgetdefinition.customerbudgetdefinition_id%type;
    vprice           number;
  
  begin
  
    select cbd.customerbudgetdefinition_id
    into   vcustbudgetdefid
    from   customerbudgetdefinition cbd
    where  cbd.customer_id = fpcustomerid
    and    cbd.code = fpcode;
  
    begin
      select cbp.price
      into   vprice
      from   customerbudgetprice cbp
      where  cbp.customerbudgetdefinition_id = vcustbudgetdefid
      and    cbp.startdate <= fpreferencedate
      and    cbp.startdate = (select max(cbp.startdate)
                              from   customerbudgetprice cbp
                              where  cbp.customerbudgetdefinition_id = vcustbudgetdefid
                              and    cbp.startdate <= fpreferencedate);
    
      return vprice;
    exception
      when no_data_found then
        return 0;
    end;
  end budget_price;

  function customer_uses_specialprices(customerid in customer.customer_id%type) return boolean is
    use_special_prices customer.useprodsizesurchargepricing%type;
  begin
    select c.useprodsizesurchargepricing
    into   use_special_prices
    from   customer c
    where  c.customer_id = customerid;
    return use_special_prices = 'Y';
  exception
    when no_data_found then
      return false;
  end customer_uses_specialprices;

  function get_standard_szbillinggroup return number is
    standard_sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
  begin
    select min(sz.sizebillinggroup_id)
    into   standard_sizebillinggroupid
    from   sizebillinggroup sz
    where  sz.standard = 'Y';
    return nvl(standard_sizebillinggroupid, 0);
  exception
    when too_many_rows then
      return 0; --should only be 1 standard
    when no_data_found then
      return 0;
  end get_standard_szbillinggroup;

  function get_product_size_billinggroup(productid in product.product_id%type,
                                         sizeid    in sizedefinition.sizedefinition_id%type)
    return number is
    sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
    lv_sizestarid      sizedefinition.sizedefinition_id%type;
  begin
    select ps.sizebillinggroup_id
    into   sizebillinggroupid
    from   productsize ps
    where  ps.product_id = productid
    and    ps.sizedefinition_id = sizeid;
  
    if (sizebillinggroupid is null) then
      select sd.sizedefinition_id into lv_sizestarid from sizedefinition sd where sd.code = '*';
    
      if (sizeid = lv_sizestarid) then
        select sd.sizebillinggroup_id
        into   sizebillinggroupid
        from   sizedefinition sd
        where  sd.sizedefinition_id = lv_sizestarid;
      end if;
    end if;
    return nvl(sizebillinggroupid, 0);
  exception
    when no_data_found then
      begin
        select sd.sizebillinggroup_id
        into   sizebillinggroupid
        from   sizedefinition sd
        where  sd.sizedefinition_id = sizeid;
        return sizebillinggroupid;
      exception
        when no_data_found then
          return 0;
      end;
  end get_product_size_billinggroup;

  procedure get_size_billing_groups(customerid                     in customer.customer_id%type,
                                    productid                      in product.product_id%type,
                                    sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                    pricetype                      number,
                                    lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                    lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type) is
  
    lv_customer_uses_sz_billing    boolean;
    lv_ss_sizespecialchargeoptions int;
    lv_is_special_size_price_used  boolean;
  begin
    begin
      select value
      into   lv_ss_sizespecialchargeoptions
      from   systemsetting st
      join   businessunit bu
      on     bu.plant_id = st.plant_id
      join   customer c
      on     c.defaultbusinessunit_id = bu.businessunit_id
      where  st.name = 'SIZESPECIALCHARGEOPTIONS'
      and    c.customer_id = customerid;
    exception
      when no_data_found then
        lv_ss_sizespecialchargeoptions := 0;
    end;
    if pricetype = 2 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 1 or
                                       lv_ss_sizespecialchargeoptions = 4 or
                                       lv_ss_sizespecialchargeoptions = 5 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    if pricetype = 3 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 3 or
                                       lv_ss_sizespecialchargeoptions = 5 or
                                       lv_ss_sizespecialchargeoptions = 6 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    if pricetype = 4 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 2 or
                                       lv_ss_sizespecialchargeoptions = 4 or
                                       lv_ss_sizespecialchargeoptions = 6 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    lv_customer_uses_sz_billing    := customer_uses_specialprices(customerid);
    lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
    if lv_customer_uses_sz_billing and lv_is_special_size_price_used then
      lv_specific_sizebillinggroupid := get_product_size_billinggroup(productid, sizedefinitionid);
    else
      lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
    end if;
  
  end get_size_billing_groups;

end pack_price_new;

/
create or replace PACKAGE PACK_PRICE_OLD is
  /*
    18/11/2009 (502831) HVH New developed.
    08/01/2010          HVH Issue fixed with rent price for changes per week.
                            When exact# of changes was passed for size <> * in some cases wrong price was returned
    12/02/2010          HVH Added Weight Price and Weight Discount
    19/02/2010          HVH Added Rent and Wash Discount + performance improvement on all price search proc's
    22/03/2011          SSB Added Special Charge functions
    29/04/2011          HVH Improved Special Charge procedure and extended return string of SpecialCharge_Details
    21/11/2012          SSB Added Residential Rent functions
    13/02/2013          HVH Added Wash_Price_PT for washprices with specific pricetype (i.e. heavy soil)
                            Also added Loan_Price functions.
    01/03/2013          PVD Update for unrelated loan and changes before for general price determination
    17/09/2013          RVI Update for under/overuse wash prices
    25/02/2014          HVH Return replacement price when inventorybillingtype = 5
    27/02/2016          HVH Extended pricelistcode from 6 to 15 chars in xxx_price_details functions
    4/08/2017           DLA Updated for size billing group
	  11/01/2018          DLA Fix for size billing group
	  15/01/2018          SSB Fix for UK weekly underuse method
    19/05/2021          DLA ABS-117421 Size billing group NULL causing issues with display and invoicing
    19/08/2021          APA ABS-119993 Customer coefficient for replacement price
	  13/09/2021			    ABS-123845 PACK_PRICE call takes alot of time and get stuck
    16/11/2021			    LAC ABS-118827 Replacement price for loss for pool with BM4 is not calculated
  */

  /* ----------------------------------------------------------------------------------------------
  /* General remarks Rent price procedures/functions.

     This procedure and functions return the rent price (and other price details) for a given
     customer, product, size and finishingmethod, that is valid on the date that is passed in the
     parameter pricedate. If this optional parameter is omited, it will return the price valid on the sysdate.

     The procedure and functions can be used in 2 ways:
     a) To retrieve a price for a product list per customer line.
        (so without a specific # of changes or specific delivery frequency)
        For this purpose omit, or pass 0 to chgperwk_or_freq parameter.
        It will try to find the most recent valid price for any number of changes or any frequency.

     b) To retrieve a price for a product with a specific # of changes or specific delivery frequency.
        For this purpose pass a value <> 0 to chgperwk_or_freq parameter.
        For garments with billingmethod 1 a specific number of changes can be passed.
        If there is no price defined for that specific number of changes, it will try
        to find the price for number of changes *
        For delivery frequency based pricing it is possible to pass a specific frequency.
        The frequency is defined in # of weeks:
        Example: for delivery scheme EOW (Every other week) frequency = 2. (weekly=1)
  */

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Rent_Price_Details

    This is the base procedure used by the Rent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure Get_Rent_Price_Details(customerid             in customer.customer_id%type,
                                   productid              in product.product_id%type,
                                   sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   pricedate              in pricelistpercustomer.dateactive%type,
                                   chgperwk_or_freq       in generalrentprice.changesperweek%type,
                                   price                  out customerrentprice.price%type,
                                   price_found_yn         out varchar2,
                                   price_start_date       out customerrentprice.startdate%type,
                                   result_code            out number,
                                   result_desc            out varchar2,
                                   price_list_type        out varchar2,
                                   price_list_code        out generalpricelist.code%type,
                                   price_list_desc        out generalpricelist.description%type,
                                   changesperwkfoundprice out customerrentprice.changesperweek%type,
                                   price_type_code        out customerrentprice.typeofrent%type,
                                   price_type_desc        out varchar2,
                                   inv_freq_code          out customerrentprice.invoicefrequencynumber%type,
                                   inv_freq_desc          out varchar2,
                                   customerrentpriceid    out customerrentprice.customerrentprice_id%type);

  /* ----------------------------------------------------------------------------------------------
    Function Rent_Price_Details

    Returns all price details, like procedure Get_Rent_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181       ( 1): invoice freq code
    pos 182 - 191 (10): invoice freq description
    pos 192 - 201 (10): found price is defined for this number of changes per week
    pos 202 - 210 ( 9): price list code part 2 char 7-15
    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    Y 1     Multiple prices applicable for different # of changes.
    Y 2     Multiple prices applicable for different frequencies.
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method with wash price only
    N 3     Price not relevant, billing method = 4 piece rate only
    N 4     Price not relevant, defined on wearer level as wearer total price.
    N 5     Price not relevant, defined at wearer function level
    N 8     Error in parameters
    N 9     ORA Error
  */
  function Rent_Price_Details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Rent_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Rent_Price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function CustomerRent_PriceID
     Use this function in calculations. It will return customer rent price id determined in Get_Rent_price_Details procedure.
  */
  function CustomerRent_PriceID(customerid        in customer.customer_id%type,
                    productid         in product.product_id%type,
                    sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                    finishingmethodid in finishingmethod.finishingmethod_id%type,
                    pricedate         in pricelistpercustomer.dateactive%type default null,
                    chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
     return number;
  /* ----------------------------------------------------------------------------------------------
     Function Rent_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Rent_Price_Display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
    return number;

  /* ---------------------------------------------------------------------------------------------- */
  /* General remarks Wash price procedures/functions.

     This procedure and functions return the wash price (and other price details) for a given
     customer, product, size and finishingmethod, that is valid on the date that is passed in the
     parameter pricedate. If this optional parameter is omited, it will return the price valid on the sysdate.

     The procedure and functions can be used in 2 ways:
     a) To retrieve a price for a product list per customer line.
        (so without indication if the price is for a LOG (Laundry Owned Goods) or COG (Customer Owned Goods) item)
        For this purpose omit, or pass 0 to pricetype parameter.
        It will try to find the most recent valid price for any number of changes or any frequency.

     b) To retrieve a price for a product for which it is known if it is a LOG or COG item.
        Pass 1 for LOG, pass 2 for COG to parameter pricetype

     c) To retrieve a price for a product for for a specific known price type (PT) use the Wash_Price_PT functions
        For example for price type Heavy Soil. Possible price types are described under Get_Wash_Price_Details_PT

  */

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Wash_Price_Details

    This is the base procedure used by the Wash_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */

  procedure Get_Wash_Price_Details(customerid             in customer.customer_id%type,
                                   productid         in product.product_id%type,
                                   sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid in finishingmethod.finishingmethod_id%type,
                                   pricedate         in pricelistpercustomer.dateactive%type,
                                   pricetype         in number, -- 0=all, 1=LOG, 2=COG
                                   price             out customerwashprice.price%type,
                                   price_found_yn    out varchar2,
                                   price_start_date  out customerwashprice.startdate%type,
                                   result_code       out number,
                                   result_desc       out varchar2,
                                   price_list_type   out varchar2,
                                   price_list_code   out generalpricelist.code%type,
                                   price_list_desc   out generalpricelist.description%type,
                                   price_type_code   out customerwashprice.pricetype%type,
                                   price_type_desc   out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Price_Details

    Returns all price details, like procedure Get_Wash_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 189 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    Y 1     Distinct prices can be applicable LOG and COG
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method 3 with rent price only
    N 3     Price not relevant, billing method = 1 flat rated rent
    N 4     Price not relevant, billing method = 2 rent based on minimum
    N 5     Price not relevant, disposable / sales only item
    N 6     Price not relevant, billing method = 4 with price for LOG only
    N 7     Price not relevant, billing method = 4 with price for COG only
    N 8     Error in parameters
    N 9     ORA Error
  */
  function Wash_Price_Details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0)
  return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Wash_Price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null,
                      pricetype         in number default 0)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Wash_Price_Display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null,
                              pricetype         in number default 0)
  return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Wash_Price_Details_PT

    This is the base procedure used by the Wash_Price_PT functions.
    This procedure can be used to know all details about a wash price for a specified price type (PT)

    Possible price types are:
    1 = All items
    2 = COG items only
    3 = Price on client delivery note
    4 = Wash part of Split price
    5 = Heavy Soil
  */

  procedure Get_Wash_Price_Details_PT(customerid             in customer.customer_id%type,
                                      productid              in product.product_id%type,
                                      sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                      pricedate              in pricelistpercustomer.dateactive%type,
                                      pricetype              in number,
                                      price                  out customerwashprice.price%type,
                                      price_found_yn         out varchar2,
                                      price_start_date       out customerwashprice.startdate%type,
                                      result_code            out number,
                                      result_desc            out varchar2,
                                      price_list_type        out varchar2,
                                      price_list_code        out generalpricelist.code%type,
                                      price_list_desc        out generalpricelist.description%type,
                                      price_type_code        out customerwashprice.pricetype%type,
                                      price_type_desc        out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Price_Details_PT

    Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
    Returns all price details, like procedure Get_Wash_Price_Details_PT,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 189 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function Wash_Price_Details_PT(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number)
  return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_PT
     Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Wash_Price_PT(customerid        in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         pricedate         in pricelistpercustomer.dateactive%type default null,
                         pricetype         in number)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Price_Display_PT
     Returns wash price for specified price type (PT). See Get_Wash_Price_Details_PT for possible price types.
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Wash_Price_Display_PT(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null,
                                 pricetype         in number)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Procedure Get_Replacement_Price_Details

     This is the base procedure used by the Replacement_PriceXXX functions.
     This procedure can be used to know all details about a price.
  */
  procedure Get_Replacement_Price_Details(customerid             in customer.customer_id%type,
                                          productid         in product.product_id%type,
                                          sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                          finishingmethodid in finishingmethod.finishingmethod_id%type,
                                          pricedate         in pricelistpercustomer.dateactive%type,
                                          price             out customerreplacementprice.price%type,
                                          price_found_yn    out varchar2,
                                          price_start_date  out customerreplacementprice.startdate%type,
                                          result_code       out number,
                                          result_desc       out varchar2,
                                          price_list_type   out varchar2,
                                          price_list_code   out generalpricelist.code%type,
                                          price_list_desc   out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Replacement_Price_Details

    Returns all price details, like procedure Get_Replacement_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method = 4 piece rate only
    N 3     Price not relevant, disposable / sales only item
    N 8     Error in parameters
    N 9     ORA Error
  */
  function Replacement_Price_Details(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Replacement_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Replacement_Price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Replacement_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Replacement_Price_Display(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type default null,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
    return number;



  /* ----------------------------------------------------------------------------------------------
     Procedure Get_Sales_Price_Details

     This is the base procedure used by the Sales_PriceXXX functions.
     This procedure can be used to know all details about a price.
  */
  procedure Get_Sales_Price_Details(customerid             in customer.customer_id%type,
                                    productid        in product.product_id%type,
                                    sizedefinitionid in sizedefinition.sizedefinition_id%type,
                                    pricedate        in pricelistpercustomer.dateactive%type,
                                    price            out customersalesprice.price%type,
                                    price_found_yn   out varchar2,
                                    price_start_date out customersalesprice.startdate%type,
                                    result_code      out number,
                                    result_desc      out varchar2,
                                    price_list_type  out varchar2,
                                    price_list_code  out generalpricelist.code%type,
                                    price_list_desc  out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Sales_Price_Details

    Returns all price details, like procedure Get_Sales_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function Sales_Price_Details(customerid        in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Sales_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Sales_Price(customerid        in customer.customer_id%type,
                       productid        in product.product_id%type,
                       sizedefinitionid in sizedefinition.sizedefinition_id%type,
                       pricedate        in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Sales_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Sales_Price_Display(customerid        in customer.customer_id%type,
                               productid        in product.product_id%type,
                               sizedefinitionid in sizedefinition.sizedefinition_id%type,
                               pricedate        in pricelistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Weight_Price_Details(customerid            in customer.customer_id%type,
                                     weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                     soil_yn            in customerweightprice.soil%type,
                                     pricedate          in pricelistpercustomer.dateactive%type,
                                     price              out customerweightprice.price%type,
                                     price_found_yn     out varchar2,
                                     price_start_date   out customerweightprice.startdate%type,
                                     result_code        out number,
                                     result_desc        out varchar2,
                                     price_list_type    out varchar2,
                                     price_list_code    out generalpricelist.code%type,
                                     price_list_desc    out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Weight_Price_Details

    Returns all price details, like procedure Get_Weight_Price_Details,
    This function returns them all concatenated in a fixed length return string.
    Parameter soil_yn should be populated with 'Y' for soil weight price or 'N' for clean weight price.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, weights not invoiced
    N 3     Price not defined, weights invoiced soil, not clean
    N 4     Price not defined, weights invoiced clean, not soil
    N 8     Error in parameters
    N 9     ORA Error
  */

  function Weight_Price_Details(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Weight_Price(customerid         in customer.customer_id%type,
                        weighingcategoryid in weighingcategory.weighingcategory_id%type,
                        soil_yn            in customerweightprice.soil%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Weight_Price_Display(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure Get_SpecCharge_Details(customerid     in customer.customer_id%type,
                                   specialchargeid  in specialcharge.specialcharge_id%type,
                                   pricedate        in pricelistpercustomer.dateactive%type,
                                   price            out customerspecialchargeprice.price%type,
                                   price_found_yn   out varchar2,
                                   price_start_date out customerspecialchargeprice.startdate%type,
                                   result_code      out number,
                                   result_desc      out varchar2,
                                   price_list_type  out varchar2,
                                   price_list_code  out generalpricelist.code%type,
                                   price_list_desc  out generalpricelist.description%type,
                                   specialchargecode      out specialcharge.code%type,
                                   percentage       out customerspecialchargeprice.percentage%type,
                                   minimumamount    out specialcharge.minimumamount%type,
                                   maximumamount    out specialcharge.maximumamount%type);

  /* ----------------------------------------------------------------------------------------------
    Function SpecialCharge_Details

    Returns all price details, like procedure Get_SpecialCharge_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price format: 99999.99999 ,  spaces when no price found or not applicable.
    pos  13       ( 1): price or percentage returned Y / N
    pos  14 - 21  ( 8): price or percentage start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, B=Base table price, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69 - 74  ( 6): special charge code
    pos  75       ( 1): price result code , see list below.
    pos  76 - 155 (80): price result description
    pos 156 - 162 ( 7): percentage fromat: 999.99, spaces when not found or not applicable.
    pos 163 - 172 (10): minimum amount fromat: 999999.99, spaces when not found or not applicable.
    pos 173 - 182 (10): maximum amount fromat: 999999.99, spaces when not found or not applicable.
    pos 183 - 191 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price or percentage found, no remark
    N 1     Price or percentage not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */

  function SpecialCharge_Details(customerid  in customer.customer_id%type,
                                 specialchargeid in specialcharge.specialcharge_id%type,
                                 pricedate       in pricelistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function SpecialCharge_Price(customerid  in customer.customer_id%type,
                               specialchargeid in specialcharge.specialcharge_id%type,
                               pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function SpecialCharge_Price_Display(customerid  in customer.customer_id%type,
                                       specialchargeid in specialcharge.specialcharge_id%type,
                                       pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Percentage
     Use this function in calculations. It will return percentage 0.00 in case the percentage could not be found.
  */
  function SpecialCharge_Percentage(customerid  in customer.customer_id%type,
                                    specialchargeid in specialcharge.specialcharge_id%type,
                                    pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_Perc_Display
     Use this function for display or print purposes. It will return null in case the percentage could not be found.
  */
  function SpecialCharge_Percentage_Disp(customerid  in customer.customer_id%type,
                                         specialchargeid in specialcharge.specialcharge_id%type,
                                         pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MinAmount
     Use this function in calculations. It will return MinAmount 0.00 in case the MinAmount could not be found.
  */
  function SpecialCharge_MinAmount(customerid  in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MinAmount_Disp
     Use this function for display or print purposes. It will return null in case the MinAmount could not be found.
  */
  function SpecialCharge_MinAmount_Disp(customerid  in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MaxAmount
     Use this function in calculations. It will return MaxAmount 0.00 in case the MaxAmount could not be found.
  */
  function SpecialCharge_MaxAmount(customerid  in customer.customer_id%type,
                                   specialchargeid in specialcharge.specialcharge_id%type,
                                   pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function SpecialCharge_MaxAmount_Disp
     Use this function for display or print purposes. It will return null in case the MaxAmount could not be found.
  */
  function SpecialCharge_MaxAmount_Disp(customerid  in customer.customer_id%type,
                                        specialchargeid in specialcharge.specialcharge_id%type,
                                        pricedate       in pricelistpercustomer.dateactive%type default null)
    return number;
  /*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Rent_Discount_Details(customerid            in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate          in Discountlistpercustomer.dateactive%type,
                                      discount              out customerrentdiscount.Discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerrentdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Rent_Discount_Details

    Returns all Discount details, like procedure Get_Rent_Discount_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description

    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, billing method with wash price only
    N 3     Discount not relevant, billing method = 4 piece rate only
    N 4     Discount not applicable, price defined on wearer level as wearer total price.
    N 5     Discount not applicable, price defined at wearer function level
    N 8     Discount in parameters
    N 9     ORA Error
  */

  function Rent_Discount_Details(customerid         in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 Discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */

  function Rent_Discount(customerid         in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */

  function Rent_Discount_Display(customerid         in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;


  /*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Wash_Discount_Details(customerid            in customer.customer_id%type,
                                      productid           in product.product_id%type,
                                      sizedefinitionid    in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid   in finishingmethod.finishingmethod_id%type,
                                      discountdate          in Discountlistpercustomer.dateactive%type,
                                      discount              out customerwashdiscount.Discount%type,
                                      discount_found_yn   out varchar2,
                                      discount_start_date out customerwashdiscount.startdate%type,
                                      result_code         out number,
                                      result_desc         out varchar2,
                                      discount_list_type  out varchar2,
                                      discount_list_code  out generaldiscountlist.code%type,
                                      discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Wash_Discount_Details

    Returns all Discount details, like procedure Get_Wash_Discount_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description

    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, billing method 3 with rent price only
    N 3     Discount not defined, billing method = 1 flat rated rent
    N 4     Discount not defined, billing method = 2 rent based on minimum
    N 5     Discount not relevant, disposable / sales only item
    N 8     Error in parameters
    N 9     ORA Error
  */

  function Wash_Discount_Details(customerid         in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 Discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */

  function Wash_Discount(customerid         in customer.customer_id%type,
                         productid         in product.product_id%type,
                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                         discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Wash_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */

  function Wash_Discount_Display(customerid         in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 discountdate      in discountlistpercustomer.dateactive%type default null)
    return number;

  /*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Weight_Discount_Details(customerid            in customer.customer_id%type,
                                        weighingcategoryid  in weighingcategory.weighingcategory_id%type,
                                        soil_yn             in customerweightdiscount.soil%type,
                                        discountdate        in discountlistpercustomer.dateactive%type,
                                        discount            out customerweightdiscount.discount%type,
                                        discount_found_yn   out varchar2,
                                        discount_start_date out customerweightdiscount.startdate%type,
                                        result_code         out number,
                                        result_desc         out varchar2,
                                        discount_list_type  out varchar2,
                                        discount_list_code  out generaldiscountlist.code%type,
                                        discount_list_desc  out generaldiscountlist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Weight_Discount_Details

    Returns all Discount details, like procedure Get_Weight_Discount_Details,
    This function returns them all concatenated in a fixed length return string.
    Parameter soil_yn should be populated with 'Y' for soil weight Discount or 'N' for clean weight Discount.

    The return string is composed of the following elements:
    pos  1 -  12  (12): Discount % format: 99999.99999 ,  spaces when no Discount found. Max 2 decimals
    pos  13       ( 1): Discount returned Y / N
    pos  14 - 21  ( 8): Discount start date format YYYYMMDD, spaces when no Discount found.
    pos  22       ( 1): Discount list type: C=Customer specific, G=General Discount list, space when no Discount found.
    pos  23 - 28  ( 6): Discount list code spaces when no Discount found, or when customer specific
    pos  29 - 68  (40): Discount list description spaces when no Discount found or 'Customer Specific' when customer specific
    pos  69       ( 1): Discount result code , see list below.
    pos  70 - 149 (80): Discount result description

    Possible values for Discount_found_yn + result_code combinations:
    Y 0     Discount found, no remark
    N 1     Discount not defined, no particular reason
    N 2     Discount not relevant, weights not invoiced
    N 3     Discount not defined, weights invoiced soil, not clean
    N 4     Discount not defined, weights invoiced clean, not soil
    N 8     Error in parameters
    N 9     ORA Error
  */

  function Weight_Discount_Details(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   Discountdate       in discountlistpercustomer.dateactive%type default null)
    return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Discount
     Use this function in calculations. It will return Discount 0.00 in case the Discount could not be found.
  */
  function Weight_Discount(customerid         in customer.customer_id%type,
                           weighingcategoryid in weighingcategory.weighingcategory_id%type,
                           soil_yn            in customerweightdiscount.soil%type,
                           discountdate       in discountlistpercustomer.dateactive%type default null)
    return number;

  /* ----------------------------------------------------------------------------------------------
     Function Weight_Discount_Display
     Use this function for display or print purposes. It will return null in case the Discount could not be found.
  */
  function Weight_Discount_Display(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
    return number;

/* ----------------------------------------------------------------------------------------------
    Procedure Get_ResidentialRent_Price_Details

    This is the base procedure used by the ResidentialRent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure Get_ResidRent_Price_Details(customerid             in customer.customer_id%type,
                                        productid              in product.product_id%type,
                                        sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                        finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                        pricedate              in pricelistpercustomer.dateactive%type,
                                        price                  out customerrentprice.price%type,
                                        price_found_yn         out varchar2,
                                        price_start_date       out customerrentprice.startdate%type,
                                        result_code            out number,
                                        result_desc            out varchar2,
                                        price_list_type        out varchar2,
                                        price_list_code        out generalpricelist.code%type,
                                        price_list_desc        out generalpricelist.description%type,
                                        price_type_code        out customerrentprice.typeofrent%type,
                                        price_type_desc        out varchar2);

  /* ----------------------------------------------------------------------------------------------
    Function ResidentialRent_Price_Details

    Returns all price details, like procedure Get_ResidentialRent_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150       ( 1): price type code
    pos 151 - 180 (30): price type description
    pos 181 - 190 (10): found price is defined for this number of changes per week
    pos 191 - 199 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 2     Price not relevant, billing method with wash price only
    N 3     Price not relevant, billing method = 4 piece rate only
    N 4     Price not relevant, defined on wearer level as wearer total price.
    N 5     Price not relevant, defined at wearer function level
    N 8     Error in parameters
    N 9     ORA Error
  */
  function ResidentialRent_Price_Details(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
  return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function ResidentialRent_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function ResidentialRent_Price(customerid        in customer.customer_id%type,
                                 productid         in product.product_id%type,
                                 sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid in finishingmethod.finishingmethod_id%type,
                                 pricedate         in pricelistpercustomer.dateactive%type default null)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function ResidentialRent_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function ResidentialRent_Price_Display(customerid        in customer.customer_id%type,
                                         productid         in product.product_id%type,
                                         sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                         finishingmethodid in finishingmethod.finishingmethod_id%type,
                                         pricedate         in pricelistpercustomer.dateactive%type default null)
  return number;

  /* ----------------------------------------------------------------------------------------------
    Procedure Get_Loan_Price_Details

    This is the base procedure used by the Rent_PriceXXX functions.
    This procedure can be used to know all details about a price.
  */
  procedure Get_Loan_Price_Details(customerid             in customer.customer_id%type,
                                   productid              in product.product_id%type,
                                   sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   pricedate              in pricelistpercustomer.dateactive%type,
                                   price                  out customerrentprice.price%type,
                                   price_found_yn         out varchar2,
                                   price_start_date       out customerrentprice.startdate%type,
                                   result_code            out number,
                                   result_desc            out varchar2,
                                   price_list_type        out varchar2,
                                   price_list_code        out generalpricelist.code%type,
                                   price_list_desc        out generalpricelist.description%type);

  /* ----------------------------------------------------------------------------------------------
    Function Loan_Price_Details

    Returns all price details, like procedure Get_Loan_Price_Details,
    This function returns them all concatenated in a fixed length return string.

    The return string is composed of the following elements:
    pos  1 -  12  (12): price  format: 99999.99999 ,  spaces when no price found.
    pos  13       ( 1): price returned Y / N
    pos  14 - 21  ( 8): price start date format YYYYMMDD, spaces when no price found.
    pos  22       ( 1): price list type: C=Customer specific, G=General price list, space when no price found.
    pos  23 - 28  ( 6): price list code part 1 char 1-6, spaces when no price found, or when customer specific
    pos  29 - 68  (40): price list description spaces when no price found or 'Customer Specific' when customer specific
    pos  69       ( 1): price result code , see list below.
    pos  70 - 149 (80): price result description
    pos 150 - 158 ( 9): price list code part 2 char 7-15

    Possible values for price_found_yn + result_code combinations:
    Y 0     Price found, no remark
    N 1     Price not defined, no particular reason
    N 8     Error in parameters
    N 9     ORA Error
  */
  function Loan_Price_Details(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
  return varchar2;

  /* ----------------------------------------------------------------------------------------------
     Function Loan_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Loan_Price(customerid        in customer.customer_id%type,
                      productid         in product.product_id%type,
                      sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                      finishingmethodid in finishingmethod.finishingmethod_id%type,
                      pricedate         in pricelistpercustomer.dateactive%type default null)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function Loan_Price_Display
     Use this function for display or print purposes. It will return null in case the price could not be found.
  */
  function Loan_Price_Display(customerid        in customer.customer_id%type,
                              productid         in product.product_id%type,
                              sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                              finishingmethodid in finishingmethod.finishingmethod_id%type,
                              pricedate         in pricelistpercustomer.dateactive%type default null)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function Budget_Price
     Use this function in calculations. It will return price 0.00 in case the price could not be found.
  */
  function Budget_Price (
       FPcustomerid customerbudgetdefinition.customer_id%type,
       FPcode       customerbudgetdefinition.code%type,
       FPreferencedate   date
       )
  return number;

  function Customer_Uses_SpecialPrices(customerid in customer.customer_id%type) return boolean;
  function Get_Standard_SzBillingGroup return number;
  function Get_Product_Size_Billinggroup(productid in product.product_id%type,
                                         sizeid    in sizedefinition.sizedefinition_id%type) return number;
  procedure Get_Size_Billing_Groups(customerid                     in customer.customer_id%type,
                                    productid                      in product.product_id%type,
                                    sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                    pricetype                      number, 
                                    lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                    lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type);
end PACK_PRICE_OLD;

/
create or replace PACKAGE BODY PACK_PRICE_OLD is

  procedure Get_Rent_Price_Details(customerid             in customer.customer_id%type,
                                  productid              in product.product_id%type,
                                  sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                  finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                  pricedate              in pricelistpercustomer.dateactive%type,
                                  chgperwk_or_freq       in generalrentprice.changesperweek%type,
                                  price                  out customerrentprice.price%type,
                                  price_found_yn         out varchar2,
                                  price_start_date       out customerrentprice.startdate%type,
                                  result_code            out number,
                                  result_desc            out varchar2,
                                  price_list_type        out varchar2,
                                  price_list_code        out generalpricelist.code%type,
                                  price_list_desc        out generalpricelist.description%type,
                                  changesperwkfoundprice out customerrentprice.changesperweek%type,
                                  price_type_code        out customerrentprice.typeofrent%type,
                                  price_type_desc        out varchar2,
                                  inv_freq_code          out customerrentprice.invoicefrequencynumber%type,
                                  inv_freq_desc          out varchar2,
                                  customerrentpriceid    out customerrentprice.customerrentprice_id%type) is

    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_changesperweek           customerrentprice.changesperweek%type;
    lv_changesperweekfound      customerrentprice.changesperweek%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_frequencybased           productlistpercustomer.rentpriceperfrequency%type;
    --PVD added
    lv_minimumturnaround        productlistpercustomer.minimumturnaround%type;
    lv_businessunitid           businessunit.businessunit_id%type;
    lv_underuse_count           number;
    lv_databasecode             databasesettings.code%type;
    --
    lv_customergarmrentspec     customer.garmentrentspecification%type;
    lv_pricelist_type           varchar2(1);
    lv_invfreqbasedprice        productlistpercustomer.invoicefreqrelatedrentprice%type;
    lv_custsplitinvperactivity  customer.splitinvoicesperactivity%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_typeofrent               customerrentprice.typeofrent%type;
    lv_typeofrent_general       customerrentprice.typeofrent%type;
    lv_typeofrent_specific      customerrentprice.typeofrent%type;
    lv_invoice_freq             customerrentprice.invoicefrequencynumber%type;
    lv_productgroup_id          product.productgroup_id%type;
    lv_custrentpriceid          customerrentprice.customerrentprice_id%type;
    lv_price                    customerrentprice.price%type;
    lv_price_start_date         customerrentprice.startdate%type;
    lv_generalpricelistid       generalrentprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;
    lv_standard_sizeBillingGroupID sizebillinggroup.sizebillinggroup_id%type;
    lv_initial_specific_sizeBillingGroupID sizebillinggroup.systemuser_id%type;
    lv_specific_sizeBillingGroupID sizebillinggroup.systemuser_id%type;
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'Y1',
                    'Multiple prices can be applicable for different # of changes',
                    'Y2',
                    'Multiple prices can be applicable for different frequencies',
                    'N1',
                    'Price not defined',
                    'N2',
                    'Price not relevant, billing method 3 with wash price only',
                    'N3',
                    'Price not relevant, billing method = 4 piece rate only',
                    'N4',
                    'Price not relevant, defined at wearer level as wearer total price',
                    'N5',
                    'Price not relevant, defined at wearer function level',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

    function decode_inv_freq(fpfreq_code in varchar2) return varchar2 is
    begin
      case fpfreq_code
        when '40' then
          return('4 Weekly');
        when '110' then
          return('Monthly');
        else
          return('Weekly');
      end case;
    end;

    function decode_type_of_rent(fptypeofrent in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fptypeofrent,
                    1,
                    'Price per Piece',
                    2,
                    'Changes per Week',
                    3,
                    'Overuse Price',
                    4,
                    'Frequency Based Price',
                    5,
                    'Underuse Price',
                    6,
                    'Lease Price',
                    7,
                    'Split Price',
                    8,
                    'Price per Invoice Freq.',
                    'Unknown type of rent')
        into r
        from dual;
      return r;
    end;     

  begin -- main rent price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    changesperwkfoundprice := null;
    price_type_code        := null;
    price_type_desc        := null;
    inv_freq_code          := null;
    inv_freq_desc          := null;

    select db.code
    into lv_databasecode
    from databasesettings db;

    get_size_billing_groups(customerid, productid, sizedefinitionid, 2, lv_standard_sizeBillingGroupID, lv_initial_specific_sizeBillingGroupID);
    lv_specific_sizeBillingGroupID := lv_initial_specific_sizeBillingGroupID;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size           := sizedefinitionid;
    lv_finmethod      := finishingmethodid;
--    lv_changesperweek := chgperwk_or_freq;  HVH 08/01/2010 change moved inside outer loop
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 2
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      lv_changesperweek           := chgperwk_or_freq;  -- HVH 08/01/2010 moved from outside loop
      -- load billingmethod etc to determine price usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_priceusage               := null;
      lv_invoice_freq             := 10; -- default is weekly
      lv_custsplitinvperactivity  := null;
      lv_minimumturnaround        := null;
      open Vcsr for
        select plpc.productlistpercustomer_id,
               plpc.billingmethod,
               plpc.priceusage,
               plpc.invoicefreqrelatedrentprice,
               plpc.rentpriceperfrequency,
               p.typeofmerchandise,
               p.productgroup_id,
               c.garmentrentspecification,
               c.splitinvoicesperactivity,
               --PVD added
               plpc.minimumturnaround,
               C.DEFAULTBUSINESSUNIT_ID
          from productlistpercustomer plpc, product p, customer c
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and p.product_id = productid
           and c.customer_id = customerid
           and plpc.sizedefinition_id = lv_size
           and plpc.finishingmethod_id = lv_finmethod
           and ((lv_pricedate >= plpc.dateactive and lv_pricedate <= plpc.dateinactive) or i>2)
           -- only filter on active in iteration 3 and 4
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_invfreqbasedprice,
               lv_frequencybased, lv_typeofmerchandize, lv_productgroup_id, lv_customergarmrentspec,
               lv_custsplitinvperactivity, lv_minimumturnaround, lv_businessunitid;
        if lv_billingmethod = 3 and lv_priceusage = 3 then /*wash only*/
          price_not_relevant := true;
          result_code        := 2; -- Price not relevant, billing method with wash price only
        end if;
        if lv_billingmethod = 4 then
          price_not_relevant := true;
          result_code        := 3; -- Price not relevant, billing method = 4 piece rate only
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize=2 and lv_customergarmrentspec=5 then -- total wearer price
          price_not_relevant := true;
          result_code        := 4; -- Price not relevant, wearer total price
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize=2 and lv_customergarmrentspec=6 then -- wearer function price
          price_not_relevant := true;
          result_code        := 5; -- Price not relevant, wearer function price
        end if;
        if (not price_found) and (not price_not_relevant) then
          lv_typeofrent := 1;
          if lv_billingmethod = 1 and lv_typeofmerchandize = 2 -- changes per week
           then
            lv_typeofrent := 2; -- changes per week
           else
            if lv_billingmethod = 1 and lv_typeofmerchandize <> 2 and lv_frequencybased='Y'
              then lv_typeofrent := 4;  -- frequency based
              else lv_changesperweek := 0;
            end if; -- frequency based=Y
          end if; -- changes/week
          if lv_billingmethod = 3 and lv_priceusage=1 /* split */
            then lv_typeofrent := 7; -- split
          end if;
          if lv_billingmethod = 5
            then lv_typeofrent := 6; -- lease
          end if;
          --PVD add underuse
          if lv_billingmethod = 2 and lv_minimumturnaround <> 0 and lv_databasecode <> 'AMM' then
            --check_underuse
            select count(1)
            into   lv_underuse_count
            from   systemsetting st
            join   businessunit bu
            on     bu.plant_id = st.plant_id
            where  st.name = 'UNDERUSEMETHOD'
            and    st.value in ('2', '4')
            and    bu.businessunit_id = lv_businessunitid;
            if lv_underuse_count > 0 then
              --underuse
              lv_typeofrent := 5;
            end if;
          end if;
          --
          if lv_billingmethod = 3 and lv_invfreqbasedprice = 'Y' and lv_custsplitinvperactivity='Y' then
            lv_typeofrent := 8;
            -- determine invoice frequency. Take lowest frequency,(to avoid BU determination) assuming that
            -- an activity for a customer is processed in only 1 plant,
            -- or if in multiple they have the same invoice frequency.
            select min(freq.invoicefrequencynumber) -- take lowest freq.
              into lv_invoice_freq
              from customeractivities ca,
                   invoicefrequency   freq,
                   productgroup       pg
             where ca.customer_id = customerid
               and ca.activity_id = pg.activity_id
               and pg.productgroup_id = lv_productgroup_id
               and freq.invoicefrequency_id = ca.invoicefrequency_id;
            if lv_invoice_freq < 100 and lv_invoice_freq <> 40 then
              lv_invoice_freq := 10;
            end if;
            if lv_invoice_freq > 100 then
              lv_invoice_freq := 110;
            end if;
          end if;
          lv_typeofrent_general := lv_typeofrent;
          lv_typeofrent_specific := lv_typeofrent;
          /*
          if lv_typeofrent_specific = 7 -- split
            then lv_typeofrent_specific := 1;
          end if;
          */
        end if;
      end if;
      close Vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            if lv_changesperweek = 0 -- no specific changes passed, take most recent active price
             then
              open Vcsr for
                select x.*, rownum
                  from (select grp.price,
                               grp.startdate,
                               grp.changesperweek,
                               g.code,
                               g.description
                          from generalrentprice grp, generalpricelist g
                         where g.generalpricelist_id = lv_generalpricelistid
                           and g.pricetype = 2
                           and g.active = 'Y'
                           and grp.generalpricelist_id = g.generalpricelist_id
                           and grp.product_id = productid
                           and grp.sizedefinition_id = lv_size
                           and grp.finishingmethod_id = lv_finmethod
                           and grp.typeofrent = lv_typeofrent_general
                           and grp.startdate <= lv_pricedate
                           and (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent_general <> 8)
                           and nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                         order by grp.startdate desc, grp.changesperweek asc) x
/* HVH I would have found more logical most recent price for smallest number of changes, this would
       then automatically choose size * if defined.
                         order by grp.changesperweek asc, grp.startdate desc) x  */
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_changesperweekfound, lv_pricelist_code, lv_pricelist_desc, dummy;
              close Vcsr;
            else
              -- specific number of changes passed, try that first, if not found try changes * (-1)
              open Vcsr for
                select x.*, rownum
                  from (select grp.price,
                               grp.startdate,
                               grp.changesperweek,
                               g.code,
                               g.description
                          from generalrentprice grp, generalpricelist g
                         where g.generalpricelist_id = lv_generalpricelistid
                           and g.pricetype = 2
                           and g.active = 'Y'
                           and grp.generalpricelist_id = g.generalpricelist_id
                           and grp.product_id = productid
                           and grp.sizedefinition_id = lv_size
                           and grp.finishingmethod_id = lv_finmethod
                           and grp.typeofrent = lv_typeofrent_general
                           and grp.changesperweek = lv_changesperweek
                           and grp.startdate <= lv_pricedate
                           and (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent_general <> 8)
                           and nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                         order by grp.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_changesperweekfound, lv_pricelist_code, lv_pricelist_desc, dummy;
              close Vcsr;
              if lv_price is null and lv_typeofrent_general = 2 then
                -- price for exact number of changes not found$, try changes / week = -1 (*)
                open Vcsr for
                  select x.*, rownum
                    from (select grp.price,
                                 grp.startdate,
                                 grp.changesperweek,
                                 g.code,
                                 g.description
                            from generalrentprice grp, generalpricelist g
                           where g.generalpricelist_id = lv_generalpricelistid
                             and g.pricetype = 2
                             and g.active = 'Y'
                             and grp.generalpricelist_id = g.generalpricelist_id
                             and grp.product_id = productid
                             and grp.sizedefinition_id = lv_size
                             and grp.finishingmethod_id = lv_finmethod
                             and grp.typeofrent = lv_typeofrent_general
                             and grp.changesperweek = -1
                             and (grp.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent_general <> 8)
                             and nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                           order by grp.startdate desc) x
                   where rownum = 1; -- take first
                fetch Vcsr
                  into lv_price, lv_price_start_date, lv_changesperweekfound, lv_pricelist_code, lv_pricelist_desc, dummy;
                close Vcsr;
              end if; -- lv_price is null
            end if; -- lv_changesperweek = 0
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            if lv_changesperweek = 0 -- no specific changes passed, take most recent active price
             then
              open Vcsr for
                select x.*, rownum
                  from (select cupri.price,
                               cupri.startdate,
                               cupri.changesperweek,
                               cupri.customerrentprice_id
                          from customerrentprice cupri
                         where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                           and cupri.startdate <= lv_pricedate
                           and cupri.typeofrent = lv_typeofrent_specific
                           and (cupri.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent_specific <> 8)
                           and nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                         order by cupri.startdate desc, cupri.changesperweek asc) x
/* HVH I would have found more logical most recent price for smallest number of changes, this would
       then automatically choose size * if defined.
                         order by cupri.changesperweek asc, cupri.startdate desc) x  */
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_changesperweekfound, lv_custrentpriceid, dummy;
              close Vcsr;
            else
              -- specific number of changes passed, try that first, if not found try changes * (-1)
              open Vcsr for
                select x.*, rownum
                  from (select cupri.price,
                               cupri.startdate,
                               cupri.changesperweek,
                               cupri.customerrentprice_id
                          from customerrentprice cupri
                         where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                           and cupri.startdate <= lv_pricedate
                           and cupri.typeofrent = lv_typeofrent_specific
                           and cupri.changesperweek = lv_changesperweek
                           and (cupri.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent_specific <> 8)
                           and nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                         order by cupri.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_changesperweekfound, lv_custrentpriceid, dummy;
              close Vcsr;
              if lv_price is null and lv_typeofrent_specific = 2 then
                -- price for exact number of changes not found$, try changes / week = -1 (*)
                open Vcsr for
                  select x.*, rownum
                    from (select cupri.price,
                                 cupri.startdate,
                                 cupri.changesperweek,
                                 cupri.customerrentprice_id
                            from customerrentprice cupri
                           where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                             and cupri.startdate <= lv_pricedate
                             and cupri.typeofrent = lv_typeofrent_specific
                             and cupri.changesperweek = -1
                             and (cupri.invoicefrequencynumber = lv_invoice_freq or lv_typeofrent_specific <> 8)
                             and nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                           order by cupri.startdate desc) x
                   where rownum = 1; -- take first
                fetch Vcsr
                  into lv_price, lv_price_start_date, lv_changesperweekfound, lv_custrentpriceid, dummy;
                close Vcsr;
              end if; -- lv_price is null
            end if; -- lv_changesperweek = 0
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- select original size again and try for an inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
      if i = 5 and lv_specific_sizeBillingGroupID <> lv_standard_sizeBillingGroupID and lv_specific_sizeBillingGroupID = lv_initial_specific_sizeBillingGroupID then
        i := 1; -- if the price was not found for the productsize.sizebillinggroup, then try for the standard
        lv_specific_sizeBillingGroupID := lv_standard_sizeBillingGroupID;
        lv_size := sizedefinitionid;
      end if;
      if i = 5 and lv_specific_sizeBillingGroupID = lv_standard_sizeBillingGroupID and lv_standard_sizeBillingGroupID <> 0 and lv_initial_specific_sizeBillingGroupID <> 0 then
        i := 1; -- if the price was not found for the productsize.sizebillinggroup, then try for the price without sizebillinggroup
        lv_specific_sizeBillingGroupID := 0;
        lv_size := sizedefinitionid;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      customerrentpriceid := lv_custrentpriceid;
      if chgperwk_or_freq=0 then
        case lv_typeofrent
          when 2 then result_code := '1'; -- when typeofrent is chgsperweek return result code about multiple prices possible
          when 4 then result_code := '2'; -- when typeofrent is frequency return result code about multiple prices possible
          else result_code := '0';
        end case;
      else result_code := '0';
      end if;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
      if lv_typeofrent in (2,4) then -- changes per week or frequency based
        changesperwkfoundprice := lv_changesperweekfound;
      end if;
      price_type_code := lv_typeofrent;
      price_type_desc := decode_type_of_rent(price_type_code);
      inv_freq_code   := lv_invoice_freq;
      inv_freq_desc   := decode_inv_freq(inv_freq_code);
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Rent_Price_details;

/*--------------------------------------------------------------------------------------------------------*/
function Rent_Price_Details(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null,
                            chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
 return varchar2 is
  /* See package header for description of return string.   */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    changesperwkfoundprice  customerrentprice.changesperweek%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);
    inv_freq_code           customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc           varchar2(10);
    customerrentpriceid     customerrentprice.customerrentprice_id%type;

    begin
      Get_Rent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             chgperwk_or_freq,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             changesperwkfoundprice,
                             price_type_code,
                             price_type_desc,
                             inv_freq_code,
                             inv_freq_desc,
                             customerrentpriceid);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(to_char(price_type_code), ' '), 1) ||
             rpad(nvl(price_type_desc, ' '), 30) ||
             rpad(nvl(to_char(inv_freq_code), ' '), 1) ||
             rpad(nvl(inv_freq_desc, ' '), 10) ||
             lpad(nvl(to_char(changesperwkfoundprice), ' '), 10) ||
             rpad(nvl(to_char(customerrentpriceid), ' '), 1) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
             );
    end Rent_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
function Rent_Price(customerid        in customer.customer_id%type,
                    productid         in product.product_id%type,
                    sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                    finishingmethodid in finishingmethod.finishingmethod_id%type,
                    pricedate         in pricelistpercustomer.dateactive%type default null,
                    chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
 return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    changesperwkfoundprice  customerrentprice.changesperweek%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);
    inv_freq_code           customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc           varchar2(10);
    customerrentpriceid     customerrentprice.customerrentprice_id%type;

    begin
      Get_Rent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             chgperwk_or_freq,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             changesperwkfoundprice,
                             price_type_code,
                             price_type_desc,
                             inv_freq_code,
                             inv_freq_desc,
                             customerrentpriceid);
      return(nvl(price,0));
    end Rent_Price;

/*--------------------------------------------------------------------------------------------------------*/
function CustomerRent_PriceID(customerid        in customer.customer_id%type,
                    productid         in product.product_id%type,
                    sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                    finishingmethodid in finishingmethod.finishingmethod_id%type,
                    pricedate         in pricelistpercustomer.dateactive%type default null,
                    chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
 return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    changesperwkfoundprice  customerrentprice.changesperweek%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);
    inv_freq_code           customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc           varchar2(10);
    customerrentpriceid     customerrentprice.customerrentprice_id%type;

    begin
      Get_Rent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             chgperwk_or_freq,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             changesperwkfoundprice,
                             price_type_code,
                             price_type_desc,
                             inv_freq_code,
                             inv_freq_desc,
                             customerrentpriceid);
      return(nvl(customerrentpriceid,0));
    end CustomerRent_PriceID;

/*--------------------------------------------------------------------------------------------------------*/
function Rent_Price_Display(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null,
                            chgperwk_or_freq  in generalrentprice.changesperweek%type default 0)
 return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    changesperwkfoundprice  customerrentprice.changesperweek%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);
    inv_freq_code           customerrentprice.invoicefrequencynumber%type;
    inv_freq_desc           varchar2(10);
    customerrentpriceid     customerrentprice.customerrentprice_id%type;

    begin
      Get_Rent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             chgperwk_or_freq,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             changesperwkfoundprice,
                             price_type_code,
                             price_type_desc,
                             inv_freq_code,
                             inv_freq_desc,
                             customerrentpriceid);
      return(price);
    end Rent_Price_Display;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Wash_Price_Details(customerid             in customer.customer_id%type,
                                   productid              in product.product_id%type,
                                   sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   pricedate              in pricelistpercustomer.dateactive%type,
                                   pricetype              in number, -- 0=all, 1=LOG, 2=COG
                                   price                  out customerwashprice.price%type,
                                   price_found_yn         out varchar2,
                                   price_start_date       out customerwashprice.startdate%type,
                                   result_code            out number,
                                   result_desc            out varchar2,
                                   price_list_type        out varchar2,
                                   price_list_code        out generalpricelist.code%type,
                                   price_list_desc        out generalpricelist.description%type,
                                   price_type_code        out customerwashprice.pricetype%type,
                                   price_type_desc        out varchar2) is

    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_chargewashonlycog        productlistpercustomer.chargewashesonlyforcog%type;
    --PVD added
    lv_minimumturnaround        productlistpercustomer.minimumturnaround%type;
    --RVI added
    lv_businessunitid           businessunit.businessunit_id%type;
    lv_underuse_count           number;
    --
    lv_pricelist_type           varchar2(1);
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_pricetype                customerwashprice.pricetype%type;
    lv_pricetype_gen_prlist     generalwashprice.pricetype%type;
    lv_found_pricetype          customerwashprice.pricetype%type;
    lv_price                    customerwashprice.price%type;
    lv_price_start_date         customerwashprice.startdate%type;
    lv_generalpricelistid       generalwashprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'Y1',
                    'Distinct prices can be applicable LOG and COG',
                    'N1',
                    'Price not defined',
                    'N2',
                    'Price not relevant, billing method 3 with rent price only',
                    'N3',
                    'Price not relevant, billing method = 1 flat rated rent',
                    'N4',
                    'Price not relevant, billing method = 2 rent based on minimum',
                    'N5',
                    'Price not relevant, disposable / sales only item',
                    'N6',
                    'Price not relevant, billing method = 4 with price for LOG only',
                    'N7',
                    'Price not relevant, billing method = 4 with price for COG only',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

    function decode_price_type(fppricetype in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fppricetype,
                    1,
                    'All (COG or LOG)',
                    2,
                    'COG Only',
                    4,
                    'Split Price',
                    'Unknown price type')
        into r
        from dual;
      return r;
    end;

  begin -- main wash price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    price_type_code        := null;
    price_type_desc        := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size           := sizedefinitionid;
    lv_finmethod      := finishingmethodid;
    lv_pricetype      := 1;
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) or (pricetype is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 1 -- Wash
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      -- load billingmethod etc to determine price usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_priceusage               := null;
      lv_chargewashonlycog        := null;
      lv_typeofmerchandize        := null;
      lv_minimumturnaround        := null;
      open Vcsr for
        select plpc.productlistpercustomer_id,
               plpc.billingmethod,
               plpc.priceusage,
               plpc.chargewashesonlyforcog,
               p.typeofmerchandise,
               --PVD added extra check
               plpc.minimumturnaround,
               -- RVI added
               c.defaultbusinessunit_id
          from productlistpercustomer plpc, product p
               -- RVI added
               , customer c
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and p.product_id = productid
           -- RVI added
           and c.customer_id = customerid
           --
           and plpc.sizedefinition_id = lv_size
           and plpc.finishingmethod_id = lv_finmethod
           and ((lv_pricedate >= plpc.dateactive and lv_pricedate <= plpc.dateinactive) or i>2)
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_chargewashonlycog, lv_typeofmerchandize, lv_minimumturnaround
          -- RVI added
          , lv_businessunitid
          ---
          ;
        if lv_billingmethod = 3 and lv_priceusage = 2 then /* rent price only*/
          price_not_relevant := true;
          result_code        := 2; -- Price not relevant, billing method 3 with rent price only
        end if;
        if lv_billingmethod = 1 and not (lv_chargewashonlycog=3 and pricetype=2) then
          price_not_relevant := true;
          result_code        := 3; -- Price not relevant, billing method = 1 flat rated rent only
        end if;
/*        if lv_billingmethod = 2 and lv_minimumturnaround = 0 then
          price_not_relevant := true;
          result_code        := 4; -- Price not relevant, billing method = 2 rent based on minimum
        end if;
*/
        -- RVI added
        if lv_billingmethod = 2 then
          -- Determine system setting UNDERUSEMETHOD
          select count(1)
          into   lv_underuse_count
          from   systemsetting st
          join   businessunit bu
          on     bu.plant_id = st.plant_id
          where  st.name = 'UNDERUSEMETHOD'
          and    st.value = '2'
          and    bu.businessunit_id = lv_businessunitid;
          -- Only for UNDERUSEMETHOD = 2 the MinimumTurnaround must be > 0
          if lv_underuse_count > 0 and lv_minimumturnaround = 0 then
            price_not_relevant := true;
            result_code        := 4; -- Price not relevant, billing method = 2 rent based on minimum
          end if;
        end if;
        ----
        if lv_typeofmerchandize = 3 then
          price_not_relevant := true;
          result_code        := 5; -- Price not relevant, disposable or sales only item.
        end if;
        if lv_billingmethod = 4 and lv_typeofmerchandize <> 3 and
           lv_chargewashonlycog = 2 /*LOG Only*/ and pricetype = 2 /*COG Only*/ then
          price_not_relevant := true;
          result_code        := 6; -- Price not relevant, billing method = 4 with for LOG only
        end if;
        if lv_billingmethod = 4 and lv_typeofmerchandize <> 3 and
           lv_chargewashonlycog = 3 /*COG Only*/ and pricetype = 1 /*LOG Only*/ then
          price_not_relevant := true;
          result_code        := 7; -- Price not relevant, billing method = 4 with for COG only
        end if;
        if (not price_found) and (not price_not_relevant) then
          lv_pricetype := 1; -- All
          if pricetype=2 and  -- COG
             lv_billingmethod in (3,4) and
             lv_chargewashonlycog in (1,3) and /* separate price for COG/LOG,  or COG only */
             lv_priceusage <> 1 /* split */ then
            lv_pricetype := 2; -- COG only
          end if;
          if pricetype=0 and  -- all
             lv_billingmethod=4 and
             lv_chargewashonlycog = 3 then /* COG only */
            lv_pricetype := 2; -- COG only
          end if;
          if lv_billingmethod = 1 and lv_chargewashonlycog = 3 and pricetype=2 then
            lv_pricetype := 2; -- COG only
          end if;
        end if;
      end if;
      close Vcsr;
      if lv_billingmethod=3 and lv_priceusage=1 -- split
       then lv_pricetype_gen_prlist := 4;
       else lv_pricetype_gen_prlist := lv_pricetype;
      end if;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        if lv_generalpricelistid is not null then  -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            if pricetype=0 -- not specified LOG or COG take most recent active price
            and lv_pricetype_gen_prlist <> 4 -- for split price always look for split prices
            and not (lv_billingmethod=4 and lv_chargewashonlycog = 3) -- for COG only look only for COG prices
             then
              open Vcsr for
                select x.*, rownum
                  from (select gwp.price,
                               gwp.startdate,
                               gwp.pricetype,
                               g.code,
                               g.description
                          from generalwashprice gwp, generalpricelist g
                         where g.generalpricelist_id = lv_generalpricelistid
                           and g.pricetype = 1 -- Wash
                           and g.active = 'Y'
                           and gwp.generalpricelist_id = g.generalpricelist_id
                           and gwp.product_id = productid
                           and gwp.sizedefinition_id = lv_size
                           and gwp.finishingmethod_id = lv_finmethod
                           and gwp.startdate <= lv_pricedate
                           and (gwp.pricetype <> 4 or lv_billingmethod <> 4) -- don't select split prices for BM 4
                         order by gwp.startdate desc, gwp.pricetype asc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_found_pricetype, lv_pricelist_code, lv_pricelist_desc, dummy;
              close Vcsr;
            else -- LOG or COG is specifically specified.
              open Vcsr for
                select x.*, rownum
                  from (select gwp.price,
                               gwp.startdate,
                               gwp.pricetype,
                               g.code,
                               g.description
                          from generalwashprice gwp, generalpricelist g
                         where g.generalpricelist_id = lv_generalpricelistid
                           and g.pricetype = 1 -- Wash
                           and g.active = 'Y'
                           and gwp.generalpricelist_id = g.generalpricelist_id
                           and gwp.product_id = productid
                           and gwp.sizedefinition_id = lv_size
                           and gwp.finishingmethod_id = lv_finmethod
                           and gwp.startdate <= lv_pricedate
                           and gwp.pricetype = lv_pricetype_gen_prlist
                         order by gwp.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date,lv_found_pricetype,lv_pricelist_code, lv_pricelist_desc, dummy;
              close Vcsr;
            end if; -- pricetype = 0
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            if pricetype=0 -- not specified LOG or COG take most recent active price
             then
              open Vcsr for
                select x.*, rownum
                  from (select cupri.price,
                               cupri.startdate,
                               cupri.pricetype
                          from customerwashprice cupri
                         where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                           and cupri.startdate <= lv_pricedate
                           and cupri.pricetype = lv_pricetype
                         order by cupri.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_found_pricetype, dummy;
              close Vcsr;
            else -- LOG or COG is specifically specified.
              open Vcsr for
                select x.*, rownum
                  from (select cupri.price,
                               cupri.startdate,
                               cupri.pricetype
                          from customerwashprice cupri
                         where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                           and cupri.startdate <= lv_pricedate
                           and cupri.pricetype = lv_pricetype
                         order by cupri.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_found_pricetype, dummy;
              close Vcsr;
            end if;  -- pricetype = 0
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      close VPriceListperCust;
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      if pricetype=0 and lv_chargewashonlycog=1 -- separate price LOG/COG
        then result_code := '1';
        else result_code := '0';
      end if;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
      price_type_code := lv_found_pricetype;
      price_type_desc := decode_price_type(price_type_code);
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Wash_Price_details;


/*--------------------------------------------------------------------------------------------------------*/
function Wash_Price_Details(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null,
                            pricetype         in number default 0)
 return varchar2 is

  /* See package header for description of return string.   */

    price                   customerwashprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerwashprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerwashprice.pricetype%type;
    price_type_desc         varchar2(30);


    begin
      Get_Wash_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             pricetype,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             price_type_code,
                             price_type_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(to_char(price_type_code), ' '), 1) ||
             rpad(nvl(price_type_desc, ' '), 30) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
             );
    end Wash_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
function Wash_Price(customerid        in customer.customer_id%type,
                    productid         in product.product_id%type,
                    sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                    finishingmethodid in finishingmethod.finishingmethod_id%type,
                    pricedate         in pricelistpercustomer.dateactive%type default null,
                    pricetype         in number default 0)
 return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerwashprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerwashprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerwashprice.pricetype%type;
    price_type_desc         varchar2(30);

    begin
      Get_Wash_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             pricetype,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             price_type_code,
                             price_type_desc);
      return(nvl(price,0));
    end Wash_Price;

/*--------------------------------------------------------------------------------------------------------*/
function Wash_Price_Display(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null,
                            pricetype         in number default 0)
return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customerwashprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerwashprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerwashprice.pricetype%type;
    price_type_desc         varchar2(30);

    begin
      Get_Wash_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             pricetype,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             price_type_code,
                             price_type_desc);
      return(price);
    end Wash_Price_Display;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Wash_Price_Details_PT(customerid             in customer.customer_id%type,
                                      productid              in product.product_id%type,
                                      sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                      pricedate              in pricelistpercustomer.dateactive%type,
                                      pricetype              in number,
                                      price                  out customerwashprice.price%type,
                                      price_found_yn         out varchar2,
                                      price_start_date       out customerwashprice.startdate%type,
                                      result_code            out number,
                                      result_desc            out varchar2,
                                      price_list_type        out varchar2,
                                      price_list_code        out generalpricelist.code%type,
                                      price_list_desc        out generalpricelist.description%type,
                                      price_type_code        out customerwashprice.pricetype%type,
                                      price_type_desc        out varchar2) is

    price_found                 boolean;
--    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_pricelist_type           varchar2(1);
    lv_pricetype                customerwashprice.pricetype%type;
    lv_pricetype_gen_prlist     generalwashprice.pricetype%type;
    lv_found_pricetype          customerwashprice.pricetype%type;
    lv_price                    customerwashprice.price%type;
    lv_price_start_date         customerwashprice.startdate%type;
    lv_generalpricelistid       generalwashprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'N1',
                    'Price not defined',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

    function decode_price_type(fppricetype in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fppricetype,
                    1,
                    'All (COG or LOG)',
                    2,
                    'COG Only',
                    3,
                    'Price on Client Delivery Note',
                    4,
                    'Split Price',
                    5,
                    'Heavy Soil',
                    'Unknown price type')
        into r
        from dual;
      return r;
    end;

  begin -- main wash price for specified price type
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    price_type_code        := null;
    price_type_desc        := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size           := sizedefinitionid;
    lv_finmethod      := finishingmethodid;
    lv_pricetype      := pricetype;
    lv_pricetype_gen_prlist := pricetype;
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) or (pricetype is null) or (pricetype = 0) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 1 -- Wash
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      -- load plpc ID
      lv_productlistpercustomerid := null;
      open Vcsr for
        select plpc.productlistpercustomer_id
          from productlistpercustomer plpc, product p
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and p.product_id = productid
           and plpc.sizedefinition_id = lv_size
           and plpc.finishingmethod_id = lv_finmethod
           and ((lv_pricedate >= plpc.dateactive and lv_pricedate <= plpc.dateinactive) or i>2)
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid;
      end if;
      close Vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) loop
        if lv_generalpricelistid is not null then  -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select gwp.price,
                             gwp.startdate,
                             gwp.pricetype,
                             g.code,
                             g.description
                        from generalwashprice gwp, generalpricelist g
                       where g.generalpricelist_id = lv_generalpricelistid
                         and g.pricetype = 1 -- Wash
                         and g.active = 'Y'
                         and gwp.generalpricelist_id = g.generalpricelist_id
                         and gwp.product_id = productid
                         and gwp.sizedefinition_id = lv_size
                         and gwp.finishingmethod_id = lv_finmethod
                         and gwp.startdate <= lv_pricedate
                         and gwp.pricetype = lv_pricetype_gen_prlist
                       order by gwp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date,lv_found_pricetype,lv_pricelist_code, lv_pricelist_desc, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.price,
                             cupri.startdate,
                             cupri.pricetype
                        from customerwashprice cupri
                       where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                         and cupri.startdate <= lv_pricedate
                         and cupri.pricetype = lv_pricetype
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_found_pricetype, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := 0;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
      price_type_code := lv_found_pricetype;
      price_type_desc := decode_price_type(price_type_code);
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || to_char(result_code));
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || to_char(result_code));
    when others then
      result_code := 9;
      result_desc := decode_error('N' || to_char(result_code)) || sqlerrm; -- ora error
  end Get_Wash_Price_details_PT;


/*--------------------------------------------------------------------------------------------------------*/
function Wash_Price_Details_PT(customerid        in customer.customer_id%type,
                               productid         in product.product_id%type,
                               sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                               finishingmethodid in finishingmethod.finishingmethod_id%type,
                               pricedate         in pricelistpercustomer.dateactive%type default null,
                               pricetype         in number)
 return varchar2 is

  /* See package header for description of return string.   */

    price                   customerwashprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerwashprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerwashprice.pricetype%type;
    price_type_desc         varchar2(30);


    begin
      Get_Wash_Price_Details_PT(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                pricedate,
                                pricetype,
                                price,
                                price_found_yn,
                                price_start_date,
                                result_code,
                                result_desc,
                                price_list_type,
                                price_list_code,
                                price_list_desc,
                                price_type_code,
                                price_type_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(to_char(price_type_code), ' '), 1) ||
             rpad(nvl(price_type_desc, ' '), 30) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
             );
    end Wash_Price_Details_PT;

/*--------------------------------------------------------------------------------------------------------*/
function Wash_Price_PT(customerid        in customer.customer_id%type,
                       productid         in product.product_id%type,
                       sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                       finishingmethodid in finishingmethod.finishingmethod_id%type,
                       pricedate         in pricelistpercustomer.dateactive%type default null,
                       pricetype         in number)
 return number is
  /* Returns the wash price for the specified pricetype, if not found, returns 0.  For use in calculations.  */

    price                   customerwashprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerwashprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerwashprice.pricetype%type;
    price_type_desc         varchar2(30);

    begin
      Get_Wash_Price_Details_PT(customerid,
                               productid,
                               sizedefinitionid,
                               finishingmethodid,
                               pricedate,
                               pricetype,
                               price,
                               price_found_yn,
                               price_start_date,
                               result_code,
                               result_desc,
                               price_list_type,
                               price_list_code,
                               price_list_desc,
                               price_type_code,
                               price_type_desc);
      return(nvl(price,0));
    end Wash_Price_PT;

/*--------------------------------------------------------------------------------------------------------*/
function Wash_Price_Display_PT(customerid        in customer.customer_id%type,
                               productid         in product.product_id%type,
                               sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                               finishingmethodid in finishingmethod.finishingmethod_id%type,
                               pricedate         in pricelistpercustomer.dateactive%type default null,
                               pricetype         in number)
return number is
  /* Returns the wash price for the specified pricetype, if not found, returns null. For display/print purposes. */

    price                   customerwashprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerwashprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerwashprice.pricetype%type;
    price_type_desc         varchar2(30);

    begin
     Get_Wash_Price_Details_PT(customerid,
                               productid,
                               sizedefinitionid,
                               finishingmethodid,
                               pricedate,
                               pricetype,
                               price,
                               price_found_yn,
                               price_start_date,
                               result_code,
                               result_desc,
                               price_list_type,
                               price_list_code,
                               price_list_desc,
                               price_type_code,
                               price_type_desc);
      return(price);
    end Wash_Price_Display_PT;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Replacement_Price_Details(customerid             in customer.customer_id%type,
                                          productid              in product.product_id%type,
                                          sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                          finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                          pricedate              in pricelistpercustomer.dateactive%type,
                                          price                  out customerreplacementprice.price%type,
                                          price_found_yn         out varchar2,
                                          price_start_date       out customerreplacementprice.startdate%type,
                                          result_code            out number,
                                          result_desc            out varchar2,
                                          price_list_type        out varchar2,
                                          price_list_code        out generalpricelist.code%type,
                                          price_list_desc        out generalpricelist.description%type) is

    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finishingmethod          finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_pricelist_type           varchar2(1);
    lv_price                    customerreplacementprice.price%type;
    lv_price_start_date         customerreplacementprice.startdate%type;
    lv_generalpricelistid       generalreplacementprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_typeofmerchandise        product.typeofmerchandise%type;
    lv_inventorybillingtype     productlistpercustomer.inventorybillingtype%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;
    lv_standard_sizeBillingGroupID         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizeBillingGroupID         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizeBillingGroupID sizebillinggroup.systemuser_id%type;
    lv_price_coefficient                   number;
    lv_chargelossforpool_yn     productlistpercustomer.chargelossforpool%type;
    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'N1',
                    'Price not defined',
                    'N2',
                    'Price not relevant, billingmethod is 4 piece rate only',
                    'N3',
                    'Price not relevant, disposable / sales only item',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main replacement
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;

    get_size_billing_groups(customerid, productid, sizedefinitionid, 3, lv_standard_sizeBillingGroupID, lv_initial_specific_sizeBillingGroupID);
    lv_specific_sizeBillingGroupID := lv_initial_specific_sizeBillingGroupID;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size := sizedefinitionid;
    lv_finishingmethod := finishingmethodid;
    if (customerid is null) OR (productid is null) OR (sizedefinitionid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id, pricelistpercustomer.pricecoefficient
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 3 -- replacement price
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid, lv_price_coefficient;
      -- load billingmethod etc to determine price usage
      lv_billingmethod     := null;
      lv_typeofmerchandise := null;
      open Vcsr for
        select plpc.productlistpercustomer_id,
               plpc.billingmethod,
               p.typeofmerchandise,
               plpc.inventorybillingtype,
               plpc.chargelossforpool
          from productlistpercustomer plpc, product p
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and p.product_id = productid
           and plpc.sizedefinition_id = lv_size
           and (plpc.finishingmethod_id = lv_finishingmethod or lv_finishingmethod is null)  -- passing null for FM is allowed
           and ((lv_pricedate >= plpc.dateactive and
                 lv_pricedate <= plpc.dateinactive) or i>2)-- only filter on active during 1st 2 iterations
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_typeofmerchandise, lv_inventorybillingtype,lv_chargelossforpool_yn;
        if (lv_billingmethod = 4 and lv_chargelossforpool_yn <> 'Y') then /*piece rate only and no loss charges*/
          price_not_relevant := true;
          result_code        := 2; -- Price not relevant, billing method piece rate only
        end if;
        if lv_typeofmerchandise = 3 then /* disposable / sales only*/
          price_not_relevant := true;
          result_code        := 3; -- Price not relevant, disposable or sales only product
        end if;
      end if;
      close Vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select lv_price_coefficient * grp.price,
                             grp.startdate,
                             g.code,
                             g.description
                        from generalreplacementprice grp, generalpricelist g
                       where g.generalpricelist_id = lv_generalpricelistid
                         and g.pricetype = 3 -- replacement price
                         and g.active = 'Y'
                         and grp.generalpricelist_id = g.generalpricelist_id
                         and grp.product_id = productid
                         and grp.sizedefinition_id = lv_size
                         and grp.startdate <= lv_pricedate
                         and nvl(grp.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                       order by grp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.price,
                             cupri.startdate
                        from customerreplacementprice cupri
                       where cupri.customer_id = customerid
                         and cupri.product_id = productid
                         and cupri.sizedefinition_id = lv_size
                         and cupri.startdate <= lv_pricedate
                         and nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid, lv_price_coefficient; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- if in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- select original size again and try for an inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
      if i = 5 and lv_specific_sizeBillingGroupID <> lv_standard_sizeBillingGroupID and lv_specific_sizeBillingGroupID = lv_initial_specific_sizeBillingGroupID then
        i := 1; -- if the price was not found for the productsize.sizebillinggroup, then try for the standard
        lv_specific_sizeBillingGroupID := lv_standard_sizeBillingGroupID;
        lv_size := sizedefinitionid;
      end if;
      if i = 5 and lv_specific_sizeBillingGroupID = lv_standard_sizeBillingGroupID and lv_standard_sizeBillingGroupID <> 0 and lv_initial_specific_sizeBillingGroupID <> 0 then
        i := 1; -- if the price was not found for the productsize.sizebillinggroup, then try for the price without sizebillinggroup
        lv_specific_sizeBillingGroupID := 0;
        lv_size := sizedefinitionid;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Replacement_Price_details;

/*--------------------------------------------------------------------------------------------------------*/
  function Replacement_Price_Details(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    price                   customerreplacementprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerreplacementprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Replacement_Price_Details(customerid,
                                    productid,
                                    sizedefinitionid,
                                    finishingmethodid,
                                    pricedate,
                                    price,
                                    price_found_yn,
                                    price_start_date,
                                    result_code,
                                    result_desc,
                                    price_list_type,
                                    price_list_code,
                                    price_list_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
            );
    end Replacement_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function Replacement_Price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             finishingmethodid in finishingmethod.finishingmethod_id%type,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerreplacementprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerreplacementprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Replacement_Price_Details(customerid,
                                    productid,
                                    sizedefinitionid,
                                    finishingmethodid,
                                    pricedate,
                                    price,
                                    price_found_yn,
                                    price_start_date,
                                    result_code,
                                    result_desc,
                                    price_list_type,
                                    price_list_code,
                                    price_list_desc);
      return(nvl(price,0));
    end Replacement_Price;

/*--------------------------------------------------------------------------------------------------------*/
  function Replacement_Price_Display(customerid        in customer.customer_id%type,
                                     productid         in product.product_id%type,
                                     sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                                     finishingmethodid in finishingmethod.finishingmethod_id%type,
                                     pricedate         in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customerreplacementprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerreplacementprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Replacement_Price_Details(customerid,
                                    productid,
                                    sizedefinitionid,
                                    finishingmethodid,
                                    pricedate,
                                    price,
                                    price_found_yn,
                                    price_start_date,
                                    result_code,
                                    result_desc,
                                    price_list_type,
                                    price_list_code,
                                    price_list_desc);
      return(price);
    end Replacement_Price_Display;



/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Sales_Price_Details(customerid             in customer.customer_id%type,
                                    productid              in product.product_id%type,
                                    sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                    pricedate              in pricelistpercustomer.dateactive%type,
                                    price                  out customersalesprice.price%type,
                                    price_found_yn         out varchar2,
                                    price_start_date       out customersalesprice.startdate%type,
                                    result_code            out number,
                                    result_desc            out varchar2,
                                    price_list_type        out varchar2,
                                    price_list_code        out generalpricelist.code%type,
                                    price_list_desc        out generalpricelist.description%type) is

    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_pricelist_type           varchar2(1);
    lv_price                    customersalesprice.price%type;
    lv_price_start_date         customersalesprice.startdate%type;
    lv_generalpricelistid       generalsalesprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;
    lv_standard_sizeBillingGroupID         sizebillinggroup.sizebillinggroup_id%type;
    lv_specific_sizeBillingGroupID         sizebillinggroup.systemuser_id%type;
    lv_initial_specific_sizeBillingGroupID sizebillinggroup.sizebillinggroup_id%type;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'N1',
                    'Price not defined',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;

    get_size_billing_groups(customerid, productid, sizedefinitionid, 4, lv_standard_sizeBillingGroupID, lv_initial_specific_sizeBillingGroupID);
    lv_specific_sizeBillingGroupID := lv_initial_specific_sizeBillingGroupID;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size := sizedefinitionid;
    if (customerid is null) OR (productid is null) OR (sizedefinitionid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 4 -- sales price
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select gsp.price,
                             gsp.startdate,
                             g.code,
                             g.description
                        from generalsalesprice gsp, generalpricelist g
                       where g.generalpricelist_id = lv_generalpricelistid
                         and g.pricetype = 4 -- sales price
                         and g.active = 'Y'
                         and gsp.generalpricelist_id = g.generalpricelist_id
                         and gsp.product_id = productid
                         and gsp.sizedefinition_id = lv_size
                         and gsp.startdate <= lv_pricedate
                         and nvl(gsp.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                       order by gsp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.price,
                             cupri.startdate
                        from customersalesprice cupri
                       where cupri.customer_id = customerid
                         and cupri.product_id = productid
                         and cupri.sizedefinition_id = lv_size
                         and cupri.startdate <= lv_pricedate
                         and nvl(cupri.sizebillinggroup_id, 0) = lv_specific_sizeBillingGroupID
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:  1 = with passed size.
                        2 = with size *  (Skipped when passed size was *)   */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- if in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
      end if;
      if i = 3 and lv_specific_sizeBillingGroupID <> lv_standard_sizeBillingGroupID and lv_specific_sizeBillingGroupID = lv_initial_specific_sizeBillingGroupID then
        i := 1; -- if the price was not found for the productsize.sizebillinggroup, then try for the standard
        lv_specific_sizeBillingGroupID := lv_standard_sizeBillingGroupID;
        lv_size := sizedefinitionid;
      end if;
      if i = 3 and lv_specific_sizeBillingGroupID = lv_standard_sizeBillingGroupID and lv_standard_sizeBillingGroupID <> 0 and lv_initial_specific_sizeBillingGroupID <> 0 then
        i := 1; -- if the price was not found for the productsize.sizebillinggroup, then try for the price without sizebillinggroup
        lv_specific_sizeBillingGroupID := 0;
        lv_size := sizedefinitionid;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Sales_Price_details;

/*--------------------------------------------------------------------------------------------------------*/
  function Sales_Price_Details(customerid        in customer.customer_id%type,
                               productid         in product.product_id%type,
                               sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                               pricedate         in pricelistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    price                   customersalesprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customersalesprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Sales_Price_Details(customerid,
                              productid,
                              sizedefinitionid,
                              pricedate,
                              price,
                              price_found_yn,
                              price_start_date,
                              result_code,
                              result_desc,
                              price_list_type,
                              price_list_code,
                              price_list_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
            );
    end Sales_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function Sales_Price(customerid        in customer.customer_id%type,
                       productid         in product.product_id%type,
                       sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                       pricedate         in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customersalesprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customersalesprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Sales_Price_Details(customerid,
                              productid,
                              sizedefinitionid,
                              pricedate,
                              price,
                              price_found_yn,
                              price_start_date,
                              result_code,
                              result_desc,
                              price_list_type,
                              price_list_code,
                              price_list_desc);
      return(nvl(price,0));
    end Sales_Price;

/*--------------------------------------------------------------------------------------------------------*/
  function Sales_Price_Display(customerid        in customer.customer_id%type,
                               productid         in product.product_id%type,
                               sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                               pricedate         in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customersalesprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customersalesprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Sales_Price_Details(customerid,
                              productid,
                              sizedefinitionid,
                              pricedate,
                              price,
                              price_found_yn,
                              price_start_date,
                              result_code,
                              result_desc,
                              price_list_type,
                              price_list_code,
                              price_list_desc);
      return(price);
    end Sales_Price_Display;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Weight_Price_Details(customerid            in customer.customer_id%type,
                                    weighingcategoryid     in weighingcategory.weighingcategory_id%type ,
                                    soil_yn                in customerweightprice.soil%type,
                                    pricedate              in pricelistpercustomer.dateactive%type,
                                    price                  out customerweightprice.price%type,
                                    price_found_yn         out varchar2,
                                    price_start_date       out customerweightprice.startdate%type,
                                    result_code            out number,
                                    result_desc            out varchar2,
                                    price_list_type        out varchar2,
                                    price_list_code        out generalpricelist.code%type,
                                    price_list_desc        out generalpricelist.description%type) is

    price_found                 boolean;
    price_not_relevant          boolean;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_pricelist_type           varchar2(1);
    lv_price                    customerweightprice.price%type;
    lv_price_start_date         customerweightprice.startdate%type;
    lv_generalpricelistid       generalweightprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    lv_weighingcatpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    lv_invoice_method           weighingcategpercustomer.invoicemethod%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'N1',
                    'Price not defined',
                    'N2',
                    'Price not relevant, weights not invoiced',
                    'N3',
                    'Price not defined, weights invoiced soil, not clean ',
                    'N4',
                    'Price not defined, weights invoiced clean, not soil ',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main Weight
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    if (customerid is null) OR (weighingcategoryid is null) OR (soil_yn not in ('Y','N')) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 5  -- this means weight price
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
-- load weighingcategpercustomer etc to determine price usage
      lv_weighingcatpercustomerid := null;
      lv_invoice_method           := null;
      open Vcsr for
        select wcpc.weighingcategpercustomer_id,
               wcpc.invoicemethod
          from weighingcategpercustomer wcpc
         where wcpc.customer_id = customerid
           and wcpc.weighingcategory_id = weighingcategoryid
           and ((lv_pricedate >= wcpc.dateactive and lv_pricedate <= wcpc.dateinactive) or i>1)
         order by wcpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_weighingcatpercustomerid, lv_invoice_method;
        if lv_invoice_method =1 then /* no invoicing based on weight */
          price_not_relevant := true;
          result_code        := 2; -- Price not relevant, customer is not invoiced based on weight
        end if;
        if lv_invoice_method in (2,4) and soil_yn = 'N' then /* configured soil, requested clean */
          price_not_relevant := true;
          result_code        := 3; -- Price not relevant, customer is invoiced based on soil weight
        end if;
        if lv_invoice_method = 3 and soil_yn = 'Y' then /* configured clean, requested soil */
          price_not_relevant := true;
          result_code        := 4; -- Price not relevant, customer is invoiced based on clean weight
        end if;
      end if;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select gwp.price,
                             gwp.startdate,
                             g.code,
                             g.description
                        from generalweightprice gwp, generalpricelist g
                       where g.generalpricelist_id = lv_generalpricelistid
                         and g.pricetype = 5 -- weight price
                         and g.active = 'Y'
                         and gwp.generalpricelist_id = g.generalpricelist_id
                         and gwp.weighingcategory_id = weighingcategoryid
                         and gwp.soil = soil_yn
                         and gwp.startdate <= lv_pricedate
                       order by gwp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.price,
                             cupri.startdate
                        from customerweightprice cupri
                       where cupri.weighingcategpercustomer_id = lv_weighingcatpercustomerid
                         and cupri.soil = soil_yn
                         and cupri.startdate <= lv_pricedate
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:  1 = try to find for active weighingcategorypercustomer
                        2 = try to find for any weighingcategorypercustomer */
        i := i + 1;
        if lv_weighingcatpercustomerid is not null then  -- active wcpc already found, so do not perform extra loop
          i := i + 1;
        end if;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Weight_Price_details;


/*--------------------------------------------------------------------------------------------------------*/
  function Weight_Price_Details(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type ,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    price                   customerweightprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerweightprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Weight_Price_Details(customerid,
                              weighingcategoryid,
                              soil_yn,
                              pricedate,
                              price,
                              price_found_yn,
                              price_start_date,
                              result_code,
                              result_desc,
                              price_list_type,
                              price_list_code,
                              price_list_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
            );
    end Weight_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function Weight_Price(customerid         in customer.customer_id%type,
                        weighingcategoryid in weighingcategory.weighingcategory_id%type ,
                        soil_yn            in customerweightprice.soil%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerweightprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerweightprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Weight_Price_Details(customerid,
                              weighingcategoryid,
                              soil_yn,
                              pricedate,
                              price,
                              price_found_yn,
                              price_start_date,
                              result_code,
                              result_desc,
                              price_list_type,
                              price_list_code,
                              price_list_desc);
      return(nvl(price,0));
    end Weight_Price;

/*--------------------------------------------------------------------------------------------------------*/
  function Weight_Price_Display(customerid         in customer.customer_id%type,
                                weighingcategoryid in weighingcategory.weighingcategory_id%type ,
                                soil_yn            in customerweightprice.soil%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customerweightprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerweightprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Weight_Price_Details(customerid,
                              weighingcategoryid,
                              soil_yn,
                              pricedate,
                              price,
                              price_found_yn,
                              price_start_date,
                              result_code,
                              result_desc,
                              price_list_type,
                              price_list_code,
                              price_list_desc);
      return(price);
    end Weight_Price_Display;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_SpecCharge_Details(customerid             in customer.customer_id%type,
                                   specialchargeid        in specialcharge.specialcharge_id%type,
                                   pricedate              in pricelistpercustomer.dateactive%type,
                                   price                  out customerspecialchargeprice.price%type,
                                   price_found_yn         out varchar2,
                                   price_start_date       out customerspecialchargeprice.startdate%type,
                                   result_code            out number,
                                   result_desc            out varchar2,
                                   price_list_type        out varchar2,
                                   price_list_code        out generalpricelist.code%type,
                                   price_list_desc        out generalpricelist.description%type,
                                   specialchargecode      out specialcharge.code%type,
                                   percentage             out customerspecialchargeprice.percentage%type,
                                   minimumamount          out specialcharge.minimumamount%type,
                                   maximumamount          out specialcharge.maximumamount%type) is

    price_found                 boolean;
    dummy                       number;
    lv_fixedamount_yn           specialcharge.fixedamount%type;
    lv_fixedamount_str          varchar2(10);
    lv_pricedate                date;
    lv_pricelist_type           varchar2(1);
    lv_price                    customerspecialchargeprice.price%type;
    lv_price_start_date         customerspecialchargeprice.startdate%type;
    lv_generalpricelistid       generalpricelist.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    lv_percentage               customerspecialchargeprice.percentage%type;
    lv_minimumamount            customerspecialchargeprice.minimumamount%type;
    lv_maximumamount            customerspecialchargeprice.maximumamount%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;

    function decode_error(errorcode in varchar2, type_str in varchar2 default null) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    type_str || ' found',
                    'N1',
                    type_str || ' not defined',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main SpecialCharge
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    lv_fixedamount_yn      := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    select c.fixedamount,
           decode(c.fixedamount,'Y','Price','Percentage')
      into lv_fixedamount_yn,
           lv_fixedamount_str
      from specialcharge c
     where c.specialcharge_id = specialchargeid;
    if ((customerid is null) OR (specialchargeid is null) OR (lv_fixedamount_yn is null) ) then
      result_code := 8; -- error in parameters
    end if;
    if result_code is null then
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 10  -- this means special charge price
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      -- start loop on pricelistpercustomer
      /* --------------------- L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_percentage       := null;
            lv_minimumamount    := null;
            lv_maximumamount    := null;
            lv_pricelist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select gscp.price,
                             gscp.startdate,
                             g.code,
                             g.description,
                             gscp.percentage, gscp.minimumamount, gscp.maximumamount
                        from generalspecialchargeprice gscp, generalpricelist g
                       where g.generalpricelist_id = lv_generalpricelistid
                         and g.pricetype = 10 -- special charge price
                         and g.active = 'Y'
                         and gscp.generalpricelist_id = g.generalpricelist_id
                         and gscp.specialcharge_id = specialchargeid
                         and gscp.startdate <= lv_pricedate
                       order by gscp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, lv_percentage, lv_minimumamount, lv_maximumamount, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_percentage       := null;
            lv_minimumamount    := null;
            lv_maximumamount    := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.price,
                             cupri.startdate,
                             cupri.percentage, cupri.minimumamount, cupri.maximumamount
                        from customerspecialchargeprice cupri
                       where cupri.specialcharge_id = specialchargeid
                         and cupri.customer_id = customerid
                         and cupri.startdate <= lv_pricedate
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_percentage, lv_minimumamount, lv_maximumamount, dummy;
            close Vcsr;
            if ((lv_price is not null) or (lv_percentage is not null)) then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   L O O P ----------------------------------------------------------*/
      -- if no price found then take from special charge base table
      if (not price_found) then
        open Vcsr for
              select x.*, rownum
                from (select sc.newamount,
                             sc.startdate,
                             sc.newpercentage, sc.minimumamount, sc.maximumamount
                        from specialcharge sc
                       where sc.specialcharge_id = specialchargeid
                       order by sc.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_percentage, lv_minimumamount, lv_maximumamount, dummy;
            close Vcsr;
            if ((lv_price is not null) or (lv_percentage is not null)) then
              price_found := true;
              lv_pricelist_type := 'B'; -- base table
            end if;
      end if;
    end if; -- result_code is null
    if price_found then
      if lv_fixedamount_yn ='Y'
       then
         price      := lv_price;
         percentage := null;
       else
         price      := null;
         percentage := lv_percentage;
      end if; -- lv_fixedamount_yn ='Y'
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := '0';
      select s.code
        into specialchargecode
        from specialcharge s
       where s.specialcharge_id = specialchargeid;
      result_desc      := decode_error('Y' || to_char(result_code),lv_fixedamount_str);
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      minimumamount    := lv_minimumamount;
      maximumamount    := lv_maximumamount;
      case lv_pricelist_type
       when 'G' then price_list_desc := lv_pricelist_desc;
       when 'B' then price_list_desc := 'Base ' || lv_fixedamount_str;
        else price_list_desc := 'Customer Specific.';
      end case;
    else
      if result_code is null then -- no price/percentage found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code,lv_fixedamount_str);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price/percentage found
      result_desc := decode_error('N' || result_code,lv_fixedamount_str);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_SpecCharge_Details;


/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_Details(customerid  in customer.customer_id%type,
                                 specialchargeid    in specialcharge.specialcharge_id%type,
                                 pricedate          in pricelistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(specialchargecode, ' '), 6) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(to_char(percentage, '999D99'), ' '), 7) ||
             rpad(nvl(to_char(minimumamount, '999999D99'), ' '), 10) ||
             rpad(nvl(to_char(maximumamount, '999999D99'), ' '), 10) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
            );
    end SpecialCharge_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_Price(customerid  in customer.customer_id%type,
                        specialchargeid    in specialcharge.specialcharge_id%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(nvl(price,0));
    end SpecialCharge_Price;

/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_Price_Display(customerid  in customer.customer_id%type,
                                specialchargeid    in specialcharge.specialcharge_id%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(price);
    end SpecialCharge_Price_Display;

/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_Percentage(customerid  in customer.customer_id%type,
                        specialchargeid    in specialcharge.specialcharge_id%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the percentage, if not found, returns 0.  For use in calculations.  */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(nvl(percentage,0));
    end SpecialCharge_Percentage;

/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_Percentage_Disp(customerid  in customer.customer_id%type,
                                specialchargeid    in specialcharge.specialcharge_id%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the percentage, if not found, returns null.  For display/print purposes. */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(percentage);
    end SpecialCharge_Percentage_Disp;
/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_MinAmount(customerid  in customer.customer_id%type,
                        specialchargeid    in specialcharge.specialcharge_id%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the MinAmount, if not found, returns 0.  For use in calculations.  */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(nvl(minimumamount,0));
    end SpecialCharge_MinAmount;

/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_MinAmount_Disp(customerid  in customer.customer_id%type,
                                specialchargeid    in specialcharge.specialcharge_id%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the MinAmount, if not found, returns null.  For display/print purposes. */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(minimumamount);
    end SpecialCharge_MinAmount_Disp;
/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_MaxAmount(customerid  in customer.customer_id%type,
                        specialchargeid    in specialcharge.specialcharge_id%type,
                        pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the MaxAmount, if not found, returns 0.  For use in calculations.  */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(nvl(maximumamount,0));
    end SpecialCharge_MaxAmount;

/*--------------------------------------------------------------------------------------------------------*/
  function SpecialCharge_MaxAmount_Disp(customerid  in customer.customer_id%type,
                                specialchargeid    in specialcharge.specialcharge_id%type,
                                pricedate          in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the MaxAmount, if not found, returns null.  For display/print purposes. */

    price                   customerspecialchargeprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerspecialchargeprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    specialchargecode       specialcharge.code%type;
    percentage              customerspecialchargeprice.percentage%type;
    minimumamount           specialcharge.minimumamount%type;
    maximumamount           specialcharge.maximumamount%type;

    begin
      Get_SpecCharge_Details(customerid,
                             specialchargeid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             specialchargecode,
                             percentage,
                             minimumamount,
                             maximumamount);
      return(maximumamount);
    end SpecialCharge_MaxAmount_Disp;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Rent_Discount_Details(customerid             in customer.customer_id%type,
                                      productid              in product.product_id%type,
                                      sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                      discountdate           in discountlistpercustomer.dateactive%type,
                                      discount               out customerrentdiscount.discount%type,
                                      discount_found_yn      out varchar2,
                                      discount_start_date    out customerrentdiscount.startdate%type,
                                      result_code            out number,
                                      result_desc            out varchar2,
                                      discount_list_type     out varchar2,
                                      discount_list_code     out generaldiscountlist.code%type,
                                      discount_list_desc     out generaldiscountlist.description%type) is

    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerrentdiscount.discount%type;
    lv_discount_start_date      customerrentdiscount.startdate%type;
    lv_generaldiscountlistid    generalrentdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_customergarmrentspec     customer.garmentrentspecification%type;
    lv_size                     sizedefinition.sizedefinition_id%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VDiscountListperCust        Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Discount found',
                    'N1',
                    'Discount not defined',
                    'N2',
                    'Discount not relevant, billing method 3 with wash price only',
                    'N3',
                    'Discount not relevant, billing method = 4 piece rate only',
                    'N4',
                    'Discount not applicable, price defined at wearer level as wearer total price',
                    'N5',
                    'Discount not applicable, price defined at wearer function level',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found            := false;
    discount_not_relevant     := false;
    discount                  := null;
    discount_found_yn         := 'N';
    discount_start_date       := null;
    result_code               := null;
    result_desc               := null;
    discount_list_type        := null;
    discount_list_code        := null;
    discount_list_desc        := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    lv_size := sizedefinitionid;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open VdiscountListperCust for
        Select discountlistpercustomer.generaldiscountlist_id
          from discountlistpercustomer
         where discountlistpercustomer.customer_id = customerid
           and discountlistpercustomer.pricetype = 2  -- this means rent discount
           and discountlistpercustomer.dateactive <= lv_discountdate
           and discountlistpercustomer.dateinactive >= lv_discountdate
         order by discountlistpercustomer.priority;
      fetch VdiscountListperCust
        into lv_generaldiscountlistid;
-- load weighingcategpercustomer etc to determine discount usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_typeofmerchandize        := null;
      lv_priceusage               := null;
      lv_customergarmrentspec     := null;
      open Vcsr for
        select plpc.productlistpercustomer_id,
               plpc.billingmethod,
               plpc.priceusage,
               p.typeofmerchandise,
               c.garmentrentspecification
          from productlistpercustomer plpc, product p, customer c
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and plpc.sizedefinition_id = lv_size
           and plpc.finishingmethod_id = finishingmethodid
           and p.product_id = plpc.product_id
           and c.customer_id = plpc.customer_id
           and ((lv_discountdate >= plpc.dateactive and lv_discountdate <= plpc.dateinactive) or i>1)
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_typeofmerchandize, lv_customergarmrentspec;
        if lv_billingmethod = 3 and lv_priceusage = 3 then /*wash only*/
          discount_not_relevant := true;
          result_code           := 2; -- Price not relevant, billing method 3 with wash price only
        end if;
        if lv_billingmethod = 4 then
          discount_not_relevant := true;
          result_code           := 3; -- Price not relevant, billing method = 4 piece rate only
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize=2 and lv_customergarmrentspec=5 then -- total wearer price
          discount_not_relevant := true;
          result_code           := 4; -- Price not relevant, wearer total price
        end if;
        if lv_billingmethod = 1 and lv_typeofmerchandize=2 and lv_customergarmrentspec=6 then -- wearer function price
          discount_not_relevant := true;
          result_code           := 5; -- Price not relevant, wearer function price
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VdiscountListperCust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select grp.discount,
                             grp.startdate,
                             g.code,
                             g.description
                        from generalrentdiscount grp, generaldiscountlist g
                       where g.generaldiscountlist_id = lv_generaldiscountlistid
                         and g.pricetype = 2 -- rent discount
                         and g.active = 'Y'
                         and grp.generaldiscountlist_id = g.generaldiscountlist_id
                         and grp.product_id = productid
                         and grp.sizedefinition_id = lv_size
                         and grp.finishingmethod_id = finishingmethodid
                         and grp.startdate <= lv_discountdate
                       order by grp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc, dummy;
            close Vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.discount,
                             cupri.startdate
                        from customerrentdiscount cupri
                       where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                         and cupri.startdate <= lv_discountdate
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close Vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch VdiscountListperCust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when activ plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G'
        then discount_list_desc := lv_discountlist_desc;
        else discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Rent_Discount_details;


/*--------------------------------------------------------------------------------------------------------*/
  function Rent_Discount_Details(customerid         in customer.customer_id%type,
                                 productid          in product.product_id%type,
                                 sizedefinitionid   in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid  in finishingmethod.finishingmethod_id%type,
                                 discountdate       in discountlistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Rent_Discount_Details(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                discountdate,
                                discount,
                                discount_found_yn,
                                discount_start_date,
                                result_code,
                                result_desc,
                                discount_list_type,
                                discount_list_code,
                                discount_list_desc);
      return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) ||
             discount_found_yn ||
             rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(discount_list_type, ' '), 1) ||
             rpad(nvl(discount_list_code, ' '), 6) ||
             rpad(nvl(discount_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80)
            );
    end Rent_Discount_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function Rent_Discount(customerid         in customer.customer_id%type,
                         productid          in product.product_id%type,
                         sizedefinitionid   in sizedefinition.sizedefinition_id%type,
                         finishingmethodid  in finishingmethod.finishingmethod_id%type,
                         discountdate       in discountlistpercustomer.dateactive%type default null)
  return number is
  /* Returns the discount, if not found, returns 0.  For use in calculations.  */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Rent_discount_Details(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                discountdate,
                                discount,
                                discount_found_yn,
                                discount_start_date,
                                result_code,
                                result_desc,
                                discount_list_type,
                                discount_list_code,
                                discount_list_desc);
      return(nvl(discount,0));
    end Rent_Discount;

/*--------------------------------------------------------------------------------------------------------*/
  function Rent_Discount_Display(customerid         in customer.customer_id%type,
                                 productid          in product.product_id%type,
                                 sizedefinitionid   in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid  in finishingmethod.finishingmethod_id%type,
                                 discountdate       in discountlistpercustomer.dateactive%type default null)
  return number is
  /* Returns the discount, if not found, returns null.  For display/print purposes. */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Rent_Discount_Details(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                discountdate,
                                discount,
                                discount_found_yn,
                                discount_start_date,
                                result_code,
                                result_desc,
                                discount_list_type,
                                discount_list_code,
                                discount_list_desc);
      return(discount);
    end Rent_Discount_Display;


/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Wash_Discount_Details(customerid             in customer.customer_id%type,
                                      productid              in product.product_id%type,
                                      sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                      finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                      discountdate           in discountlistpercustomer.dateactive%type,
                                      discount               out customerwashdiscount.discount%type,
                                      discount_found_yn      out varchar2,
                                      discount_start_date    out customerwashdiscount.startdate%type,
                                      result_code            out number,
                                      result_desc            out varchar2,
                                      discount_list_type     out varchar2,
                                      discount_list_code     out generaldiscountlist.code%type,
                                      discount_list_desc     out generaldiscountlist.description%type) is

    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerwashdiscount.discount%type;
    lv_discount_start_date      customerwashdiscount.startdate%type;
    lv_generaldiscountlistid    generalwashdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod            productlistpercustomer.billingmethod%type;
    lv_priceusage               productlistpercustomer.priceusage%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_size                     sizedefinition.sizedefinition_id%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VDiscountListperCust        Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Discount found',
                    'N1',
                    'Discount not defined',
                    'N2',
                    'Discount not relevant, billing method 3 with rent price only',
                    'N3',
                    'Discount not relevant, billing method = 1 flat rated rent',
                    'N4',
                    'Discount not relevant, billing method = 2 rent based on minimum',
                    'N5',
                    'Discount not relevant, disposable / sales only item',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found            := false;
    discount_not_relevant     := false;
    discount                  := null;
    discount_found_yn         := 'N';
    discount_start_date       := null;
    result_code               := null;
    result_desc               := null;
    discount_list_type        := null;
    discount_list_code        := null;
    discount_list_desc        := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    lv_size := sizedefinitionid;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open VdiscountListperCust for
        Select discountlistpercustomer.generaldiscountlist_id
          from discountlistpercustomer
         where discountlistpercustomer.customer_id = customerid
           and discountlistpercustomer.pricetype = 1  -- this means wash discount
           and discountlistpercustomer.dateactive <= lv_discountdate
           and discountlistpercustomer.dateinactive >= lv_discountdate
         order by discountlistpercustomer.priority;
      fetch VdiscountListperCust
        into lv_generaldiscountlistid;
-- load weighingcategpercustomer etc to determine discount usage
      lv_productlistpercustomerid := null;
      lv_billingmethod            := null;
      lv_typeofmerchandize        := null;
      lv_priceusage               := null;
      open Vcsr for
        select plpc.productlistpercustomer_id,
               plpc.billingmethod,
               plpc.priceusage,
               p.typeofmerchandise
          from productlistpercustomer plpc, product p
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and plpc.sizedefinition_id = lv_size
           and plpc.finishingmethod_id = finishingmethodid
           and p.product_id = plpc.product_id
           and ((lv_discountdate >= plpc.dateactive and lv_discountdate <= plpc.dateinactive) or i>1)
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid, lv_billingmethod, lv_priceusage, lv_typeofmerchandize;
        if lv_billingmethod = 3 and lv_priceusage = 2 then /* rent price only*/
          discount_not_relevant := true;
          result_code           := 2; -- Price not relevant, billing method 3 with rent price only
        end if;
        if lv_billingmethod = 1 /*and pricetype<>2*/ then
          discount_not_relevant := true;
          result_code           := 3; -- Price not relevant, billing method = 1 flat rated rent only
        end if;
        if lv_billingmethod = 2 then
          discount_not_relevant := true;
          result_code           := 4; -- Price not relevant, billing method = 2 rent based on minimum
        end if;
        if lv_typeofmerchandize = 3 then
          discount_not_relevant := true;
          result_code           := 5; -- Price not relevant, disposable or sales only item.
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VdiscountListperCust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select gwp.discount,
                             gwp.startdate,
                             g.code,
                             g.description
                        from generalwashdiscount gwp, generaldiscountlist g
                       where g.generaldiscountlist_id = lv_generaldiscountlistid
                         and g.pricetype = 1 -- wash discount
                         and g.active = 'Y'
                         and gwp.generaldiscountlist_id = g.generaldiscountlist_id
                         and gwp.product_id = productid
                         and gwp.sizedefinition_id = lv_size
                         and gwp.finishingmethod_id = finishingmethodid
                         and gwp.startdate <= lv_discountdate
                       order by gwp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc, dummy;
            close Vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.discount,
                             cupri.startdate
                        from customerwashdiscount cupri
                       where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                         and cupri.startdate <= lv_discountdate
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close Vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch VdiscountListperCust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when activ plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- try again original size but now for inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code and try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G'
        then discount_list_desc := lv_discountlist_desc;
        else discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Wash_Discount_details;


/*--------------------------------------------------------------------------------------------------------*/
  function Wash_Discount_Details(customerid         in customer.customer_id%type,
                                 productid          in product.product_id%type,
                                 sizedefinitionid   in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid  in finishingmethod.finishingmethod_id%type,
                                 discountdate       in discountlistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Wash_Discount_Details(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                discountdate,
                                discount,
                                discount_found_yn,
                                discount_start_date,
                                result_code,
                                result_desc,
                                discount_list_type,
                                discount_list_code,
                                discount_list_desc);
      return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) ||
             discount_found_yn ||
             rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(discount_list_type, ' '), 1) ||
             rpad(nvl(discount_list_code, ' '), 6) ||
             rpad(nvl(discount_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80)
            );
    end Wash_Discount_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function Wash_Discount(customerid         in customer.customer_id%type,
                         productid          in product.product_id%type,
                         sizedefinitionid   in sizedefinition.sizedefinition_id%type,
                         finishingmethodid  in finishingmethod.finishingmethod_id%type,
                         discountdate       in discountlistpercustomer.dateactive%type default null)
  return number is
  /* Returns the discount, if not found, returns 0.  For use in calculations.  */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Wash_discount_Details(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                discountdate,
                                discount,
                                discount_found_yn,
                                discount_start_date,
                                result_code,
                                result_desc,
                                discount_list_type,
                                discount_list_code,
                                discount_list_desc);
      return(nvl(discount,0));
    end Wash_Discount;

/*--------------------------------------------------------------------------------------------------------*/
  function Wash_Discount_Display(customerid         in customer.customer_id%type,
                                 productid          in product.product_id%type,
                                 sizedefinitionid   in sizedefinition.sizedefinition_id%type,
                                 finishingmethodid  in finishingmethod.finishingmethod_id%type,
                                 discountdate       in discountlistpercustomer.dateactive%type default null)
  return number is
  /* Returns the discount, if not found, returns null.  For display/print purposes. */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Wash_Discount_Details(customerid,
                                productid,
                                sizedefinitionid,
                                finishingmethodid,
                                discountdate,
                                discount,
                                discount_found_yn,
                                discount_start_date,
                                result_code,
                                result_desc,
                                discount_list_type,
                                discount_list_code,
                                discount_list_desc);
      return(discount);
    end Wash_Discount_Display;

/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Weight_Discount_Details(customerid             in customer.customer_id%type,
                                        weighingcategoryid     in weighingcategory.weighingcategory_id%type ,
                                        soil_yn                in customerweightdiscount.soil%type,
                                        discountdate           in discountlistpercustomer.dateactive%type,
                                        discount               out customerweightdiscount.discount%type,
                                        discount_found_yn      out varchar2,
                                        discount_start_date    out customerweightdiscount.startdate%type,
                                        result_code            out number,
                                        result_desc            out varchar2,
                                        discount_list_type     out varchar2,
                                        discount_list_code     out generaldiscountlist.code%type,
                                        discount_list_desc     out generaldiscountlist.description%type) is

    discount_found              boolean;
    discount_not_relevant       boolean;
    i                           number;
    dummy                       number;
    lv_discountdate             date;
    lv_discountlist_type        varchar2(1);
    lv_discount                 customerweightdiscount.discount%type;
    lv_discount_start_date      customerweightdiscount.startdate%type;
    lv_generaldiscountlistid    generalwashdiscount.generaldiscountlist_id%type;
    lv_discountlist_code        generaldiscountlist.code%type;
    lv_discountlist_desc        generaldiscountlist.description%type;
    lv_weighingcatpercustomerid weighingcategpercustomer.weighingcategpercustomer_id%type;
    lv_invoice_method           weighingcategpercustomer.invoicemethod%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VDiscountListperCust        Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Discount found',
                    'N1',
                    'Discount not defined',
                    'N2',
                    'Discount not relevant, weights not invoiced',
                    'N3',
                    'Discount not defined, weights invoiced soil, not clean ',
                    'N4',
                    'Discount not defined, weights invoiced clean, not soil ',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main sales
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    discount_found            := false;
    discount_not_relevant     := false;
    discount                  := null;
    discount_found_yn         := 'N';
    discount_start_date       := null;
    result_code               := null;
    result_desc               := null;
    discount_list_type        := null;
    discount_list_code        := null;
    discount_list_desc        := null;
    if discountdate is null then
      select sysdate into lv_discountdate from dual;
    else
      lv_discountdate := discountdate;
    end if;
    if (customerid is null) OR (weighingcategoryid is null) OR (soil_yn not in ('Y','N')) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 3) and (result_code is null) and (not discount_found) and
          (not discount_not_relevant) loop
      open VdiscountListperCust for
        Select discountlistpercustomer.generaldiscountlist_id
          from discountlistpercustomer
         where discountlistpercustomer.customer_id = customerid
           and discountlistpercustomer.pricetype = 5  -- this means weight discount
           and discountlistpercustomer.dateactive <= lv_discountdate
           and discountlistpercustomer.dateinactive >= lv_discountdate
         order by discountlistpercustomer.priority;
      fetch VdiscountListperCust
        into lv_generaldiscountlistid;
-- load weighingcategpercustomer etc to determine discount usage
      lv_weighingcatpercustomerid := null;
      lv_invoice_method           := null;
      open Vcsr for
        select wcpc.weighingcategpercustomer_id,
               wcpc.invoicemethod
          from weighingcategpercustomer wcpc
         where wcpc.customer_id = customerid
           and wcpc.weighingcategory_id = weighingcategoryid
           and ((lv_discountdate >= wcpc.dateactive and lv_discountdate <= wcpc.dateinactive) or i>1)
         order by wcpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_weighingcatpercustomerid, lv_invoice_method;
        if lv_invoice_method =1 then /* no invoicing based on weight */
          discount_not_relevant := true;
          result_code        := 2; -- discount not relevant, customer is not invoiced based on weight
        end if;
        if lv_invoice_method in (2,4) and soil_yn = 'N' then /* configured soil, requested clean */
          discount_not_relevant := true;
          result_code        := 3; -- discount not relevant, customer is invoiced based on soil weight
        end if;
        if lv_invoice_method = 3 and soil_yn = 'Y' then /* configured clean, requested soil */
          discount_not_relevant := true;
          result_code        := 4; -- discount not relevant, customer is invoiced based on clean weight
        end if;
      end if;
      -- start inner loop on discountlistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VdiscountListperCust%notfound) and (not discount_found) and
            (not discount_not_relevant) loop
        --if not discount_found then
        if lv_generaldiscountlistid is not null then
          -- general discount list
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select gwp.discount,
                             gwp.startdate,
                             g.code,
                             g.description
                        from generalweightdiscount gwp, generaldiscountlist g
                       where g.generaldiscountlist_id = lv_generaldiscountlistid
                         and g.pricetype = 5 -- weight discount
                         and g.active = 'Y'
                         and gwp.generaldiscountlist_id = g.generaldiscountlist_id
                         and gwp.weighingcategory_id = weighingcategoryid
                         and gwp.soil = soil_yn
                         and gwp.startdate <= lv_discountdate
                       order by gwp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_discount, lv_discount_start_date, lv_discountlist_code, lv_discountlist_desc, dummy;
            close Vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generaldiscountlistid is not null  customer specific discountlist
          begin
            lv_discount            := null;
            lv_discount_start_date := null;
            lv_discountlist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.discount,
                             cupri.startdate
                        from customerweightdiscount cupri
                       where cupri.weighingcategpercustomer_id = lv_weighingcatpercustomerid
                         and cupri.soil = soil_yn
                         and cupri.startdate <= lv_discountdate
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_discount, lv_discount_start_date, dummy;
            close Vcsr;
            if lv_discount is not null then
              discount_found := true;
            end if;
          end; -- else
        end if; -- end if generaldiscountlistid is not null
        fetch VdiscountListperCust
          into lv_generaldiscountlistid; -- continue with next discountlistpercustomer
      end loop; -- end while not VdiscountListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not discount_found) and (not discount_not_relevant) then
        /* iterations:  1 = try to find for active weighingcategorypercustomer
                        2 = try to find for any weighingcategorypercustomer */
        i := i + 1;
        if lv_weighingcatpercustomerid is not null then  -- active wcpc already found, so do not perform extra loop
          i := i + 1;
        end if;
      end if;
    end loop; -- end while i < 3
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if discount_found then
      discount            := lv_discount;
      discount_found_yn   := 'Y';
      discount_start_date := lv_discount_start_date;
      result_code      := '0';
      result_desc      := decode_error('Y' || to_char(result_code));
      discount_list_type  := lv_discountlist_type;
      discount_list_code  := lv_discountlist_code;
      if lv_discountlist_type = 'G'
        then discount_list_desc := lv_discountlist_desc;
        else discount_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no discount found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no discount found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Weight_Discount_details;


/*--------------------------------------------------------------------------------------------------------*/
  function Weight_Discount_Details(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type ,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
  return varchar2 is
  /* See package header for description of return string.   */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Weight_Discount_Details(customerid,
                                  weighingcategoryid,
                                  soil_yn,
                                  discountdate,
                                  discount,
                                  discount_found_yn,
                                  discount_start_date,
                                  result_code,
                                  result_desc,
                                  discount_list_type,
                                  discount_list_code,
                                  discount_list_desc);
      return(rpad(nvl(to_char(discount, '999999D9999'), ' '), 12) ||
             discount_found_yn ||
             rpad(nvl(to_char(discount_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(discount_list_type, ' '), 1) ||
             rpad(nvl(discount_list_code, ' '), 6) ||
             rpad(nvl(discount_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80)
            );
    end Weight_Discount_Details;

/*--------------------------------------------------------------------------------------------------------*/
  function Weight_Discount(customerid         in customer.customer_id%type,
                           weighingcategoryid in weighingcategory.weighingcategory_id%type ,
                           soil_yn            in customerweightdiscount.soil%type,
                           discountdate       in discountlistpercustomer.dateactive%type default null)
  return number is
  /* Returns the discount, if not found, returns 0.  For use in calculations.  */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Weight_discount_Details(customerid,
                                  weighingcategoryid,
                                  soil_yn,
                                  discountdate,
                                  discount,
                                  discount_found_yn,
                                  discount_start_date,
                                  result_code,
                                  result_desc,
                                  discount_list_type,
                                  discount_list_code,
                                  discount_list_desc);
      return(nvl(discount,0));
    end Weight_Discount;

/*--------------------------------------------------------------------------------------------------------*/
  function Weight_Discount_Display(customerid         in customer.customer_id%type,
                                   weighingcategoryid in weighingcategory.weighingcategory_id%type ,
                                   soil_yn            in customerweightdiscount.soil%type,
                                   discountdate       in discountlistpercustomer.dateactive%type default null)
  return number is
  /* Returns the discount, if not found, returns null.  For display/print purposes. */

    discount                   customerweightdiscount.discount%type;
    discount_found_yn          varchar2(1);
    discount_start_date        customerweightdiscount.startdate%type;
    result_code                number;
    result_desc                varchar2(80);
    discount_list_type         varchar2(1);
    discount_list_code         generaldiscountlist.code%type;
    discount_list_desc         generaldiscountlist.description%type;

    begin
      Get_Weight_Discount_Details(customerid,
                                  weighingcategoryid,
                                  soil_yn,
                                  discountdate,
                                  discount,
                                  discount_found_yn,
                                  discount_start_date,
                                  result_code,
                                  result_desc,
                                  discount_list_type,
                                  discount_list_code,
                                  discount_list_desc);
      return(discount);
    end Weight_Discount_Display;

/*--------------------------------------------------------------------------------------------------------*/
procedure Get_ResidRent_Price_Details(customerid             in customer.customer_id%type,
                                  productid              in product.product_id%type,
                                  sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                  finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                  pricedate              in pricelistpercustomer.dateactive%type,
                                  price                  out customerrentprice.price%type,
                                  price_found_yn         out varchar2,
                                  price_start_date       out customerrentprice.startdate%type,
                                  result_code            out number,
                                  result_desc            out varchar2,
                                  price_list_type        out varchar2,
                                  price_list_code        out generalpricelist.code%type,
                                  price_list_desc        out generalpricelist.description%type,
                                  price_type_code        out customerrentprice.typeofrent%type,
                                  price_type_desc        out varchar2) is

    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_residentialrentid        residentialrent.residentialrent_id%type;
    lv_customergarmrentspec     customer.garmentrentspecification%type;
    lv_pricelist_type           varchar2(1);
    lv_custsplitinvperactivity  customer.splitinvoicesperactivity%type;
    lv_typeofmerchandize        product.typeofmerchandise%type;
    lv_typeofrent               generalrentprice.typeofrent%type;
    lv_typeofrent_general       generalrentprice.typeofrent%type;
    lv_typeofrent_specific      generalrentprice.typeofrent%type;
    lv_productgroup_id          product.productgroup_id%type;
    lv_price                    customerresidentialrentprice.price%type;
    lv_price_start_date         customerresidentialrentprice.startdate%type;
    lv_generalpricelistid       generalrentprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'N1',
                    'Price not defined',
                    'N2',
                    'Price not relevant, billing method 3 with wash price only',
                    'N3',
                    'Price not relevant, billing method = 4 piece rate only',
                    'N4',
                    'Price not relevant, defined at wearer level as wearer total price',
                    'N5',
                    'Price not relevant, defined at wearer function level',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

    function decode_type_of_rent(fptypeofrent in number) return varchar2 is
      r varchar2(30);
    begin
      select decode(fptypeofrent,
                    9,
                    'Residential Rent',
                    'Unknown type of rent')
        into r
        from dual;
      return r;
    end;

  begin -- main rent price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    price_type_code        := null;
    price_type_desc        := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size           := sizedefinitionid;
    lv_finmethod      := finishingmethodid;
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 2
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      lv_residentialrentid := null;
      lv_custsplitinvperactivity  := null;
      open Vcsr for
        select rr.residentialrent_id,
               p.typeofmerchandise,
               p.productgroup_id,
               c.garmentrentspecification,
               c.splitinvoicesperactivity
          from residentialrent rr, product p, customer c--productlistpercustomer plpc
         where rr.customer_id = customerid
           and rr.product_id = productid
           and p.product_id = productid
           and c.customer_id = customerid
           and rr.sizedefinition_id = lv_size
           and rr.finishingmethod_id = lv_finmethod
           and ((lv_pricedate >= rr.startdate and lv_pricedate <= rr.enddate) or i > 2)
           -- only filter on active in iteration 3 and 4
         order by rr.startdate desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_residentialrentid,
               lv_typeofmerchandize, lv_productgroup_id, lv_customergarmrentspec,
               lv_custsplitinvperactivity;
          lv_typeofrent := 9;
          lv_typeofrent_general := lv_typeofrent;
          lv_typeofrent_specific := lv_typeofrent;
      end if;
      close Vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
              open Vcsr for
                select x.*, rownum
                  from (select grp.price,
                               grp.startdate,
                               g.code,
                               g.description
                          from generalrentprice grp, generalpricelist g
                         where g.generalpricelist_id = lv_generalpricelistid
                           and g.pricetype = 2
                           and g.active = 'Y'
                           and grp.generalpricelist_id = g.generalpricelist_id
                           and grp.product_id = productid
                           and grp.sizedefinition_id = lv_size
                           and grp.finishingmethod_id = lv_finmethod
                           and grp.startdate <= lv_pricedate
                           and grp.typeofrent = lv_typeofrent_general
                         order by grp.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
              close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- select original size again and try for an inactive plpc
          if lv_residentialrentid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if not price_found then
              open Vcsr for
                select x.*, rownum
                  from (select cupri.price,
                               cupri.startdate
                          from customerresidentialrentprice cupri
                         where cupri.customer_id = customerid
                               and cupri.product_id = productid
                               and cupri.sizedefinition_id = sizedefinitionid
                               and cupri.finishingmethod_id = finishingmethodid
                               and cupri.startdate <= lv_pricedate
                         order by cupri.startdate desc) x
                 where rownum = 1; -- take first
              fetch Vcsr
                into lv_price, lv_price_start_date, dummy;
              close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
    end if;
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
      price_type_code := lv_typeofrent;
      price_type_desc := decode_type_of_rent(price_type_code);
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_ResidRent_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
function ResidentialRent_Price_Details(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null)
 return varchar2 is
  /* See package header for description of return string.   */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(100);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);

    begin
      Get_ResidRent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             price_type_code,
                             price_type_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(to_char(price_type_code), ' '), 1) ||
             rpad(nvl(price_type_desc, ' '), 30) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
             );
    end ResidentialRent_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
function ResidentialRent_Price(customerid        in customer.customer_id%type,
                    productid         in product.product_id%type,
                    sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                    finishingmethodid in finishingmethod.finishingmethod_id%type,
                    pricedate         in pricelistpercustomer.dateactive%type default null)
 return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(100);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);

    begin
      Get_ResidRent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             price_type_code,
                             price_type_desc);
      return(nvl(price,0));
    end ResidentialRent_Price;

/*--------------------------------------------------------------------------------------------------------*/
function ResidentialRent_Price_Display(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null)
 return number is
  /* Returns the price, if not found, returns null.  For display/print purposes. */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(100);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;
    price_type_code         customerrentprice.typeofrent%type;
    price_type_desc         varchar2(30);

    begin
      Get_ResidRent_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc,
                             price_type_code,
                             price_type_desc);
      return(price);
    end ResidentialRent_Price_Display;


/*--------------------------------------------------------------------------------------------------------*/
  procedure Get_Loan_Price_Details(customerid             in customer.customer_id%type,
                                   productid              in product.product_id%type,
                                   sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                                   finishingmethodid      in finishingmethod.finishingmethod_id%type,
                                   pricedate              in pricelistpercustomer.dateactive%type,
                                   price                  out customerrentprice.price%type,
                                   price_found_yn         out varchar2,
                                   price_start_date       out customerrentprice.startdate%type,
                                   result_code            out number,
                                   result_desc            out varchar2,
                                   price_list_type        out varchar2,
                                   price_list_code        out generalpricelist.code%type,
                                   price_list_desc        out generalpricelist.description%type) is

    price_found                 boolean;
    price_not_relevant          boolean;
    lv_size                     sizedefinition.sizedefinition_id%type;
    lv_finmethod                finishingmethod.finishingmethod_id%type;
    i                           number;
    dummy                       number;
    lv_pricedate                date;
    lv_productlistpercustomerid productlistpercustomer.productlistpercustomer_id%type;
    lv_pricelist_type           varchar2(1);
    lv_typeofrent               customerrentprice.typeofrent%type;
    lv_price                    customerrentprice.price%type;
    lv_price_start_date         customerrentprice.startdate%type;
    lv_generalpricelistid       generalrentprice.generalpricelist_id%type;
    lv_pricelist_code           generalpricelist.code%type;
    lv_pricelist_desc           generalpricelist.description%type;
    type Tcsr                   is ref cursor;
    Vcsr                        Tcsr;
    VPriceListperCust           Tcsr;

    function decode_error(errorcode in varchar2) return varchar2 is
      r varchar2(80);
    begin
      select decode(errorcode,
                    'Y0',
                    'Price found',
                    'N1',
                    'Price not defined',
                    'N8',
                    'Error in parameters',
                    'N9',
                    'ORA Error',
                    'Unknown error code')
        into r
        from dual;
      return r;
    end;

  begin -- main loan price
    /* ------------------------ I N I T I A L I S A T I O N ------------------------------------------------------*/
    lv_typeofrent          := 10; -- Loan
    price_found            := false;
    price_not_relevant     := false;
    price                  := null;
    price_found_yn         := 'N';
    price_start_date       := null;
    result_code            := null;
    result_desc            := null;
    price_list_type        := null;
    price_list_code        := null;
    price_list_desc        := null;
    if pricedate is null then
      select sysdate into lv_pricedate from dual;
    else
      lv_pricedate := pricedate;
    end if;
    lv_size           := sizedefinitionid;
    lv_finmethod      := finishingmethodid;
    if (customerid is null) OR (productid is null) OR
       (sizedefinitionid is null) OR (finishingmethodid is null) then
      result_code := 8; -- error in parameters
    end if;
    i := 1;
    -- start outer loop on exact match, size * etc.
    /* ############################ O U T E R L O O P ############################################################*/
    while (i < 5) and (result_code is null) and (not price_found) and
          (not price_not_relevant) loop
      open VPriceListperCust for
        Select pricelistpercustomer.generalpricelist_id
          from pricelistpercustomer
         where pricelistpercustomer.customer_id = customerid
           and pricelistpercustomer.pricetype = 2
           and pricelistpercustomer.dateactive <= lv_pricedate
           and pricelistpercustomer.dateinactive >= lv_pricedate
         order by pricelistpercustomer.priority;
      fetch VPriceListperCust
        into lv_generalpricelistid;
      -- load plpc
      lv_productlistpercustomerid := null;
      open Vcsr for
        select plpc.productlistpercustomer_id
          from productlistpercustomer plpc
         where plpc.customer_id = customerid
           and plpc.product_id = productid
           and plpc.sizedefinition_id = lv_size
           and plpc.finishingmethod_id = lv_finmethod
           and ((lv_pricedate >= plpc.dateactive and lv_pricedate <= plpc.dateinactive) or i>2)
           -- only filter on active in iteration 3 and 4
         order by plpc.dateactive desc;
      if Vcsr%notfound then
        null;
      else
        fetch Vcsr
          into lv_productlistpercustomerid;
      end if;
      close Vcsr;
      -- start inner loop on pricelistpercustomer
      /* --------------------- I N N E R L O O P ----------------------------------------------------------*/
      while (not VPriceListperCust%notfound) and (not price_found) and
            (not price_not_relevant) loop
        --if not price_found then
        if lv_generalpricelistid is not null then
          -- general price list
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'G'; -- general
            open Vcsr for
              select x.*, rownum
                from (select grp.price,
                             grp.startdate,
                             g.code,
                             g.description
                        from generalrentprice grp, generalpricelist g
                       where g.generalpricelist_id = lv_generalpricelistid
                         and g.pricetype = 2
                         and g.active = 'Y'
                         and grp.generalpricelist_id = g.generalpricelist_id
                         and grp.product_id = productid
                         and grp.sizedefinition_id = lv_size
                         and grp.finishingmethod_id = lv_finmethod
                         and grp.typeofrent = lv_typeofrent
                         and grp.startdate <= lv_pricedate
                       order by grp.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, lv_pricelist_code, lv_pricelist_desc, dummy;
            close Vcsr;
            if lv_price is not null then
              price_found := true;
            end if;
          exception
            when no_data_found then
              null;
            when others then
              null;
          end;
        else  --  generalpricelistid is not null  customer specific pricelist
          begin
            lv_price            := null;
            lv_price_start_date := null;
            lv_pricelist_type   := 'C'; -- customer specific
            open Vcsr for
              select x.*, rownum
                from (select cupri.price,
                             cupri.startdate
                        from customerrentprice cupri
                       where cupri.productlistpercustomer_id = lv_productlistpercustomerid
                         and cupri.startdate <= lv_pricedate
                         and cupri.typeofrent = lv_typeofrent
                       order by cupri.startdate desc) x
               where rownum = 1; -- take first
            fetch Vcsr
              into lv_price, lv_price_start_date, dummy;
            close Vcsr;

            if lv_price is not null then
              price_found := true;
            end if;
          end; -- else
        end if; -- end if generalpricelistid is not null
        fetch VPriceListperCust
          into lv_generalpricelistid; -- continue with next pricelistpercustomer
      end loop; -- end while not VPriceListperCust%notfound
      /* --------------- E N D   I N N E R L O O P ----------------------------------------------------------*/
      if (not price_found) and (not price_not_relevant) then
        /* iterations:
           1 = with plpc active and passed size
           2 = with plpc active and size *.             Skipped when passed size was *
           3 = with plpc inactive and passed size.      Skipped when active plpc was found
           4 = with plpc inactive and size *            Skipped when passed size was *
        */
        i := i + 1;
        if i = 2 then --  select sizedefinition_id for '*' code
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 1 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 2
          end if;
        end if;
        if i = 3 then -- select original size again and try for an inactive plpc
          if lv_productlistpercustomerid is not null
            then i := 5; -- don't search further
            else lv_size := sizedefinitionid;
          end if;
        end if;
        if i = 4 then --  select sizedefinition_id for '*' code try again for inactive plpc
          select sizedefinition.sizedefinition_id
            into lv_size
            from sizedefinition
           where sizedefinition.code = '*';
          if lv_size = sizedefinitionid -- in iteration 3 was size * already tried, because size * was passed.
            then i := i + 1;  -- skip iteration 4
          end if;
        end if;
      end if;
    end loop; -- end while i < 5
    /* ##################### E N D   O U T E R L O O P ############################################################*/
    if price_found then
      price            := lv_price;
      price_found_yn   := 'Y';
      price_start_date := lv_price_start_date;
      result_code      := 0;
      result_desc      := decode_error('Y' || to_char(result_code));
      price_list_type  := lv_pricelist_type;
      price_list_code  := lv_pricelist_code;
      if lv_pricelist_type = 'G'
        then price_list_desc := lv_pricelist_desc;
        else price_list_desc := 'Customer Specific.';
      end if;
    else
      if result_code is null then -- no price found
        result_code := 1;
      end if;
      result_desc := decode_error('N' || result_code);
    end if;
  exception
    when no_data_found then
      result_code := 1; -- no price found (often because fin method * not defined)
      result_desc := decode_error('N' || result_code);
    when others then
      result_code := 9;
      result_desc := decode_error('N' || result_code) || sqlerrm; -- ora error
  end Get_Loan_Price_details;

/*--------------------------------------------------------------------------------------------------------*/
function Loan_Price_Details(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null)
 return varchar2 is
  /* See package header for description of return string.   */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Loan_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc);
      return(rpad(nvl(to_char(price, '999999D9999'), ' '), 12) ||
             price_found_yn ||
             rpad(nvl(to_char(price_start_date, 'YYYYMMDD'),' '), 8) ||
             rpad(nvl(price_list_type, ' '), 1) ||
             rpad(nvl(substr(price_list_code,1,6), ' '), 6) ||  -- part 1  pos 1-6
             rpad(nvl(price_list_desc, ' '), 40) ||
             rpad(nvl(to_char(result_code), ' '), 1) ||
             rpad(nvl(result_desc, ' '), 80) ||
             rpad(nvl(substr(price_list_code,7,9), ' '), 9)  -- part 2  pos 7-15
             );
    end Loan_Price_Details;

/*--------------------------------------------------------------------------------------------------------*/
function Loan_Price(customerid        in customer.customer_id%type,
                    productid         in product.product_id%type,
                    sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                    finishingmethodid in finishingmethod.finishingmethod_id%type,
                    pricedate         in pricelistpercustomer.dateactive%type default null)
 return number is
  /* Returns the loan price, if not found, returns 0.  For use in calculations.  */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Loan_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc);
      return(nvl(price,0));
    end Loan_Price;

/*--------------------------------------------------------------------------------------------------------*/
function Loan_Price_Display(customerid        in customer.customer_id%type,
                            productid         in product.product_id%type,
                            sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                            finishingmethodid in finishingmethod.finishingmethod_id%type,
                            pricedate         in pricelistpercustomer.dateactive%type default null)
 return number is
  /* Returns the loan price, if not found, returns null.  For display/print purposes. */

    price                   customerrentprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerrentprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      Get_Loan_Price_Details(customerid,
                             productid,
                             sizedefinitionid,
                             finishingmethodid,
                             pricedate,
                             price,
                             price_found_yn,
                             price_start_date,
                             result_code,
                             result_desc,
                             price_list_type,
                             price_list_code,
                             price_list_desc);
      return(price);
    end Loan_Price_Display;

/*--------------------------------------------------------------------------------------------------------*/
function Budget_Price (
       FPcustomerid customerbudgetdefinition.customer_id%type,
       FPcode       customerbudgetdefinition.code%type,
       FPreferencedate   date
       ) return number is
  /* Returns the budget price, if not found, returns 0.  For use in calculations.  */
  vcustbudgetdefid customerbudgetdefinition.customerbudgetdefinition_id%type;
  vprice number;

begin

  select cbd.customerbudgetdefinition_id
    into vcustbudgetdefid
    from customerbudgetdefinition cbd
   where cbd.customer_id = FPcustomerid
     and cbd.code = FPcode;

  begin
  select cbp.price
    into vprice
    from customerbudgetprice cbp
   where cbp.customerbudgetdefinition_id = vcustbudgetdefid
     and cbp.startdate <= FPreferencedate
     and cbp.startdate =
         (select max(cbp.startdate)
            from customerbudgetprice cbp
           where cbp.customerbudgetdefinition_id = vcustbudgetdefid
             and cbp.startdate <= FPreferencedate);

  return vprice;
  exception
    when no_data_found then return 0;
  end;
end Budget_Price;

  function customer_uses_specialprices(customerid in customer.customer_id%type)
    return boolean is
    use_special_prices customer.useprodsizesurchargepricing%type;
  begin
    select c.useprodsizesurchargepricing
      into use_special_prices
      from customer c
     where c.customer_id = customerid;
    return use_special_prices = 'Y';
  exception
    when no_data_found then
      return false;
  end customer_uses_specialprices;
  
  function get_standard_szbillinggroup return number is
    standard_sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
  begin
    select sz.sizebillinggroup_id
      into standard_sizebillinggroupid
      from sizebillinggroup sz
     where sz.standard = 'Y';
    return standard_sizebillinggroupid;
  exception
    when no_data_found then
      return 0;
  end get_standard_szbillinggroup;
  
  function get_product_size_billinggroup(productid in product.product_id%type,
                                         sizeid    in sizedefinition.sizedefinition_id%type)
    return number is
    sizebillinggroupid sizebillinggroup.sizebillinggroup_id%type;
    lv_sizestarid         sizedefinition.sizedefinition_id%type;
  begin
    select ps.sizebillinggroup_id
      into sizebillinggroupid
      from productsize ps
     where ps.product_id = productid
       and ps.sizedefinition_id = sizeid;
     
    if (sizebillinggroupid is null) then
      select sd.sizedefinition_id
      into lv_sizestarid
      from sizedefinition sd
      where sd.code = '*';
      
      if (sizeid = lv_sizestarid) then
         select sd.sizebillinggroup_id
         into sizebillinggroupid
         from sizedefinition sd
         where sd.sizedefinition_id = lv_sizestarid;
      end if;
    end if;
    return nvl(sizebillinggroupid, 0);
  exception
    when no_data_found then
      begin
        select sd.sizebillinggroup_id
          into sizebillinggroupid
          from sizedefinition sd
         where sd.sizedefinition_id = sizeid;
        return sizebillinggroupid;
      exception
        when no_data_found then
          return 0;
      end;
  end get_product_size_billinggroup;

  procedure get_size_billing_groups(customerid                     in customer.customer_id%type,
                                    productid                      in product.product_id%type,
                                    sizedefinitionid               in sizedefinition.sizedefinition_id%type,
                                    pricetype                      number,
                                    lv_standard_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type,
                                    lv_specific_sizebillinggroupid out sizebillinggroup.sizebillinggroup_id%type) is
  
    lv_customer_uses_sz_billing    boolean;
    lv_ss_sizespecialchargeoptions int;
    lv_is_special_size_price_used  boolean;
  begin
    begin
      select value
        into lv_ss_sizespecialchargeoptions
        from systemsetting st
        join businessunit bu
          on bu.plant_id = st.plant_id
        join customer c
          on c.defaultbusinessunit_id = bu.businessunit_id
       where st.name = 'SIZESPECIALCHARGEOPTIONS'
         and c.customer_id = customerid;
    exception
      when no_data_found then
        lv_ss_sizespecialchargeoptions := 0;
    end;
    if pricetype = 2 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 1 or
                                       lv_ss_sizespecialchargeoptions = 4 or
                                       lv_ss_sizespecialchargeoptions = 5 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    if pricetype = 3 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 3 or
                                       lv_ss_sizespecialchargeoptions = 5 or
                                       lv_ss_sizespecialchargeoptions = 6 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    if pricetype = 4 then
      lv_is_special_size_price_used := lv_ss_sizespecialchargeoptions = 2 or
                                       lv_ss_sizespecialchargeoptions = 4 or
                                       lv_ss_sizespecialchargeoptions = 6 or
                                       lv_ss_sizespecialchargeoptions = 7;
    end if;
    lv_customer_uses_sz_billing    := customer_uses_specialprices(customerid);
    lv_standard_sizebillinggroupid := get_standard_szbillinggroup();
    if lv_customer_uses_sz_billing and lv_is_special_size_price_used then
      lv_specific_sizebillinggroupid := get_product_size_billinggroup(productid,
                                                                      sizedefinitionid);
    else
      lv_specific_sizebillinggroupid := lv_standard_sizebillinggroupid;
    end if;
  
  end get_size_billing_groups;

END PACK_PRICE_OLD;

/
create or replace PACKAGE PACK_PRODLISTPERDISTRIBPOINT is

procedure CFbStoreOrCreate (
        FPnPRODLISTPERDISTRIBPOINT_ID             in out PRODUCTLISTPERDISTRIBPOINT.PRODUCTLISTPERDISTRIBPOINT_ID%type,
				FPnSTANDARDDELIVERYLINE_ID                in out STANDARDDELIVERYLINE.STANDARDDELIVERYLINE_ID%type,
				FPnSTANDARDDELIVERY_ID                    in out STANDARDDELIVERYLINE.STANDARDDELIVERY_ID%type,
        FPsLOCATION																in out STANDARDDELIVERYLINE.LOCATION%type,
        FPnDISTRIBUTIONPOINT_ID                   in out PRODUCTLISTPERDISTRIBPOINT.DISTRIBUTIONPOINT_ID%type,
        FPnPRODUCT_ID                             in out PRODUCTLISTPERDISTRIBPOINT.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out PRODUCTLISTPERDISTRIBPOINT.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out PRODUCTLISTPERDISTRIBPOINT.FINISHINGMETHOD_ID%type,
        FPnCOUNTSEQUENCE                          in out PRODUCTLISTPERDISTRIBPOINT.COUNTSEQUENCE%type,
        FPnORDERINGMETHOD                         in out PRODUCTLISTPERDISTRIBPOINT.ORDERINGMETHOD%type,
        FPnHOLIDAYUSAGEFACTOR                     in out PRODUCTLISTPERDISTRIBPOINT.HOLIDAYUSAGEFACTOR%type,
				FPdtDATEACTIVE                            in out STANDARDDELIVERYLINE.DATEACTIVE%type,
				FPdtDATEINACTIVE													in out STANDARDDELIVERYLINE.DATEINACTIVE%type,
				FPnDELIVERYSCHEME_ID											in out STANDARDDELIVERYLINE.DELIVERYSCHEME_ID%type,
        FPnSYSTEMUSER_ID                          in out PRODUCTLISTPERDISTRIBPOINT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out PRODUCTLISTPERDISTRIBPOINT.TIMESTAMP%type,
				FPnAmountMO                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountTU                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountWE                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountTH                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountFR                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountSA                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountSU                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type);

procedure CFbStoreStdDelAmount(
				FPnSTANDARDDELIVERYLINE_ID                in     STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
				FPnDAY_ID																	in     STANDARDDELIVERYAMOUNT.DAY_ID%type,
				FPnAMOUNT                                 in     STANDARDDELIVERYAMOUNT.AMOUNT%type,
        FPnSYSTEMUSER_ID                          in     STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in     STANDARDDELIVERYAMOUNT.TIMESTAMP%type);

end PACK_PRODLISTPERDISTRIBPOINT;




/
create or replace PACKAGE BODY PACK_PRODLISTPERDISTRIBPOINT is

procedure CFbStoreOrCreate (
        FPnPRODLISTPERDISTRIBPOINT_ID             in out PRODUCTLISTPERDISTRIBPOINT.PRODUCTLISTPERDISTRIBPOINT_ID%type,
				FPnSTANDARDDELIVERYLINE_ID                in out STANDARDDELIVERYLINE.STANDARDDELIVERYLINE_ID%type,
				FPnSTANDARDDELIVERY_ID                    in out STANDARDDELIVERYLINE.STANDARDDELIVERY_ID%type,
        FPsLOCATION																in out STANDARDDELIVERYLINE.LOCATION%type,
        FPnDISTRIBUTIONPOINT_ID                   in out PRODUCTLISTPERDISTRIBPOINT.DISTRIBUTIONPOINT_ID%type,
        FPnPRODUCT_ID                             in out PRODUCTLISTPERDISTRIBPOINT.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out PRODUCTLISTPERDISTRIBPOINT.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out PRODUCTLISTPERDISTRIBPOINT.FINISHINGMETHOD_ID%type,
        FPnCOUNTSEQUENCE                          in out PRODUCTLISTPERDISTRIBPOINT.COUNTSEQUENCE%type,
        FPnORDERINGMETHOD                         in out PRODUCTLISTPERDISTRIBPOINT.ORDERINGMETHOD%type,
        FPnHOLIDAYUSAGEFACTOR                     in out PRODUCTLISTPERDISTRIBPOINT.HOLIDAYUSAGEFACTOR%type,
				FPdtDATEACTIVE                            in out STANDARDDELIVERYLINE.DATEACTIVE%type,
				FPdtDATEINACTIVE													in out STANDARDDELIVERYLINE.DATEINACTIVE%type,
				FPnDELIVERYSCHEME_ID											in out STANDARDDELIVERYLINE.DELIVERYSCHEME_ID%type,
        FPnSYSTEMUSER_ID                          in out PRODUCTLISTPERDISTRIBPOINT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out PRODUCTLISTPERDISTRIBPOINT.TIMESTAMP%type,
				FPnAmountMO                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountTU                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountWE                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountTH                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountFR                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountSA                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
				FPnAmountSU                               in out STANDARDDELIVERYAMOUNT.AMOUNT%type
) is
begin
		if FPnCOUNTSEQUENCE = -1 then
    	select nvl(max(COUNTSEQUENCE),0)+1 into FPnCOUNTSEQUENCE
      	from PRODUCTLISTPERDISTRIBPOINT
	    where DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID;
    end if;
    insert into PRODUCTLISTPERDISTRIBPOINT(
        PRODUCTLISTPERDISTRIBPOINT_ID,
        DISTRIBUTIONPOINT_ID,
        PRODUCT_ID,
        SIZEDEFINITION_ID,
        FINISHINGMETHOD_ID,
        COUNTSEQUENCE,
        ORDERINGMETHOD,
        HOLIDAYUSAGEFACTOR,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        SEQ_PRODUCTLISTPERDISTRIBPOINT.nextval,
        FPnDISTRIBUTIONPOINT_ID,
        FPnPRODUCT_ID,
        FPnSIZEDEFINITION_ID,
        FPnFINISHINGMETHOD_ID,
        FPnCOUNTSEQUENCE,
        FPnORDERINGMETHOD,
        FPnHOLIDAYUSAGEFACTOR,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    ) returning PRODUCTLISTPERDISTRIBPOINT_ID into FPnPRODLISTPERDISTRIBPOINT_ID;

    insert into STANDARDDELIVERYLINE(
        STANDARDDELIVERYLINE_ID,
        STANDARDDELIVERY_ID,
        PRODUCTLISTPERDISTRIBPOINT_ID,
        LOCATION,
				DATEACTIVE,
				DATEINACTIVE,
				DELIVERYSCHEME_ID,
        SYSTEMUSER_ID,
        TIMESTAMP,
				FIXEDRENTQUANTITY--,
        --TEMPORARYSTOPSTARTWEEK, TEMPORARYSTOPENDWEEK,
				--Temporarystopstartyear, Temporarystopendyear,
				--Tempstoprentforweek, Tempstoprentforyearweek,
				--Tempstopstartweekforyear, Tempstopendweekforyear
    )
    values (
        SEQ_STANDARDDELIVERYLINE.nextval,
        FPnSTANDARDDELIVERY_ID,
        FPnPRODLISTPERDISTRIBPOINT_ID,
        FPsLOCATION,
				FPdtDATEACTIVE,
				FPdtDATEINACTIVE,
				FPnDELIVERYSCHEME_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
				0--, 0, 0, 0, 0, 'N', 'N', 0, 0
    ) returning STANDARDDELIVERYLINE_ID into FPnSTANDARDDELIVERYLINE_ID;

		if (FPnAmountMO != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 1, FPnAmountMO, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountTU != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 2, FPnAmountTU, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountWE != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 3, FPnAmountWE, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountTH != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 4, FPnAmountTH, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountFR != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 5, FPnAmountFR, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountSA != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 6, FPnAmountSA, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountSU != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 7, FPnAmountSU, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;

exception
	when dup_val_on_index then
    update PRODUCTLISTPERDISTRIBPOINT
    set
        HOLIDAYUSAGEFACTOR = FPnHOLIDAYUSAGEFACTOR,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID
        and PRODUCT_ID = FPnPRODUCT_ID
        and SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID
        and FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID
    returning PRODUCTLISTPERDISTRIBPOINT_ID into FPnPRODLISTPERDISTRIBPOINT_ID;

    begin
		    insert into STANDARDDELIVERYLINE(
    		    STANDARDDELIVERYLINE_ID,
        		STANDARDDELIVERY_ID,
		        PRODUCTLISTPERDISTRIBPOINT_ID,
    		    LOCATION,
						DATEACTIVE,
						DATEINACTIVE,
						DELIVERYSCHEME_ID,
        		SYSTEMUSER_ID,
		        TIMESTAMP,
						FIXEDRENTQUANTITY--,
						--TEMPORARYSTOPSTARTWEEK, TEMPORARYSTOPENDWEEK,
						--TEMPORARYSTOPSTARTYEAR, TEMPORARYSTOPENDYEAR,
						--TEMPSTOPSTARTWEEKFORYEAR, TEMPSTOPENDWEEKFORYEAR,
						--TEMPSTOPRENTFORWEEK, TEMPSTOPRENTFORYEARWEEK
    		)
		    values (
    		    SEQ_STANDARDDELIVERYLINE.nextval,
        		FPnSTANDARDDELIVERY_ID,
		        FPnPRODLISTPERDISTRIBPOINT_ID,
    		    FPsLOCATION,
						FPdtDATEACTIVE,
						FPdtDATEINACTIVE,
						FPnDELIVERYSCHEME_ID,
        		FPnSYSTEMUSER_ID,
		        FPdtTIMESTAMP,
						0--, 0, 0, 0, 0, 0, 0, 'N', 'N'
    		) returning STANDARDDELIVERYLINE_ID into FPnSTANDARDDELIVERYLINE_ID;
    exception
    	when dup_val_on_index then
		    update STANDARDDELIVERYLINE
    		set
    		    LOCATION = FPsLOCATION,
						DATEACTIVE = FPdtDATEACTIVE,
						DATEINACTIVE = FPdtDATEINACTIVE,
						DELIVERYSCHEME_ID = FPnDELIVERYSCHEME_ID,
        		SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
		        TIMESTAMP = FPdtTIMESTAMP
    		where STANDARDDELIVERY_ID = FPnSTANDARDDELIVERY_ID and
        			PRODUCTLISTPERDISTRIBPOINT_ID = FPnPRODLISTPERDISTRIBPOINT_ID and
							DATEACTIVE = FPdtDATEACTIVE and
							SEASON_ID is null
		    returning STANDARDDELIVERYLINE_ID into FPnSTANDARDDELIVERYLINE_ID;
				delete from standarddeliveryamount where standarddeliveryline_id = FPnSTANDARDDELIVERYLINE_ID;
		end;

		if (FPnAmountMO != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 1, FPnAmountMO, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountTU != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 2, FPnAmountTU, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountWE != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 3, FPnAmountWE, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountTH != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 4, FPnAmountTH, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountFR != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 5, FPnAmountFR, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountSA != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 6, FPnAmountSA, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;
		if (FPnAmountSU != 0) then
			CFbStoreStdDelAmount(FPnSTANDARDDELIVERYLINE_ID, 7, FPnAmountSU, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
		end if;

end;

procedure CFbStoreStdDelAmount(
				FPnSTANDARDDELIVERYLINE_ID                in     STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
				FPnDAY_ID																	in     STANDARDDELIVERYAMOUNT.DAY_ID%type,
				FPnAMOUNT                                 in     STANDARDDELIVERYAMOUNT.AMOUNT%type,
        FPnSYSTEMUSER_ID                          in     STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in     STANDARDDELIVERYAMOUNT.TIMESTAMP%type
) is
begin
	insert into STANDARDDELIVERYAMOUNT (STANDARDDELIVERYLINE_ID, DAY_ID, AMOUNT, SYSTEMUSER_ID, TIMESTAMP)
	values (FPnSTANDARDDELIVERYLINE_ID, FPnDAY_ID, FPnAMOUNT, FPnSYSTEMUSER_ID, FPdtTIMESTAMP);
end;


end;



/
create or replace package pack_purge is
  /**************************************************************\
  *   -- Author  : HVH/PVD                                       *
  *   -- Version : 1.10                                          *
  *   -- Created : 30-6-2010                                     *
  *   -- Purpose : Cleanup/purge historical data                 *
  *                Using tables PurgeTable and                   *
  *                PurgeConfig                                   *
  *   -- Changes : 28-2-2022 ABS-128679 2 small changes (log)    *
  *                09-3-2022 ABS-128679 change to log, show date *
  *                10-1-2023 ABS-158910 log  date for table that *
  *                15-1-2024 ABS-160212 Change log in Pack_Purge *
  *  25-1-2024  ABS-160383 Improvements to Log in Pack Purge     *
  *  16-9-2024  ABS-169079 cleanup ok weekly in previous century *
  *  16-10-2024 ABS-169885 small log enhancement in pack_purge   *
  \**************************************************************/
  function genericpurge(fp_plant_id       in plant.plant_id%type,
                        fp_plantprocessid in plantprocess.plantprocess_id%type) return number;
end pack_purge;
/
create or replace package body pack_purge is
  function genericpurge(fp_plant_id       in plant.plant_id%type,
                        fp_plantprocessid in plantprocess.plantprocess_id%type) return number is
    ----------locale variables
    lv_cursornum              integer;
    lv_numrows                integer;
    lv_ignore                 integer;
    lv_count                  number;
    lv_numchunks              integer;
    lv_whereclause            varchar2(2000);
    lv_maxweekstopurge        integer;
    lv_oldest_date            date;
    lv_purge_until_date       date;
    lv_sql_stmnt              varchar2(4000);
    lv_message                abslogprocessjobline.message%type;
    lv_abslogprocessjobid     abslogprocessjob.abslogprocessjob_id%type;
    lv_abslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type;
    lv_systemuserid           systemuser.systemuser_id%type;
    lv_processname            abslogprocessjobpart.processname%type;
    return_ok           constant integer := 0;
    return_failed_purge constant integer := -1;
    gv_returnvalue      number := return_ok;
    gv_maxcleanupdate   date;
    gv_cleanup_weeks2go number;

    ----------locale procedure/functions
    procedure end_log is
    begin
      --end_log
      abslogwrite.abslogprocessjob_update(lv_abslogprocessjobid, sysdate, lv_systemuserid);
    exception
      when others then
        begin
          dbms_output.put_line(lv_message);
          dbms_output.put_line(sqlerrm);
        end;
    end end_log;

    procedure write_log(fp_priority abslogprocessjobline.priority%type default 1) is
    begin
      --write_log
      if lv_abslogprocessjobid is null then
        lv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(fp_plant_id, sysdate, null, null,
                                                                    fp_plantprocessid,
                                                                    lv_systemuserid);
      end if;
      --write_log part
      if lv_abslogprocessjobpartid is null and lv_abslogprocessjobid is not null then
        lv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(lv_abslogprocessjobid,
                                                                            lv_processname,
                                                                            lv_systemuserid);
      end if;
      --write line
      abslogwrite.abslogprocessjobline_write(lv_abslogprocessjobpartid, fp_priority, lv_message,
                                             lv_systemuserid);
    exception
      when others then
        begin
          --give output when cannot safe error logs
          dbms_output.put_line(lv_message);
          dbms_output.put_line(sqlerrm);
        end;
    end write_log;

    procedure intitialize is
    begin
      --intitialize
      lv_systemuserid := 0;
      lv_count        := 0;
      execute immediate 'alter session set nls_date_format = ''DD-MM-YYYY''';
    end intitialize;

    procedure get_systemsetting is
    begin
      lv_message := ' get_systemsetting plant id ' || fp_plant_id;
      --get_systemsetting
      begin
        select to_number(nvl(s.value, '0'))
        into   lv_maxweekstopurge
        from   systemsetting s
        where  s.plant_id = fp_plant_id
        and    s.name = 'MAXWEEKSTOPURGEPERRUN';
      exception
        when others then
          lv_maxweekstopurge := 3;
      end;
      if lv_maxweekstopurge = 0 then
        lv_maxweekstopurge := 3;
      end if;
    end get_systemsetting;

    procedure build_where_clause(fp_whereclause    in varchar2,
                                 fp_plantfieldname in purgetable.plantfieldname%type,
                                 fp_bufieldname    in purgetable.businessunitfieldname%type,
                                 fp_datefieldname  in purgetable.datefieldname%type,
                                 fp_weekstokeep    in purgeplantconfig.numberofweekstokeep%type) is
    begin
      -- prepare where clause
      lv_message     := ' build_where_clause';
      lv_whereclause := fp_whereclause;
      if lv_whereclause is not null then
        lv_whereclause := ' (' || lv_whereclause || ') and ';
      end if;
      if fp_plantfieldname is not null then
        lv_whereclause := lv_whereclause || ' ' || fp_plantfieldname || '=' || fp_plant_id ||
                          ' and ';
      end if;
      if fp_bufieldname is not null then
        lv_whereclause := lv_whereclause || ' ' || fp_bufieldname ||
                          ' in (select b.businessunit_id from businessunit b where b.plant_id=' ||
                          fp_plant_id || ') and ';
      end if;
      gv_maxcleanupdate := trunc(sysdate) - (fp_weekstokeep * 7);
      lv_whereclause    := lv_whereclause || fp_datefieldname || ' < (trunc(sysdate) - (' ||
                           fp_weekstokeep || ' * 7))';
    end build_where_clause;
  begin
    gv_returnvalue := return_ok;
    ----------Main process starts
    intitialize;
    get_systemsetting;
    ----loop through tables that must be cleaned up----
    for x in (select t.tablename, t.whereclause, t.datefieldname, t.hint, t.plantfieldname,
                     t.businessunitfieldname, nvl(t.commitsize, 5000) commitsize,
                     p.numberofweekstokeep, t.description
              from   purgetable t
              join   purgeplantconfig p
              on     p.purgetable_id = t.purgetable_id
              where  p.plant_id = fp_plant_id
              order  by t.tablename) loop
      begin
        --set variables
        lv_processname            := x.tablename || ' [' || x.description || ']';
        lv_abslogprocessjobpartid := null;
        --build_where_clause
        build_where_clause(x.whereclause, x.plantfieldname, x.businessunitfieldname,
                           x.datefieldname, x.numberofweekstokeep);
        --prepare hint clause
        if nvl(x.hint, '-1') <> '-1' then
          x.hint := '/*' || x.hint || '*/';
        end if;
        -- STEP 1 Initial Select oldest date --
        lv_message   := 'STEP 1 For ' || x.tablename || ' table data will be deleted older than ' ||
                        x.numberofweekstokeep || ' weeks, max ' || lv_maxweekstopurge ||
                        ' weeks per run';
        lv_cursornum := dbms_sql.open_cursor;
        lv_sql_stmnt := 'select min( ' || x.datefieldname || ') from ' || x.tablename || ' where ' ||
                        lv_whereclause;
        dbms_sql.parse(lv_cursornum, lv_sql_stmnt, dbms_sql.v7);
        write_log(1);
        dbms_sql.define_column(lv_cursornum, 1, lv_oldest_date);
        lv_ignore := dbms_sql.execute(lv_cursornum);
        lv_ignore := dbms_sql.fetch_rows(lv_cursornum);
        dbms_sql.column_value(lv_cursornum, 1, lv_oldest_date);
        dbms_sql.close_cursor(lv_cursornum);
        --only cleanup when oldest date is not null
        if lv_oldest_date is not null then
          begin
            -- else there is no data to purge
            lv_purge_until_date := lv_oldest_date + (lv_maxweekstopurge * 7);
            -- STEP 2 Initial Select count
            lv_message   := 'STEP 2 Starting delete this run on  ' ||
                            to_char(lv_oldest_date, 'dd-mm-yyyy');
            lv_cursornum := dbms_sql.open_cursor;
            lv_sql_stmnt := 'select count(1) from ' || x.tablename || ' where ' || lv_whereclause ||
                            ' and ' || x.datefieldname || ' < to_date(''' || lv_purge_until_date ||
                            ''')';
            dbms_sql.parse(lv_cursornum, lv_sql_stmnt, dbms_sql.v7);
            write_log(1);
            dbms_sql.define_column(lv_cursornum, 1, lv_numrows);
            lv_ignore := dbms_sql.execute(lv_cursornum);
            lv_ignore := dbms_sql.fetch_rows(lv_cursornum);
            dbms_sql.column_value(lv_cursornum, 1, lv_numrows);
            dbms_sql.close_cursor(lv_cursornum);
            lv_numchunks := trunc(lv_numrows / x.commitsize) + 1;
            -- STEP 3 Loop to delete in chunks
            lv_message := 'STEP 3 Loop to delete in chunks for table ' || x.tablename || ' ' ||
                          x.description;
            write_log(1);
            lv_count := 0;
            for i in 1 .. lv_numchunks loop
              begin
                lv_cursornum := dbms_sql.open_cursor;
                lv_sql_stmnt := 'delete ' || x.hint || ' from ' || x.tablename || ' where ' ||
                                lv_whereclause || ' and ' || x.datefieldname || ' < to_date(''' ||
                                lv_purge_until_date || ''')' || ' and rownum <= ' || x.commitsize;
                lv_message   := 'Deleting for ' || x.description || ' chunk ' || i;
                write_log(1);
                dbms_sql.parse(lv_cursornum, lv_sql_stmnt, dbms_sql.v7);
                lv_ignore := dbms_sql.execute(lv_cursornum);
                lv_count  := lv_count + lv_ignore;
                dbms_sql.close_cursor(lv_cursornum);
                commit;
              exception
                when others then
                  begin
                    rollback;
                    lv_message := 'Delete from ' || x.tablename ||
                                  ' table not possible. Next error occurred: ' || sqlerrm;
                    write_log(3);
                    gv_returnvalue := return_failed_purge;
                  end;
              end;
            end loop; -- for i in 1 .. lv_numchunks
            --determine the number of weeks we still need to cleanup
            select max(((select dy.weekseq from date_yearweekday dy where dy.date_ = trunc(sysdate)) -
                        dw.weekseq)) - x.numberofweekstokeep to_cleanup_weektogo
            into   gv_cleanup_weeks2go
            from   date_yearweekday dw
            where  dw.date_ = least(gv_maxcleanupdate, lv_purge_until_date);
            --logging
            lv_message := lv_count || ' records from ' || x.tablename ||
                          ' deleted. Oldest record now ' ||
                          to_char(least(gv_maxcleanupdate, lv_purge_until_date), 'dd-mm-yyyy') ||
                          ' Still ' || nvl(greatest(gv_cleanup_weeks2go, 0), 999) ||
                          ' weeks to go.';
            write_log(1);
          end;
        else
          begin
            lv_message := 'No ' || x.tablename || ' found older than ' || x.numberofweekstokeep ||
                          ' weeks ! ' || ' Nothing found to delete for ' || x.tablename || ' - ' ||
                          x.description;
            write_log(2);
          end;
        end if; --lv_oldest_date is not null
      end;
    end loop; --x
    return gv_returnvalue;
    end_log;
    ----------Main process ends
  exception
    when others then
      begin
        --errors
        rollback;
        write_log(3);
        end_log;
        gv_returnvalue := return_failed_purge;
        return gv_returnvalue;
      end;
  end genericpurge;
end pack_purge;
/
create or replace PACKAGE PACK_RAGGEDITEM is

procedure CFbStoreOrCreate (
        FPnRAGGEDITEM_ID                          in out RAGGEDITEM.RAGGEDITEM_ID%type,
        FPsPRIMARYID                              in out RAGGEDITEM.PRIMARYID%type,
        FPsSECONDARYID                            in out RAGGEDITEM.SECONDARYID%type,
        FPdtRAGTIMESTAMP                          in out RAGGEDITEM.RAGTIMESTAMP%type,
        FPnRAGREASON_ID                           in out RAGGEDITEM.RAGREASON_ID%type,
        FPnGARMSEQUENCENUMBER                     in out RAGGEDITEM.GARMSEQUENCENUMBER%type,
        FPnPREVSTATUS_ID                          in out RAGGEDITEM.PREVSTATUS_ID%type,
        FPnPREVSTAY_ID                            in out RAGGEDITEM.PREVSTAY_ID%type,
        FPnPRODUCT_LINK_ID                        in out RAGGEDITEM.PRODUCT_LINK_ID%type,
        FPnSIZEDEFINITION_LINK_ID                 in out RAGGEDITEM.SIZEDEFINITION_LINK_ID%type,
        FPnPOOLITEM                               in out RAGGEDITEM.POOLITEM%type,
        FPdtPURCHASEDATE                          in out RAGGEDITEM.PURCHASEDATE%type,
        FPdtLASTONSTOCKDATE                       in out RAGGEDITEM.LASTONSTOCKDATE%type,
        FPdtFIRSTISSUEDATE                        in out RAGGEDITEM.FIRSTISSUEDATE%type,
        FPdtLASTISSUEDATE                         in out RAGGEDITEM.LASTISSUEDATE%type,
        FPnNUMBEROFISSUES                         in out RAGGEDITEM.NUMBEROFISSUES%type,
        FPdtENDDATEFULLRENT                       in out RAGGEDITEM.ENDDATEFULLRENT%type,
        FPnQUALITYGRADE_ID                        in out RAGGEDITEM.QUALITYGRADE_ID%type,
        FPnWASHESTOTAL                            in out RAGGEDITEM.WASHESTOTAL%type,
        FPnREPAIRSTOTAL                           in out RAGGEDITEM.REPAIRSTOTAL%type,
        FPnREWASHTOTAL                            in out RAGGEDITEM.REWASHTOTAL%type,
        FPnDAYSINCIRCULATION                      in out RAGGEDITEM.DAYSINCIRCULATION%type,
        FPnDAYSINSTOCK                            in out RAGGEDITEM.DAYSINSTOCK%type,
        FPnSUPPLIER_ID                            in out RAGGEDITEM.SUPPLIER_ID%type,
        FPnPURCHASEPRICE                          in out RAGGEDITEM.PURCHASEPRICE%type,
        FPsCUSTOMEROWNED                          in out RAGGEDITEM.CUSTOMEROWNED%type,
        FPnRELATEDCUSTOMERLINK_ID                 in out RAGGEDITEM.RELATEDCUSTOMERLINK_ID%type,
        FPnLASTWEAREREMPLOYMENT_LINK              in out RAGGEDITEM.LASTWEAREREMPLOYMENT_LINK_ID%type,
        FPnREASONCODE_ID                          in out RAGGEDITEM.REASONCODE_ID%type,
        FPnRESIDUALVALUE                          in out RAGGEDITEM.RESIDUALVALUE%type,
        FPnLASTDISTRIBUTIONPOINT_LINK             in out RAGGEDITEM.LASTDISTRIBUTIONPOINT_LINK_ID%type,
        FPnBUSINESSUNIT_ID                        in out RAGGEDITEM.BUSINESSUNIT_ID%type,
        FPnWEAREREMPLOYMENT_LINK_ID               in out RAGGEDITEM.WEAREREMPLOYMENT_LINK_ID%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out RAGGEDITEM.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnSYSTEMUSER_ID                          in out RAGGEDITEM.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out RAGGEDITEM.TIMESTAMP%type);

end PACK_RAGGEDITEM;


/
create or replace PACKAGE BODY PACK_RAGGEDITEM is

procedure CFbStoreOrCreate (
        FPnRAGGEDITEM_ID                          in out RAGGEDITEM.RAGGEDITEM_ID%type,
        FPsPRIMARYID                              in out RAGGEDITEM.PRIMARYID%type,
        FPsSECONDARYID                            in out RAGGEDITEM.SECONDARYID%type,
        FPdtRAGTIMESTAMP                          in out RAGGEDITEM.RAGTIMESTAMP%type,
        FPnRAGREASON_ID                           in out RAGGEDITEM.RAGREASON_ID%type,
        FPnGARMSEQUENCENUMBER                     in out RAGGEDITEM.GARMSEQUENCENUMBER%type,
        FPnPREVSTATUS_ID                          in out RAGGEDITEM.PREVSTATUS_ID%type,
        FPnPREVSTAY_ID                            in out RAGGEDITEM.PREVSTAY_ID%type,
        FPnPRODUCT_LINK_ID                        in out RAGGEDITEM.PRODUCT_LINK_ID%type,
        FPnSIZEDEFINITION_LINK_ID                 in out RAGGEDITEM.SIZEDEFINITION_LINK_ID%type,
        FPnPOOLITEM                               in out RAGGEDITEM.POOLITEM%type,
        FPdtPURCHASEDATE                          in out RAGGEDITEM.PURCHASEDATE%type,
        FPdtLASTONSTOCKDATE                       in out RAGGEDITEM.LASTONSTOCKDATE%type,
        FPdtFIRSTISSUEDATE                        in out RAGGEDITEM.FIRSTISSUEDATE%type,
        FPdtLASTISSUEDATE                         in out RAGGEDITEM.LASTISSUEDATE%type,
        FPnNUMBEROFISSUES                         in out RAGGEDITEM.NUMBEROFISSUES%type,
        FPdtENDDATEFULLRENT                       in out RAGGEDITEM.ENDDATEFULLRENT%type,
        FPnQUALITYGRADE_ID                        in out RAGGEDITEM.QUALITYGRADE_ID%type,
        FPnWASHESTOTAL                            in out RAGGEDITEM.WASHESTOTAL%type,
        FPnREPAIRSTOTAL                           in out RAGGEDITEM.REPAIRSTOTAL%type,
        FPnREWASHTOTAL                            in out RAGGEDITEM.REWASHTOTAL%type,
        FPnDAYSINCIRCULATION                      in out RAGGEDITEM.DAYSINCIRCULATION%type,
        FPnDAYSINSTOCK                            in out RAGGEDITEM.DAYSINSTOCK%type,
        FPnSUPPLIER_ID                            in out RAGGEDITEM.SUPPLIER_ID%type,
        FPnPURCHASEPRICE                          in out RAGGEDITEM.PURCHASEPRICE%type,
        FPsCUSTOMEROWNED                          in out RAGGEDITEM.CUSTOMEROWNED%type,
        FPnRELATEDCUSTOMERLINK_ID                 in out RAGGEDITEM.RELATEDCUSTOMERLINK_ID%type,
        FPnLASTWEAREREMPLOYMENT_LINK              in out RAGGEDITEM.LASTWEAREREMPLOYMENT_LINK_ID%type,
        FPnREASONCODE_ID                          in out RAGGEDITEM.REASONCODE_ID%type,
        FPnRESIDUALVALUE                          in out RAGGEDITEM.RESIDUALVALUE%type,
        FPnLASTDISTRIBUTIONPOINT_LINK             in out RAGGEDITEM.LASTDISTRIBUTIONPOINT_LINK_ID%type,
        FPnBUSINESSUNIT_ID                        in out RAGGEDITEM.BUSINESSUNIT_ID%type,
        FPnWEAREREMPLOYMENT_LINK_ID               in out RAGGEDITEM.WEAREREMPLOYMENT_LINK_ID%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out RAGGEDITEM.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnSYSTEMUSER_ID                          in out RAGGEDITEM.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out RAGGEDITEM.TIMESTAMP%type)is
begin
  begin
   insert into RAGGEDITEM(
        RAGGEDITEM_ID,
        PRIMARYID,
        SECONDARYID,
        RAGTIMESTAMP,
        RAGREASON_ID,
        GARMSEQUENCENUMBER,
        PREVSTATUS_ID,
        PREVSTAY_ID,
        PRODUCT_LINK_ID,
        SIZEDEFINITION_LINK_ID,
        POOLITEM,
        PURCHASEDATE,
        LASTONSTOCKDATE,
        FIRSTISSUEDATE,
        LASTISSUEDATE,
        NUMBEROFISSUES,
        ENDDATEFULLRENT,
        QUALITYGRADE_ID,
        WASHESTOTAL,
        REPAIRSTOTAL,
        REWASHTOTAL,
        DAYSINCIRCULATION,
        DAYSINSTOCK,
        SUPPLIER_ID,
        PURCHASEPRICE,
        CUSTOMEROWNED,
        RELATEDCUSTOMERLINK_ID,
        LASTWEAREREMPLOYMENT_LINK_ID,
        REASONCODE_ID,
        RESIDUALVALUE,
        LASTDISTRIBUTIONPOINT_LINK_ID,
        BUSINESSUNIT_ID,
        WEAREREMPLOYMENT_LINK_ID,
        DISTRIBUTIONPOINT_LINK_ID,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        SEQ_UNIQUEITEM.nextval,
        FPsPRIMARYID,
        FPsSECONDARYID,
        FPdtRAGTIMESTAMP,
        FPnRAGREASON_ID,
        FPnGARMSEQUENCENUMBER,
        FPnPREVSTATUS_ID,
        FPnPREVSTAY_ID,
        FPnPRODUCT_LINK_ID,
        FPnSIZEDEFINITION_LINK_ID,
        FPnPOOLITEM,
        FPdtPURCHASEDATE,
        FPdtLASTONSTOCKDATE,
        FPdtFIRSTISSUEDATE,
        FPdtLASTISSUEDATE,
        FPnNUMBEROFISSUES,
        FPdtENDDATEFULLRENT,
        FPnQUALITYGRADE_ID,
        FPnWASHESTOTAL,
        FPnREPAIRSTOTAL,
        FPnREWASHTOTAL,
        FPnDAYSINCIRCULATION,
        FPnDAYSINSTOCK,
        FPnSUPPLIER_ID,
        FPnPURCHASEPRICE,
        FPsCUSTOMEROWNED,
        FPnRELATEDCUSTOMERLINK_ID,
        FPnLASTWEAREREMPLOYMENT_LINK,
        FPnREASONCODE_ID,
        FPnRESIDUALVALUE,
        FPnLASTDISTRIBUTIONPOINT_LINK,
        FPnBUSINESSUNIT_ID,
        FPnWEAREREMPLOYMENT_LINK_ID,
        FPnDISTRIBUTIONPOINT_LINK_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
    select SEQ_UNIQUEITEM.currval into FPnRAGGEDITEM_ID from dual;
    insert into UNIQUEITEM_LINK(
        UNIQUEITEM_LINK_ID,
        UNIQUEITEM_ID,
        RAGGEDITEM_ID,
        SYSTEMUSER_ID,
        TIMESTAMP)
    values (
        FPnRAGGEDITEM_ID,
        null,
        FPnRAGGEDITEM_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
  exception
  	when dup_val_on_index then
	     update RAGGEDITEM
    set
        PRIMARYID = FPsPRIMARYID,
        SECONDARYID = FPsSECONDARYID,
        RAGTIMESTAMP = FPdtRAGTIMESTAMP,
        RAGREASON_ID = FPnRAGREASON_ID,
        GARMSEQUENCENUMBER = FPnGARMSEQUENCENUMBER,
        PREVSTATUS_ID = FPnPREVSTATUS_ID,
        PREVSTAY_ID = FPnPREVSTAY_ID,
        PRODUCT_LINK_ID = FPnPRODUCT_LINK_ID,
        SIZEDEFINITION_LINK_ID = FPnSIZEDEFINITION_LINK_ID,
        POOLITEM = FPnPOOLITEM,
        PURCHASEDATE = FPdtPURCHASEDATE,
        LASTONSTOCKDATE = FPdtLASTONSTOCKDATE,
        FIRSTISSUEDATE = FPdtFIRSTISSUEDATE,
        LASTISSUEDATE = FPdtLASTISSUEDATE,
        NUMBEROFISSUES = FPnNUMBEROFISSUES,
        ENDDATEFULLRENT = FPdtENDDATEFULLRENT,
        QUALITYGRADE_ID = FPnQUALITYGRADE_ID,
        WASHESTOTAL = FPnWASHESTOTAL,
        REPAIRSTOTAL = FPnREPAIRSTOTAL,
        REWASHTOTAL = FPnREWASHTOTAL,
        DAYSINCIRCULATION = FPnDAYSINCIRCULATION,
        DAYSINSTOCK = FPnDAYSINSTOCK,
        SUPPLIER_ID = FPnSUPPLIER_ID,
        PURCHASEPRICE = FPnPURCHASEPRICE,
        CUSTOMEROWNED = FPsCUSTOMEROWNED,
        RELATEDCUSTOMERLINK_ID = FPnRELATEDCUSTOMERLINK_ID,
        LASTWEAREREMPLOYMENT_LINK_ID = FPnLASTWEAREREMPLOYMENT_LINK,
        REASONCODE_ID = FPnREASONCODE_ID,
        RESIDUALVALUE = FPnRESIDUALVALUE,
        LASTDISTRIBUTIONPOINT_LINK_ID = FPnLASTDISTRIBUTIONPOINT_LINK,
        BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID,
        WEAREREMPLOYMENT_LINK_ID = FPnWEAREREMPLOYMENT_LINK_ID,
        DISTRIBUTIONPOINT_LINK_ID = FPnDISTRIBUTIONPOINT_LINK_ID,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
      where BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID and
            PRIMARYID = FPsPRIMARYID and
            RAGTIMESTAMP = FPdtRAGTIMESTAMP;
		-- get ID
		select RAGGEDITEM_ID
			into FPnRAGGEDITEM_ID
			from RAGGEDITEM
			where BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID and
            PRIMARYID = FPsPRIMARYID and
            RAGTIMESTAMP = FPdtRAGTIMESTAMP;
  end;
end;


end PACK_RAGGEDITEM;


/
create or replace package pack_railimportdefinition is

  /***********************************************************************\
  * Package Pack_RailImportDefinition Version 2.4                         *
  *                                                                       *
  * ABS-141976 21/02/2022 sorting database table and procedures           *
  * ABS-168848 Adjustment package railimportdefinition / ABS-169850       *
  * Additional changes provided by customer                               *
  \***********************************************************************/

  --Import a file and insert or update the railimportdefinition
  /*-----------------------------------------------------------------------
  Optionally FLAG or CUSTOMER + one or more extra fields other then the flag field
  #    Field description
  -------------------------------------------------------------------------
  1    Business unit code MUST BE FILLED not null allowed
  2    Flag code
  3    Customer number
  4    Department number
  5    Garmentdispenser code
  6    Deliverypoint code --> needed for locker, and then must be filled
  7    Bank --> can be left blank
  8    Locker --> together with field 5 and 6 determines the locker !
  9    Wearer number
  10   Product code
  11   Size code
  12   Finishingmethod code
  13   Railimportdefinition (length 6)
  -------------------------------------------------------------------------*/
  procedure import_railimportdefinition(fp_filename  in varchar2,
                                        fp_importdir in varchar2,
                                        fp_separator in varchar2 default ';');

  --get_railimportdefinition, returns railimportdefinition for first combo found
  function get_railimportdefinition(fp_businessunit_id    in number, --must be filled
                                    fp_flagid             in number default null,
                                    fp_customerid         in number default null,
                                    fp_departmentid       in number default null,
                                    fp_garmentdispenserid in number default null,
                                    fp_lockerid           in number default null,
                                    fp_wearerid           in number default null,
                                    fp_productid          in number default null,
                                    fp_sizeid             in number default null,
                                    fp_finishingmethodid  in number default null)
    return varchar2;

  --returns makesacn = Y when an rail import definition has been found
  procedure getgarmentdatarail2(fp_idcode    in uniqueitem.primaryid%type,
                                fp_plantcode in out plant.code%type,
                                fp_rail      out nocopy varchar2,
                                fp_makescan  out nocopy varchar2);
  procedure getgarmentdatarail(idcode      in uniqueitem.primaryid%type,
                               plantcode   in out plant.code%type,
                               sortaddress out nocopy varchar2,
                               makescan    out nocopy varchar2);

end pack_railimportdefinition;
/
create or replace package body pack_railimportdefinition is

  procedure import_railimportdefinition(fp_filename  in varchar2,
                                        fp_importdir in varchar2,
                                        fp_separator in varchar2 default ';') is
    --Import a file and insert or update the railimportdefinition
    /*-----------------------------------------------------------------------
    Optionally FLAG or CUSTOMER + one or more extra fields other then the flag field
    #    Field description
    -------------------------------------------------------------------------
    1 Business Unit code
    2  Flag code
    3  Customer number
    4  Customer name
    5  Department number
    6  Department description
    7  Garmentdispenser code
    8  Deliverypoint code --> needed for locker, and then must be filled
    9  Bank --> can be left blank
    10 Locker --> together with field 5 and 6 determines the locker !
    11 Wearer number
    12 Wearer name
    13 Product code
    14 Product desc
    15 Size code
    16 Size desc
    17 Finishingmethod code
    18 Finishing method desc
    19 Railimportdefinition (length 6)
    20  Actie D or Empty, when D delete the line from the table, when empty insert or update.

    -------------------------------------------------------------------------*/
    --Import Rail Import Definition
    --
    --Global variables
    gv_user__exception exception;
    gv_text            abslog.message%type;
    gv_line_counter    number := 0;
    gv_lines_imported  number := 0;
    gv_lines_deleted   number := 0;
    gv_error_count     number := 0;
    gv_update_count    number := 0;
    gv_input           utl_file.file_type;
    gv_export          utl_file.file_type;
    gv_changes         number := 0;
    --
    ---internal procedures/functions
    procedure write_log(fp_message in varchar2 default null, fp_priority in number) is
    begin
      abslogwrite.abslog_write(5, 'import_railimportdefinition', null, fp_priority, fp_message);
      begin
        dbms_output.put_line(fp_message);
      exception
        when others then
          null; --ok no output does not matter
      end;
    end write_log;

    function open_xfile return utl_file.file_type is
    begin
      --open file
      gv_text := 'Read file ' || fp_filename || ' in directory ' || fp_importdir;
      return utl_file.fopen(fp_importdir, fp_filename, 'r', 32767);
    exception
      when utl_file.invalid_path then
        raise_application_error(-20100, 'Invalid Path');
      when utl_file.invalid_mode then
        raise_application_error(-20101, 'Invalid Mode');
      when utl_file.invalid_operation then
        raise_application_error(-20102, 'Invalid Operation');
      when utl_file.invalid_filehandle then
        raise_application_error(-20103, 'Invalid FileHandle');
      when utl_file.write_error then
        raise_application_error(-20104, 'Write Error');
      when utl_file.read_error then
        raise_application_error(-20105, 'Read Error');
      when utl_file.internal_error then
        raise_application_error(-20106, 'Internal Error');
    end open_xfile;

    function open_wfile return utl_file.file_type is
    begin
      --open file
      gv_text := 'Open export file ' || 'import_rail_definition.exp' || ' in directory ' || fp_importdir;
      return utl_file.fopen(fp_importdir, 'import_rail_definition.exp', 'w');
    exception
      when utl_file.invalid_path then
        raise_application_error(-20100, 'Invalid Path');
      when utl_file.invalid_mode then
        raise_application_error(-20101, 'Invalid Mode');
      when utl_file.invalid_operation then
        raise_application_error(-20102, 'Invalid Operation');
      when utl_file.invalid_filehandle then
        raise_application_error(-20103, 'Invalid FileHandle');
      when utl_file.write_error then
        raise_application_error(-20104, 'Write Error');
      when utl_file.read_error then
        raise_application_error(-20105, 'Read Error');
      when utl_file.internal_error then
        raise_application_error(-20106, 'Internal Error');
    end open_wfile;

    procedure load_file is
      lv_readline             varchar2(4000);
      lv_businessunitid       businessunit.businessunit_id%type;
      lv_flagid               flag.flag_id%type;
      lv_customerid           customer.customer_id%type;
      lv_departmentid         department.department_id%type;
      lv_wearerid             wearer.wearer_id%type;
      lv_deliverypointid      deliverypoint.deliverypoint_id%type;
      lv_bank                 locker.bank%type;
      lv_lockerid             locker.locker_id%type;
      lv_garmentdispenserid   garmentdispenser.garmentdispenser_id%type;
      lv_productid            product.product_id%type;
      lv_sizeid               sizedefinition.sizedefinition_id%type;
      lv_finishingmethodid    finishingmethod.finishingmethod_id%type;
      lv_railimportdefinition railimportdefinition.railimportdefinition%type;
      lv_rowcount             number;
      lv_action               varchar2(1);
      lv_customername         customer.name%type;
      lv_departmentdesc       department.description%type;
      lv_wearername           wearer.fullname%type;
      lv_productdesc          product_desc.description%type;
      lv_sizedesc             sizedefinition_desc.description%type;
      lv_fm_desc              finishingmethod_desc.description%type;

      procedure get_businessunitid(fp_businessunitcode in businessunit.code%type) is
      begin
        --get_businessunitid
        gv_text := 'businessunit ' || nvl(fp_businessunitcode, 'NULL');
        select bu.businessunit_id
        into   lv_businessunitid
        from   businessunit bu
        where  bu.code = fp_businessunitcode;
      end get_businessunitid;

      procedure get_flagid(fp_flagcode in flag.code%type) is
      begin
        --get_flagid
        if fp_flagcode is null then
          lv_flagid := null;
        else
          begin
            gv_text := 'flag ' || nvl(fp_flagcode, 'NULL') || ' flag type 1';
            select f.flag_id
            into   lv_flagid
            from   flag f
            where  f.code = fp_flagcode
            and    f.flagtype = 1;
          end;
        end if;
      end get_flagid;

      ---procedure get_customerid(fp_customernumber in customer.customernumber%type) is
      procedure get_customerid(fp_customernumber in customer.customernumber%type, fp_flagcode in flag.code%type) is

      begin
        --get_customerid
        if fp_customernumber is null and fp_flagcode is null then
          begin
            lv_customerid := null;
            gv_text       := 'Customer cannot be left blank if flag is also blank!';
            raise gv_user__exception;
          end;
        elsif fp_customernumber is null then
          begin
            lv_customerid := null;
          end;
        else
          begin
            gv_text := 'customer ' || nvl(to_char(fp_customernumber), 'NULL');
            select c.customer_id
            into   lv_customerid
            from   customer c
            where  c.customernumber = fp_customernumber;
          end;
        end if;
      end get_customerid;

      procedure get_departmentid(fp_departmentnumber in department.departmentnumber%type) is
      begin
        --get_departmentid
        gv_text := 'department ' || nvl(to_char(fp_departmentnumber), 'NULL') ||
                   ' for customer id ' || nvl(to_char(lv_customerid), 'NULL');
        if fp_departmentnumber is null then
          begin
            lv_departmentid := null;
          end;
        else
          begin
            select t.department_id
            into   lv_departmentid
            from   department t
            where  t.departmentnumber = fp_departmentnumber
            and    t.customer_id = lv_customerid;
          end;
        end if;
      end get_departmentid;

      procedure get_deliverypointid(fp_deliverypointcode in deliverypoint.code%type) is
      begin
        --get_deliverypointid
        if fp_deliverypointcode is null then
          lv_deliverypointid := null;
        else
          begin
            gv_text := 'deliverypoint ' || nvl(fp_deliverypointcode, 'NULL') || ' for customer id ' ||
                       nvl(to_char(lv_customerid), 'NULL');
            select cc.deliverypoint_id
            into   lv_deliverypointid
            from   deliverypoint cc
            where  cc.code = fp_deliverypointcode
            and    cc.customer_id = lv_customerid;
          end;
        end if;
      end get_deliverypointid;

      procedure get_lockerid(fp_locker in locker.locker%type) is
      begin
        --get_lockerid
        if fp_locker is null then
          lv_lockerid := null;
        else
          begin
            gv_text := 'locker ' || nvl(to_char(fp_locker), 'NULL') || ' bank ' ||
                       nvl(to_char(lv_bank), 'NULL') || ' for customer id ' ||
                       nvl(to_char(lv_customerid), 'NULL') || ' for deliverypoint id ' ||
                       nvl(to_char(lv_deliverypointid), 'NULL');
            if lv_bank is null then
              begin
                select t.locker_id
                into   lv_lockerid
                from   locker t
                where  t.locker = fp_locker
                and    t.bank is null
                and    t.deliverypoint_id = lv_deliverypointid
                and    t.customer_id = lv_customerid;
              end;
            else
              begin
                select t.locker_id
                into   lv_lockerid
                from   locker t
                where  t.locker = fp_locker
                and    t.bank = lv_bank
                and    t.deliverypoint_id = lv_deliverypointid
                and    t.customer_id = lv_customerid;
              end;
            end if;
          end;
        end if;
      end get_lockerid;

      procedure get_garmentdispenserid(fp_garmentdispenser in garmentdispenser.code%type) is
      begin
        --get_garmentdispenserid
        if fp_garmentdispenser is null then
          lv_garmentdispenserid := null;
        else
          begin
            gv_text := 'garmentdispenser ' || nvl(to_char(fp_garmentdispenser), 'NULL') ||
                       ' for customer id ' || nvl(to_char(lv_customerid), 'NULL');
            select t.garmentdispenser_id
            into   lv_garmentdispenserid
            from   garmentdispenser t
            where  t.code = fp_garmentdispenser
            and    t.customer_id = lv_customerid;
          end;
        end if;
      end get_garmentdispenserid;

      procedure get_wearerid(fp_wearernumber wearer.wearernumber%type) is
      begin
        --get_wearerid
        if fp_wearernumber is null then
          lv_wearerid := null;
        else
          begin
            gv_text := 'wearer ' || nvl(to_char(fp_wearernumber), 'NULL') || ' for customer id ' ||
                       nvl(to_char(lv_customerid), 'NULL');
            select w.wearer_id
            into   lv_wearerid
            from   wearer w
            where  w.customer_id = lv_customerid
            and    w.wearernumber = fp_wearernumber;
          end;
        end if;
      end get_wearerid;

      procedure get_productid(fp_productcode in product.code%type,
                              fp_tom_product in number default 2) is
        lv_tom_product product.typeofmerchandise%type;
      begin
        --get_productid
        if fp_productcode is null then
          lv_productid := null;
        else
          begin
            gv_text := 'product ' || nvl(fp_productcode, 'NULL');
            select s.product_id, s.typeofmerchandise
            into   lv_productid, lv_tom_product
            from   product s
            where  s.code = fp_productcode;
            if fp_tom_product <> lv_tom_product then
              begin
                gv_text := 'product ' || nvl(fp_productcode, 'NULL') || ' has TOM ' ||
                           to_char(lv_tom_product) || ' required is ' || fp_tom_product;
                raise gv_user__exception;
              end;
            end if;
          end;
        end if;
      end get_productid;

      procedure get_sizeid(fp_sizecode in sizedefinition.code%type) is
      begin
        --get_sizeid
        if fp_sizecode is null then
          lv_sizeid := null;
        else
          begin
            gv_text := 'size ' || nvl(fp_sizecode, 'NULL');
            select s.sizedefinition_id
            into   lv_sizeid
            from   sizedefinition s
            where  s.code = fp_sizecode;
          end;
        end if;
      end get_sizeid;

      procedure get_finishingmethodid(fp_finishingmethodcode in finishingmethod.code%type) is
      begin
        --get_finishingmethodid
        if fp_finishingmethodcode is null then
          lv_finishingmethodid := null;
        else
          begin
            gv_text := 'finishingmethod ' || fp_finishingmethodcode;
            select rg.finishingmethod_id
            into   lv_finishingmethodid
            from   finishingmethod rg
            where  rg.code = fp_finishingmethodcode;
          end;
        end if;
      end get_finishingmethodid;

      ----load_file
    procedure load_line(fp_readline in varchar2) is
      function get_valuepos(fp_xmessage in varchar2, fp_position in number)
        return varchar2 is
        lv_start_pos number;
        lv_next_pos  number;
      begin
        --get_nextvalue
        gv_text      := 'Get value ' || fp_xmessage || ' position ' ||
                        to_char(fp_position);
        lv_start_pos := case
                          when fp_position = 1 then
                           1
                          else
                           instr(fp_readline, fp_separator, 1, fp_position - 1) + 1
                        end;
        lv_next_pos  := instr(fp_readline, fp_separator, lv_start_pos);
        if (lv_next_pos - lv_start_pos) < 0 then
        --if lv_next_pos = 0  then
          return substr(fp_readline, lv_start_pos);
        else
          return substr(fp_readline,
                        lv_start_pos,
                        lv_next_pos - lv_start_pos);
        end if;
      end get_valuepos;
    begin
      --load_line fields data
      get_businessunitid(get_valuepos('Businessunit field 1 ', 1));
      get_flagid(get_valuepos('Flag field 2 ', 2));

      --get_customerid(get_valuepos('Customer field 3 ', 3),);
      get_customerid(get_valuepos('Customer field 3 ', 3), get_valuepos('Flag field 2 ', 2));
      lv_customername := get_valuepos('Customer name field 4 ', 4);
      get_departmentid(get_valuepos('Department field 5 ', 5));
      lv_departmentdesc := get_valuepos('Department desc field 6 ', 6);
      get_garmentdispenserid(get_valuepos('Garment dispenser field 7 ', 7));
      get_deliverypointid(get_valuepos('Deliverypoint field 8 ', 8));
      lv_bank := get_valuepos('Bank field 9 ', 9);
      get_lockerid(get_valuepos('Locker field 10 ', 10));
      get_wearerid(get_valuepos('Wearer field 11 ', 11));
      lv_wearername := get_valuepos('Wearer name field 12 ', 12);
      get_productid(get_valuepos('Product field 13 ', 13));
      lv_productdesc := get_valuepos('Product desc field 14 ', 14);
      get_sizeid(get_valuepos('Size field 15 ', 15));
      lv_sizedesc := get_valuepos('Size desc field 16 ', 16);
      get_finishingmethodid(get_valuepos('Finisihgmethod field 17 ', 17));
      lv_fm_desc := get_valuepos('Finisihgmethod desc field 18 ', 18);

      lv_railimportdefinition := get_valuepos('Railimportdefinition field 19 ', 19);
      --lv_action := get_valuepos('Action field 20 ', 20);
      lv_action := substr(get_valuepos('Action field 20 ', 20), 1, 1);

      if lv_railimportdefinition is null then
        begin
          gv_text := 'Field 19 for Railimportdefinition cannot be left blank!';
          raise gv_user__exception;
        end;
      end if;

      if lv_action = 'D' and lv_flagid is null then
        --delete the record
        gv_text := 'delete railimportdefinition';
        delete from railimportdefinition rl
         where rl.businessunit_id = lv_businessunitid
           and rl.customer_id = lv_customerid
           and (rl.department_id = lv_departmentid or
               (rl.department_id is null and lv_departmentid is null))
           and (rl.garmentdispenser_id = lv_garmentdispenserid or
               (rl.garmentdispenser_id is null and
               lv_garmentdispenserid is null))
           and (rl.locker_id = lv_lockerid or
               (rl.locker_id is null and lv_lockerid is null))
           and (rl.wearer_id = lv_wearerid or
               (rl.wearer_id is null and lv_wearerid is null))
           and (rl.product_id = lv_productid or
               (rl.product_id is null and lv_productid is null))
           and (rl.size_id = lv_sizeid or
               (rl.size_id is null and lv_sizeid is null))
           and (rl.finishingmethod_id = lv_finishingmethodid or
               (rl.finishingmethod_id is null and
               lv_finishingmethodid is null));
        --gv_changes := gv_changes + 1;
        gv_lines_deleted := gv_lines_deleted + 1;

       elsif lv_action = 'D' and lv_flagid is not null then
      --delete the record
        gv_text := 'delete railimportdefinition';
        delete from railimportdefinition rl
            where rl.flag_id = lv_flagid
              and rl.businessunit_id = lv_businessunitid;
        gv_lines_deleted := gv_lines_deleted + 1;

      else
        --insert the record
        gv_text := 'insert into railimportdefinition';
        if lv_flagid is not null then
          begin
            --update the duplicate railimportdefinition for flag
            gv_text := 'update railimportdefinition for flag id ' ||
                       to_char(lv_flagid);
            update railimportdefinition rl
               set rl.railimportdefinition = lv_railimportdefinition,
                   rl.timestamp            = sysdate,
                   rl.systemuser_id        = 1
             where rl.flag_id = lv_flagid
               and rl.businessunit_id = lv_businessunitid;
            lv_rowcount := sql%rowcount;
            gv_changes := gv_changes + 1;
          end;
        else
          begin
            --update the duplicate railimportdefinition for customer ...
            gv_text := 'update railimportdefinition for customer id ' ||
                       to_char(lv_customerid);
            update railimportdefinition rl
               set rl.railimportdefinition = lv_railimportdefinition,
                   rl.timestamp            = sysdate,
                   rl.systemuser_id        = 1
             where rl.businessunit_id = lv_businessunitid
               and rl.customer_id = lv_customerid
               and (rl.department_id = lv_departmentid or
                   (rl.department_id is null and lv_departmentid is null))
               and (rl.garmentdispenser_id = lv_garmentdispenserid or
                   (rl.garmentdispenser_id is null and
                   lv_garmentdispenserid is null))
               and (rl.locker_id = lv_lockerid or
                   (rl.locker_id is null and lv_lockerid is null))
               and (rl.wearer_id = lv_wearerid or
                   (rl.wearer_id is null and lv_wearerid is null))
               and (rl.product_id = lv_productid or
                   (rl.product_id is null and lv_productid is null))
               and (rl.size_id = lv_sizeid or
                   (rl.size_id is null and lv_sizeid is null))
               and (rl.finishingmethod_id = lv_finishingmethodid or
                   (rl.finishingmethod_id is null and
                   lv_finishingmethodid is null));
            gv_changes := gv_changes + 1;
            lv_rowcount := sql%rowcount;
          end;
        end if;
        gv_update_count := gv_update_count + nvl(lv_rowcount, 0);
        if lv_rowcount = 0 then
          begin
            insert into railimportdefinition
              (railimportdefinition_id,
               flag_id,
               customer_id,
               department_id,
               garmentdispenser_id,
               locker_id,
               wearer_id,
               product_id,
               size_id,
               finishingmethod_id,
               railimportdefinition,
               businessunit_id)
            values
              (seq_railimportdefinition.nextval,
               lv_flagid,
               lv_customerid,
               lv_departmentid,
               lv_garmentdispenserid,
               lv_lockerid,
               lv_wearerid,
               lv_productid,
               lv_sizeid,
               lv_finishingmethodid,
               lv_railimportdefinition,
               lv_businessunitid);

                gv_lines_imported := gv_lines_imported + 1;
            --gv_changes := gv_changes + 1;
          end;
        end if;

      end if; -- lv_action = 'D'
      commit;
      --line impored counter
      --gv_lines_imported := gv_lines_imported + 1;
    exception
      when gv_user__exception then
        begin
          gv_error_count := gv_error_count + 1;
          write_log('Line# ' || gv_line_counter || ' Error ' || gv_text ||
                    ' file ' || fp_filename,
                    3);
        end;
      when no_data_found then
        begin
          gv_error_count := gv_error_count + 1;
          write_log('Line# ' || gv_line_counter || ' No data found for ' ||
                    gv_text || ' file ' || fp_filename,
                    3);
        end;
      when others then
        begin
          gv_error_count := gv_error_count + 1;
          write_log('Line# ' || gv_line_counter || ' Error ' || sqlerrm || ' ' ||
                    gv_text || ' file ' || fp_filename,
                    3);
        end;
    end load_line;
    begin
    --load_file
    gv_text := 'load_file ' || nvl(fp_filename, '<Empty>') || ' directory ' || nvl(fp_importdir, '<Empty>');

    --loop go through lines
    loop begin
      begin
        -- get line from file.
        utl_file.get_line(gv_input, lv_readline);
        gv_line_counter := gv_line_counter + 1;
          exception when no_data_found then exit;
      end;
      --load_line, skip header line
      if gv_line_counter > 1 then
        gv_text := 'Line# ' || gv_line_counter;
        load_line(lv_readline);
      end if;
      end;
    end loop;
    end load_file;

    procedure close_file is
    lv_date  varchar2(13);
    begin
      SELECT to_char(sysdate,'YYYYMMDDHH24MM_') INTO lv_date FROM DUAL;
      --always rename the file
      utl_file.frename(fp_importdir, fp_filename, fp_importdir, lv_date || fp_filename);
      --close file
      if utl_file.is_open(gv_input) = true then
        utl_file.fclose(gv_input);
      end if;
      if utl_file.is_open(gv_export) = true then
        utl_file.fclose(gv_export);
      end if;
      utl_file.fclose_all;
    end close_file;

    procedure export_file is
    lv_language_id languages.language_id%type;
    begin
      gv_export := open_wfile;

      select min(l.language_id) into lv_language_id from languages l;

    --Create header line

     utl_file.put_line(gv_export,
                            'businessunit' || fp_separator || 'flag' ||
                            fp_separator || 'customernumber' || fp_separator ||
                            'customername' || fp_separator || 'departmentnumber' ||
                            fp_separator || 'departmentname' || fp_separator ||
                            'garmentdispenser' || fp_separator || 'deliverypoint' ||
                            fp_separator || 'bank' || fp_separator ||
                            'locker' || fp_separator ||
                            'wearernumber' || fp_separator || 'wearername' ||
                            fp_separator || 'productcode' ||
                            fp_separator || 'productdescription' ||
                            fp_separator || 'sizecode' ||
                            fp_separator || 'sizedescription' ||
                            fp_separator || 'finishingmethodecode' ||
                            fp_separator || 'finishingmethodedesc' ||
                            fp_separator || 'sortaddress' ||
                            fp_separator || 'action' ||
                            fp_separator) ;


      for x in (select b.code bu_code, f.code flag_code, c.customernumber, c.name cust_name, d.departmentnumber,
                  d.description, gd.code gd_code, delp.code delp_code, l.bank, l.locker, w.wearernumber, w.fullname wearer_name,
                  p.code prod_code, (select pd.description from product_desc pd where pd.product_id = p.product_id and pd.language_id = lv_language_id) prod_desc,
                  s.code size_code, (select sd.description from sizedefinition_desc sd where sd.sizedefinition_id = s.sizedefinition_id and sd.language_id = lv_language_id) size_desc,
                  fm.code fm_code, (select fmd.description from finishingmethod_desc fmd where fmd.finishingmethod_id = fm.finishingmethod_id and fmd.language_id = lv_language_id) fm_desc,
                  ri.railimportdefinition
                  from railimportdefinition ri
                  left join flag f
                    on f.flag_id = ri.flag_id
                  left join customer c
                    on c.customer_id = ri.customer_id
                  left join department d
                    on d.department_id = ri.department_id
                  left join garmentdispenser gd
                    on gd.garmentdispenser_id = ri.garmentdispenser_id
                  left join locker l
                    on l.locker_id = ri.locker_id
                  left join deliverypoint delp on delp.deliverypoint_id = l.deliverypoint_id
                  left join wearer w
                    on w.wearer_id = ri.wearer_id
                  left join product p
                    on p.product_id = ri.product_id
                  left join sizedefinition s
                    on s.sizedefinition_id = ri.size_id
                  left join finishingmethod fm
                    on fm.finishingmethod_id = ri.finishingmethod_id
                  left join businessunit b
                    on b.businessunit_id = ri.businessunit_id) loop
        begin
          gv_text := 'railimportdefinition loop';

          --Add lines to the file
          utl_file.put_line(gv_export,
                            x.bu_code || fp_separator || x.flag_code ||
                            fp_separator || x.customernumber || fp_separator ||
                            x.cust_name || fp_separator || x.departmentnumber ||
                            fp_separator || x.description || fp_separator ||
                            x.gd_code || fp_separator || x.delp_code ||
                            fp_separator || x.bank || fp_separator ||
                            x.locker || fp_separator ||
                            x.wearernumber || fp_separator || x.wearer_name ||
                            fp_separator || x.prod_code ||
                            fp_separator || x.prod_desc ||
                            fp_separator || x.size_code ||
                            fp_separator || x.size_desc ||
                            fp_separator || x.fm_code ||
                            fp_separator || x.fm_desc ||
                            fp_separator || x.railimportdefinition ||
                            fp_separator || fp_separator) ;
        end;
      end loop;
    end;

    procedure finalize is
    begin
      --finalize
      if gv_error_count > 0 then
        begin
          --errors so we do a rollback
          rollback;
          gv_text := 'Partially successful imported ' || to_char(gv_lines_imported) ||
                     ' and updated ' || to_char(gv_update_count) || ' and deleted' || to_char(gv_lines_deleted) ||' lines, from a total of ' ||
                     to_char(gv_line_counter - 1) || ' with ' || to_char(gv_error_count) ||
                     ' error lines during import, using directory ' || fp_importdir || ' filename ' ||
                     fp_filename || ' please check the log!';
          write_log(gv_text, 3);
        end;
      else
        begin
          --all ok, we commit
          commit;
         gv_text := 'Imported ' || to_char(gv_lines_imported) || ' and updated ' ||
                     to_char(gv_update_count) || ' and deleted ' || to_char(gv_lines_deleted) ||' lines, from a total of ' ||
                     to_char(gv_line_counter - 1) || ' lines, using directory ' || fp_importdir ||
                     ' filename ' || fp_filename;
          write_log(gv_text, 1);
        end;
      end if;
    end finalize;
  begin
    --initialize, create export file, open/describe cursor
    begin
        gv_input := open_xfile;
    exception
     when others then
        gv_text := 'File does not exist: ' || fp_filename || ' in directory ' || fp_importdir || ' - ' || substr(sqlerrm, 1, 200);
        write_log(gv_text, 2);
        return; -- stop
    end;
    --load_file
    load_file;
    -- export file
    if gv_changes > 0 then
      export_file;
    end if;
    --close_file
    close_file;
    --finalize
    finalize;
  exception
    when others then
      begin
        --close_file
        close_file;
        --create message for info
        gv_text := 'Error during import ' || fp_filename || ' directory ' || fp_importdir || ' ' ||
                   substr(sqlerrm, 1, 200);
        write_log(gv_text, 3);
      end;
  end import_railimportdefinition;

  function get_railimportdefinition(fp_businessunit_id    in number,
                                    fp_flagid             in number default null,
                                    fp_customerid         in number default null,
                                    fp_departmentid       in number default null,
                                    fp_garmentdispenserid in number default null,
                                    fp_lockerid           in number default null,
                                    fp_wearerid           in number default null,
                                    fp_productid          in number default null,
                                    fp_sizeid             in number default null,
                                    fp_finishingmethodid  in number default null) return varchar2 is
    fp_railimportdefinition railimportdefinition.railimportdefinition%type;
  begin
    --get_railimportdefinition, returns the railimportdefinition, for first good combo found
    for x in (select case
                       when r.businessunit_id = fp_businessunit_id then
                        0
                       else
                        1
                     end forrightbu, r.flag_id, r.wearer_id, r.garmentdispenser_id, r.locker_id,
                     r.department_id, r.customer_id, r.finishingmethod_id, r.size_id, r.product_id,
                     r.railimportdefinition
              from   railimportdefinition r
              where  (r.flag_id = fp_flagid or r.flag_id is null)
              and    (r.customer_id = fp_customerid or r.customer_id is null)
              and    (r.department_id = fp_departmentid or r.department_id is null)
              and    (r.garmentdispenser_id = fp_garmentdispenserid or
                    r.garmentdispenser_id is null)
              and    (r.locker_id = fp_lockerid or r.locker_id is null)
              and    (r.wearer_id = fp_wearerid or r.wearer_id is null)
              and    (r.product_id = fp_productid or r.product_id is null)
              and    (r.size_id = fp_sizeid or r.size_id is null)
              and    (r.finishingmethod_id = fp_finishingmethodid or r.finishingmethod_id is null)
              order  by 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) loop
      begin
        fp_railimportdefinition := x.railimportdefinition;
        exit;
      end;
    end loop; --x
    return(fp_railimportdefinition);
  exception
    when no_data_found then
      begin
        return null;
      end;
  end get_railimportdefinition;

  procedure getgarmentdatarail2(fp_idcode    in uniqueitem.primaryid%type,
                                fp_plantcode in out plant.code%type,
                                fp_rail      out nocopy varchar2,
                                fp_makescan  out nocopy varchar2) is
    --Get Garment Data Rail
    --
    --Global variables
    gv_plantid            plant.plant_id%type;
    gv_rec_uniqueitem     uniqueitem%rowtype;
    gv_secondaryid        varchar2(24);
    gv_uistatus           varchar2(2);
    gv_customerid         number;
    gv_departmentid       number;
    gv_garmentdispenserid number;
    gv_lockerid           number;
    gv_wearerid           number;
    --
    ---internal procedures/functions
    procedure write_log(fp_message in varchar2 default null, fp_priority in number default 1) is
    begin
      abslogwrite.abslog_write(5, 'getgarmentdatalts', gv_plantid, nvl(fp_priority, 1), fp_message);
      begin
        dbms_output.put_line(fp_message);
      exception
        when others then
          null; --ok no output does not matter
      end;
    end write_log;

    procedure initialize is
    begin
      --initialize
      fp_makescan := 'N';
      if fp_plantcode is not null then
        begin
          select pt.plant_id into gv_plantid from plant pt where pt.code = fp_plantcode;
        exception
          when no_data_found then
            begin
              gv_plantid   := null;
              fp_plantcode := null;
            end;
        end;
      else
        begin
          gv_plantid := null;
        end;
      end if;
    end initialize;

    procedure proc_railimportdefinition_flags is
    begin
      --proc_railimportdefinition_flags
      for vcursor in (select fo.confirm, f.priority, uf.startdate, f.showalways, f.flag_id
                      from   uniqueitemflag uf
                      join   flag f
                      on     f.flag_id = uf.flag_id
                      join   flagoptions fo
                      on     fo.flag_id = uf.flag_id
                      join   dialogs d
                      on     d.dialog_id = fo.dialog_id
                      where  uf.uniqueitem_id = gv_rec_uniqueitem.uniqueitem_id
                      and    d.code = 'OutScan'
                      and    fo.show = 'Y'
                      and    (f.priority = 1 or f.showalways = 'Y')
                      and    uf.startdate <= sysdate
                      order  by fo.confirm desc, f.priority asc, uf.startdate asc) loop
        begin
          fp_rail := get_railimportdefinition(gv_rec_uniqueitem.businessunit_id, vcursor.flag_id);
          if fp_rail is not null then
            exit;
          end if;
        end;
      end loop;
    end proc_railimportdefinition_flags;

    procedure proc_railimportdefinition is
    begin
      --proc_railimportdefinition
      if gv_rec_uniqueitem.poolitem = 2 then
        begin
          select w.customer_id, dp.department_id, we.garmentdispenser_id, we.locker_id, we.wearer_id
          into   gv_customerid, gv_departmentid, gv_garmentdispenserid, gv_lockerid, gv_wearerid
          from   uniqueitemnonpool un
          join   weareremployment we
          on     we.weareremployment_id = un.weareremployment_id
          join   wearer w
          on     w.wearer_id = we.wearer_id
          join   distributionpoint dp
          on     dp.distributionpoint_id = we.distributionpoint_id
          where  un.uniqueitem_id = gv_rec_uniqueitem.uniqueitem_id;
          --get_railimportdefinition
          fp_rail := get_railimportdefinition(gv_rec_uniqueitem.businessunit_id, null, gv_customerid,
                                              gv_departmentid, gv_garmentdispenserid, gv_lockerid,
                                              gv_wearerid, gv_rec_uniqueitem.product_id,
                                              gv_rec_uniqueitem.sizedefinition_id,
                                              gv_rec_uniqueitem.finishingmethod_id);
        exception
          when no_data_found then
            begin
              gv_customerid         := null;
              gv_departmentid       := null;
              gv_garmentdispenserid := null;
              gv_lockerid           := null;
              gv_wearerid           := null;
            end;
        end;
      end if;
    end proc_railimportdefinition;
  begin
    --initialize
    initialize;
    --get uniqueitem data
    pack_sort2.get_uniqueitem(fp_idcode, fp_plantcode, gv_plantid, gv_rec_uniqueitem,
                              gv_secondaryid);
    --get status
    select st.code
    into   gv_uistatus
    from   status st
    where  st.status_id = gv_rec_uniqueitem.status_id;
    ---------------------------------------------------------------
    --other fields
    if gv_uistatus in ('20', '30') then
      begin
        --process railimportdefinition flags
        proc_railimportdefinition_flags;
        if fp_rail is null then
          begin
            --process railimportdefinition
            proc_railimportdefinition;
          end;
        end if;
      end;
    end if;
    if fp_rail is not null then
      begin
        fp_makescan := 'Y';
      end;
    end if;
  exception
    when others then
      begin
        fp_rail     := null;
        fp_makescan := 'N';
        write_log('IDCode' || fp_idcode || ' Plantcode ' || fp_plantcode || ' ' || sqlerrm, 3);
      end;
  end getgarmentdatarail2;

  procedure getgarmentdatarail(idcode      in uniqueitem.primaryid%type,
                               plantcode   in out plant.code%type,
                               sortaddress out nocopy varchar2,
                               makescan    out nocopy varchar2) is
  begin
    --getgarmentdatarail
    --wrap procedure so parameters have a different name
    pack_railimportdefinition.getgarmentdatarail2(fp_idcode => idcode, fp_plantcode => plantcode,
                                                  fp_rail => sortaddress, fp_makescan => makescan);
  end getgarmentdatarail;

end pack_railimportdefinition;
/
create or replace PACKAGE PACK_RENTALQTYADJUSTMENT is

procedure CFbStoreOrCreate (
        FPnRENTALQTYADJUSTMENT_ID                 in out RENTALQTYADJUSTMENT.RENTALQTYADJUSTMENT_ID%type,
        FPnPRODUCTLISTPERDIP_ID                   in out RENTALQTYADJUSTMENT.PRODUCTLISTPERDISTRIBPOINT_ID%type,
        FPsREMARK                                 in out RENTALQTYADJUSTMENT.REMARK%type,
        FPnQUANTITY                               in out RENTALQTYADJUSTMENT.QUANTITY%type,
        FPdtADJUSTMENTDATE                        in out RENTALQTYADJUSTMENT.ADJUSTMENTDATE%type,
        FPnREASONCODE_ID                          in out RENTALQTYADJUSTMENT.REASONCODE_ID%type,
        FPnSYSTEMUSER_ID                          in out RENTALQTYADJUSTMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out RENTALQTYADJUSTMENT.TIMESTAMP%type,
        FPnDELIVERYVARIATION_ID                   in out RENTALQTYADJUSTMENT.DELIVERYVARIATIONS_ID%type);

end PACK_RENTALQTYADJUSTMENT;



/
create or replace PACKAGE BODY PACK_RENTALQTYADJUSTMENT is

procedure CFbStoreOrCreate (
        FPnRENTALQTYADJUSTMENT_ID                 in out RENTALQTYADJUSTMENT.RENTALQTYADJUSTMENT_ID%type,
        FPnPRODUCTLISTPERDIP_ID                   in out RENTALQTYADJUSTMENT.PRODUCTLISTPERDISTRIBPOINT_ID%type,
        FPsREMARK                                 in out RENTALQTYADJUSTMENT.REMARK%type,
        FPnQUANTITY                               in out RENTALQTYADJUSTMENT.QUANTITY%type,
        FPdtADJUSTMENTDATE                        in out RENTALQTYADJUSTMENT.ADJUSTMENTDATE%type,
        FPnREASONCODE_ID                          in out RENTALQTYADJUSTMENT.REASONCODE_ID%type,
        FPnSYSTEMUSER_ID                          in out RENTALQTYADJUSTMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out RENTALQTYADJUSTMENT.TIMESTAMP%type,
        FPnDELIVERYVARIATION_ID                   in out RENTALQTYADJUSTMENT.DELIVERYVARIATIONS_ID%type
) is
begin
    insert into RENTALQTYADJUSTMENT(
        RENTALQTYADJUSTMENT_ID,
        PRODUCTLISTPERDISTRIBPOINT_ID,
        REMARK,
        QUANTITY,
        ADJUSTMENTDATE,
        REASONCODE_ID,
        SYSTEMUSER_ID,
        TIMESTAMP,
        DELIVERYVARIATIONS_ID
    )
    values (
        SEQ_RENTALQTYADJUSTMENT.nextval,
        FPnPRODUCTLISTPERDIP_ID,
        FPsREMARK,
        FPnQUANTITY,
        FPdtADJUSTMENTDATE,
        FPnREASONCODE_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
        FPnDELIVERYVARIATION_ID
    ) returning RENTALQTYADJUSTMENT_ID into FPnRENTALQTYADJUSTMENT_ID;
exception
	when dup_val_on_index then
    update RENTALQTYADJUSTMENT
 	  set
   	    REMARK = FPsREMARK,
     	  QUANTITY = FPnQUANTITY,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
 	      TIMESTAMP = FPdtTIMESTAMP,
   	    DELIVERYVARIATIONS_ID=FPnDELIVERYVARIATION_ID
    where PRODUCTLISTPERDISTRIBPOINT_ID = FPnPRODUCTLISTPERDIP_ID and
					ADJUSTMENTDATE = FPdtADJUSTMENTDATE and
	       	REASONCODE_ID = FPnREASONCODE_ID
 	  returning RENTALQTYADJUSTMENT_ID into FPnRENTALQTYADJUSTMENT_ID;
end;

end PACK_RENTALQTYADJUSTMENT;



/
create or replace package PACK_RESIDUALVALUEHISTORY is
  /* ----------------------------------------------------------------------------------------------
   * -- Author   : CDS
   * -- Created  : 08-07-2015 .. 08-07-2015
   * -- Package  version 2.4
  /* ---------------------------------------------------------------------------------------------- */
  /*
    08/04/2022          ABS-132808 Residual Value gone / not calculated / week 49
    14/04/2022          ABS-132808 Residual Value Price determined using pack_price_new, with NO FM
    21/04/2022          ABS-125301 Wrong info RV module Urvina Maroc - added correction of RV info in UI
                                   and the determination of RV scheme definition for RV History
    28/04/2022          ABS-134244 RD not recalculated by SQ RV when circ inventory=0
    14/03/2023          ABS-147352 Incorrect RV amounts calculated for JSG
  */

  procedure createSQResidualValueHistory(fp_processPlantID      plant.plant_id%type,
                                         fp_abslogprocessjob_id abslogprocessjob.abslogprocessjob_id%type,
                                         fp_systemUserID        systemuser.systemuser_id%type);

end PACK_RESIDUALVALUEHISTORY;
/
create or replace package body PACK_RESIDUALVALUEHISTORY is

  priority_message constant abslogprocessjobline.priority%type := 1;
  --priority_warning constant abslogprocessjobline.priority%type := 2;
  priority_error constant abslogprocessjobline.priority%type := 3;
  priority_debug constant abslogprocessjobline.priority%type := 5;

  -- private variable declarations
  gv_processname            abslogprocessjobpart.processname%type;
  gv_systemuserid           systemuser.systemuser_id%type := 0;
  gv_abslogprocessjobid     abslogprocessjob.abslogprocessjob_id%type;
  gv_abslogprocessjobpartid abslogprocessjobpart.abslogprocessjobpart_id%type := null;
  gv_plantid                plant.plant_id%type;
  gv_message                abslog.message%type;
  -- private type declarations
  gv_userexception   exception;
  gv_updateexception exception;
  gv_alwaysrecalculaterv number;

  procedure write_log(fp_message  in abslogprocessjobline.message%type,
                      fp_priority in abslogprocessjobline.priority%type default priority_message) is
  begin
    --write_log part
    if gv_abslogprocessjobpartid is null and
       gv_abslogprocessjobid is not null then
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gv_abslogprocessjobid,
                                                                          gv_processname,
                                                                          gv_systemuserid);
    end if;
    if (gv_abslogprocessjobpartid is not null) then
      abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid,
                                             fp_priority,
                                             fp_message,
                                             gv_systemuserid);
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(fp_message);
        dbms_output.put_line(sqlerrm);
        raise gv_userexception;
      end;
  end write_log;

  ---------------------------------------------------------------------------------------------------
  procedure end_log is
  begin
    --end_log
    if gv_abslogprocessjobid is not null then
      abslogwrite.abslogprocessjob_update(gv_abslogprocessjobid,
                                          sysdate,
                                          gv_systemuserid);
      gv_abslogprocessjobid := null;
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(gv_message);
        dbms_output.put_line(sqlerrm);
      end;
  end end_log;

  ----- Internal procedures functions ------------------------------------
  procedure get_wi(fp_wearerinventory            in wearerinventory.wearerinventory_id%type,
                   fp_temporaryrentstopstartdate out wearerinventory.temporaryrentstopstartdate%type,
                   fp_temporaryrentstopenddate   out wearerinventory.temporaryrentstopenddate%type,
                   fp_season_id                  out wearerinventory.season_id%type,
                   fp_dateinactive               out wearerinventory.dateactive%type) is

  begin

    select wi.temporaryrentstopstartdate,
           wi.temporaryrentstopenddate,
           wi.season_id,
           wi.dateinactive
      into fp_temporaryrentstopstartdate,
           fp_temporaryrentstopenddate,
           fp_season_id,
           fp_dateinactive
      from wearerinventory wi
     where wi.wearerinventory_id = fp_wearerinventory;

  exception
    when no_data_found then
      begin
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Wearer inventory information could not be retrieved for wearerinventory_id ' ||
                  fp_wearerinventory,
                  priority_error);
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Get wearer inventory details. Wearer inventory=' ||
                  fp_wearerinventory,
                  priority_error);
        end_log;
      end;

  end get_wi;

  procedure get_plpc(fp_productid       in product.product_id%type,
                     fp_sizedefinition  in sizedefinition.sizedefinition_id%type,
                     fp_finishingmethod in finishingmethod.finishingmethod_id%type,
                     fp_customer        in customer.customer_id%type,
                     fp_plpcid          out productlistpercustomer.productlistpercustomer_id%type) is

  begin

    select coalesce((select plpc.productlistpercustomer_id
                      from productlistpercustomer plpc
                     where plpc.product_id = fp_productid
                       and plpc.sizedefinition_id = fp_sizedefinition
                       and plpc.finishingmethod_id = fp_finishingmethod
                       and plpc.customer_id = fp_customer
                       and sysdate between plpc.dateactive and
                           plpc.dateinactive),
                    (select plpc.productlistpercustomer_id
                       from productlistpercustomer plpc
                      where plpc.product_id = fp_productid
                        and plpc.sizedefinition_id =
                            (select sd.sizedefinition_id
                               from sizedefinition sd
                              where sd.code = '*')
                        and plpc.finishingmethod_id = fp_finishingmethod
                        and plpc.customer_id = fp_customer
                        and sysdate between plpc.dateactive and
                            plpc.dateinactive),
					          (select max(plpc.productlistpercustomer_id)
                      from productlistpercustomer plpc
                     where plpc.product_id = fp_productid
                       and plpc.sizedefinition_id = fp_sizedefinition
                       and plpc.finishingmethod_id = fp_finishingmethod
                       and plpc.customer_id = fp_customer),
					           (select max(plpc.productlistpercustomer_id)
                       from productlistpercustomer plpc
                      where plpc.product_id = fp_productid
                        and plpc.sizedefinition_id =
                            (select sd.sizedefinition_id
                               from sizedefinition sd
                              where sd.code = '*')
                        and plpc.finishingmethod_id = fp_finishingmethod
                        and plpc.customer_id = fp_customer))
      into fp_plpcid
      from dual;

    if fp_plpcid is null then
      write_log('Error CREATESQRESIDUALVALUEHISTORY: ' ||
                'No active PLPC found.' || ' Customer_id=' || fp_customer ||
                ' Product_id=' || fp_productid ||
                ' Sizedefinition_id=' || fp_sizedefinition ||
                ' Finishingmethod_id=' || fp_finishingmethod,
                priority_error);
    end if;

  exception
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Get product list per customer.',
                  priority_error);
        end_log;
      end;

  end get_plpc;

  procedure get_plpc_no_fm(fp_customer       in customer.customer_id%type,
                           fp_productid      in product.product_id%type,
                           fp_sizedefinition in sizedefinition.sizedefinition_id%type,
                           fp_plpcid         out productlistpercustomer.productlistpercustomer_id%type) is

  begin

    select coalesce((select max(plpc.productlistpercustomer_id) keep(dense_rank first order by plpc.dateactive desc NULLS LAST)
                      from productlistpercustomer plpc
                     where plpc.product_id = fp_productid
                       and plpc.sizedefinition_id = fp_sizedefinition
                       and plpc.customer_id = fp_customer
                       and sysdate between plpc.dateactive and
                           plpc.dateinactive),
                    (select max(plpc.productlistpercustomer_id) keep(dense_rank first order by plpc.dateactive desc NULLS LAST)
                       from productlistpercustomer plpc
                      where plpc.product_id = fp_productid
                        and plpc.sizedefinition_id =
                            (select sd.sizedefinition_id
                               from sizedefinition sd
                              where sd.code = '*')
                        and plpc.customer_id = fp_customer
                        and sysdate between plpc.dateactive and
                            plpc.dateinactive))
      into fp_plpcid
      from dual;

    if fp_plpcid is null then
      write_log('Error CREATESQRESIDUALVALUEHISTORY: ' ||
                'No active PLPC found :' || ' Customer_id=' || fp_customer ||
                ' Product_id=' || fp_productid ||
                ' Sizedefinition_id=' || fp_sizedefinition,
                priority_error);
    end if;
  exception
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Get product list per customer without finishing method ',
                  priority_error);
        end_log;
      end;
  end get_plpc_no_fm;

  function get_residual_val_prec(fp_resvaluescheme_id number,
                                 fp_age               number) return number is
    calculated_percentage number := 0;
  begin
    begin
      if fp_age = 0 then
        calculated_percentage := 100;
      else
        select coalesce(max(case
                              when r.definitiontype = 2 -- linear
                               then
                               round(((r.endpercentage - r.startpercentage) /
                                     (r.rangeend - r.rangestart)) * fp_age +
                                     (r.startpercentage * r.rangeend -
                                     r.endpercentage * r.rangestart) /
                                     (r.rangeend - r.rangestart))
                              else -- fixed
                               r.fixedpercentage
                            end),
                        0) calc_percentage
          into calculated_percentage
          from resvalschemedefinition r
         where r.residualvaluescheme_id = fp_resvaluescheme_id
           and r.rangestart <= fp_age
           and r.rangeend >= fp_age
           and fp_age > 0;
      end if;
    exception
      when no_data_found then
        calculated_percentage := 0;
      when others then
        begin
          write_log(sqlerrm, priority_debug);
          write_log('Error CREATESQRESIDUALVALUEHISTORY: Calcualtion residual value percentage',
                    priority_error);
          end_log;
        end;
    end;
    return(calculated_percentage);
  end get_residual_val_prec;

  function get_ui_age(fp_calculationbasis in residualvaluescheme.calculationbasis%type,
                      fp_daysincirc       in uniqueitemfixedinfo.daysincircprevissue%type,
                      fp_lastissuedate    in uniqueitemfixedinfo.lastissuedate%type,
                      fp_washes           in uniqueitem.washestotal%type) return number is
    lv_age number := 0;
  begin
    case fp_calculationbasis
      when 1 then
        if fp_lastissuedate is not null then
          lv_age := ceil((fp_daysincirc + (trunc(sysdate) - trunc(fp_lastissuedate))) / 7);
        end if;
      when 2 then
        lv_age := fp_washes;
      when 3 then
        lv_age := ceil((trunc(sysdate) - trunc(fp_lastissuedate)) / 7);
    end case;
    return lv_age;
  end get_ui_age;

  procedure get_residualvalue(fp_plpcid                  in productlistpercustomer.productlistpercustomer_id%type,
                              fp_daysincirc              in uniqueitemfixedinfo.daysincircprevissue%type,
                              fp_lastissuedate           in uniqueitemfixedinfo.lastissuedate%type,
                              fp_washes                  in uniqueitem.washestotal%type,
                              fp_residualvalueschemeid   out residualvaluescheme.residualvaluescheme_id%type,
                              fp_residualvaluecode       out residualvaluescheme.code%type,
                              fp_calcualtionbasis        out residualvaluescheme.calculationbasis%type,
                              fp_calculationweeks        out residualvaluescheme.calculationweeks%type,
                              fp_pricetype               out residualvaluescheme.replacementpricetype%type,
                              fp_residualvalueprecentage out number) is

    lv_age              number := 0;
    lv_calculationbasis number;
  begin
    select rsv.residualvaluescheme_id,
           rsv.code,
           rsv.replacementpricetype,
           rsv.calculationbasis,
           rsv.calculationweeks
      into fp_residualvalueschemeid,
           fp_residualvaluecode,
           fp_pricetype,
           lv_calculationbasis,
           fp_calculationweeks
      from productlistpercustomer plpc, residualvaluescheme rsv
     where plpc.residualvaluescheme_id = rsv.residualvaluescheme_id
       and plpc.productlistpercustomer_id = fp_plpcid;

    lv_age := get_ui_age(lv_calculationbasis,
                         fp_daysincirc,
                         fp_lastissuedate,
                         fp_washes);
    fp_calcualtionbasis        := lv_calculationbasis;
    fp_residualvalueprecentage := get_residual_val_prec(fp_residualvalueschemeid,
                                                        lv_age);
  exception
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Get residual value.',
                  priority_error);
        end_log;
      end;

  end get_residualvalue;

  procedure get_residualvaluehistory(fp_uniqueitem_id           in uniqueitem.uniqueitem_id%type,
                                     fp_residualvaluehistory_id out number,
                                     fp_calculationdate         out date) is

    lv_residualvaluehistory_id residualvaluehistory.residualvaluehistory_id%type := null;
    lv_calculationdate         residualvaluehistory.calculationdate%type := null;

  begin
    fp_residualvaluehistory_id := null;
    fp_calculationdate         := null;

    select max(rvh.residualvaluehistory_id) keep(dense_rank first order by rvh.calculationdate desc NULLS LAST)
      into lv_residualvaluehistory_id
      from residualvaluehistory rvh, uniqueitem_link uil, uniqueitem ui
     where rvh.uniqueitem_link_id = uil.uniqueitem_link_id
       and uil.uniqueitem_link_id = ui.uniqueitem_id
       and ui.uniqueitem_id = fp_uniqueitem_id;

    fp_residualvaluehistory_id := lv_residualvaluehistory_id;

    if lv_residualvaluehistory_id is not null then
      begin
        select rvh.calculationdate
          into lv_calculationdate
          from residualvaluehistory rvh
         where rvh.transactiontype <> 0
           and rvh.residualvaluehistory_id = lv_residualvaluehistory_id;

        fp_calculationdate := lv_calculationdate;

      exception
        when no_data_found then
          fp_calculationdate         := null;
          fp_residualvaluehistory_id := lv_residualvaluehistory_id;
        when others then
          begin
            write_log(sqlerrm, priority_debug);
            write_log('Error CREATESQRESIDUALVALUEHISTORY: Get residual value history for unique residual value id = ' ||
                      lv_residualvaluehistory_id,
                      priority_error);
            end_log;
          end;
      end;
    end if;

  exception
    when no_data_found then
      fp_residualvaluehistory_id := null;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Get residual value history for unique item id = ' ||
                  fp_uniqueitem_id,
                  priority_error);
        end_log;
      end;

  end get_residualvaluehistory;

  procedure get_rvh_weekly(fp_uniqueitem_id           in uniqueitem.uniqueitem_id%type,
                           fp_residualvaluehistory_id out number) is

  begin
    fp_residualvaluehistory_id := null;

    select max(rvh.residualvaluehistory_id) keep(dense_rank first order by rvh.calculationdate desc NULLS LAST)
      into fp_residualvaluehistory_id
      from residualvaluehistory rvh, uniqueitem_link uil, uniqueitem ui
     where rvh.uniqueitem_link_id = uil.uniqueitem_link_id
       and uil.uniqueitem_link_id = ui.uniqueitem_id
       and ui.uniqueitem_id = fp_uniqueitem_id ;

  exception
    when no_data_found then
      fp_residualvaluehistory_id := null;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Get residual value history for unique item id = ' ||
                  fp_uniqueitem_id,
                  priority_error);
        end_log;
      end;

  end get_rvh_weekly;

  procedure get_rvh_info(fp_residualvaluehistory_id in residualvaluehistory.residualvaluehistory_id%type,
                         fp_record                  out residualvaluehistory%rowtype) is

  begin
    select *
      into fp_record
      from residualvaluehistory rvh
     where rvh.residualvaluehistory_id = fp_residualvaluehistory_id;
  exception
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Procedure get_rvh_info for residualvaluehistory_id= ' ||
                  fp_residualvaluehistory_id,
                  priority_error);
        end_log;
      end;
  end get_rvh_info;

  procedure check_wearer(fp_date in date, fp_wearer_inactive out number) is
  begin
    if fp_date <= sysdate then
      fp_wearer_inactive := 1;
    else
      fp_wearer_inactive := 0;
    end if;
  end check_wearer;

  function f_customer_rent_stop(fp_customerid in customer.customer_id%type)
    return boolean is
    lv_result boolean := false;
    lv_return number;
    lv_year   number;
    lv_date   number;
  begin
    lv_result := true;
    select getyearofweek(sysdate) into lv_year from dual;

    select getweeknumber(sysdate) into lv_date from dual;

    select 1
      into lv_return
      from temporarygarmentrentstop trs
     where trs.customer_id = fp_customerid
       and f_isinyearweeklifespan(trs.startyear,
                                  trs.startweek,
                                  lv_year,
                                  lv_date,
                                  trs.endyear,
                                  trs.endweek) = 1;
     return lv_result;
  exception
    when no_data_found then
      begin
        return false;
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Function f_customer_rent_stop for customer_id= ' ||
                  fp_customerid,
                  priority_error);
        end_log;
      return false;
      end;

  end f_customer_rent_stop;

  function f_check_deposit_stock(fp_plpcid       in customer.customer_id%type,
                                 fp_uniqueitemid in uniqueitem.uniqueitem_id%type)
    return boolean is
    lv_result        boolean := false;
    lv_billingmethod productlistpercustomer.billingmethod%type;
    lv_depositstock  productlistpercustomer.depositstockallowed%type;
    lv_stay          number;
  begin
    lv_result := true;

    select plpc.billingmethod, plpc.depositstockallowed
      into lv_billingmethod, lv_depositstock
      from productlistpercustomer plpc
     where plpc.productlistpercustomer_id = fp_plpcid;

    select 1
      into lv_stay
      from uniqueitem ui
     where ui.uniqueitem_id = fp_uniqueitemid
       and ui.stay_id in (select s.stay_id
                            from stay s
                           where s.staytype = 1
                             and s.staynr = 37);

    if lv_billingmethod <> 3 or lv_depositstock <> 'Y' or lv_stay <> 1 then
      lv_result := false;
    end if;
  return lv_result;
  exception
    when no_data_found then
      begin
        return false;
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Function f_check_deposit_stock for productlistpercustomer_id=' ||
                  fp_plpcid || ' and uniqueitem_id=' || fp_uniqueitemid,
                  priority_error);
        end_log;
    return false;
      end;

  end f_check_deposit_stock;

  procedure check_cust_rent_stop(fp_customerid        in customer.customer_id%type,
                                 fp_customer_rentstop out number) is
  begin
    if f_customer_rent_stop(fp_customerid) then
      fp_customer_rentstop := 1;
    else

      fp_customer_rentstop := 0;
    end if;

  end check_cust_rent_stop;

  procedure check_wi_rent_stop(fp_temporaryrentstopstartdate in date,
                               fp_temporaryrentstopenddate   in date,
                               fp_rentstop                   out number) is

  begin
    if (fp_temporaryrentstopstartdate <= sysdate and
       sysdate <= fp_temporaryrentstopenddate) then
      fp_rentstop := 1;
    else
      fp_rentstop := 0;
    end if;
  end check_wi_rent_stop;

  procedure check_season(fp_season_id       in season.season_id%type,
                         fp_plpc_id         in productlistpercustomer.productlistpercustomer_id%type,
                         fp_season_inactive out number) is

    lv_seasontype_id productlistpercustomer.seasontype_id%type := 0;
    lv_seasonrent    productlistpercustomer.seasonalrent%type;
  begin
    fp_season_inactive := 0;

    select 0
      into fp_season_inactive
      from seasonweek sw
     where sw.season_id = fp_season_id
       and sw.weeknumber = getweeknumber(sysdate);

  exception
    when no_data_found then
      begin
        if (fp_season_id is not null) then
          select plpc.seasontype_id, plpc.seasonalrent
            into lv_seasontype_id, lv_seasonrent
            from productlistpercustomer plpc
           where plpc.productlistpercustomer_id = fp_plpc_id;

          if lv_seasontype_id is not null then
            if lv_seasonrent in (0, 1) then
              fp_season_inactive := 1;
            else
              fp_season_inactive := 0;
            end if;
          end if;
        end if;
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Procedure check_season for season_id=' ||
                  fp_season_id,
                  priority_error);
        end_log;
      end;

  end check_season;

  procedure check_depositstock(fp_plpc_id       in productlistpercustomer.productlistpercustomer_id%type,
                               fp_uniqueitem_id in uniqueitem.uniqueitem_id%type,
                               fp_deposit_stock out number) is
  begin
    if f_check_deposit_stock(fp_plpc_id, fp_uniqueitem_id) then
      fp_deposit_stock := 1;
    else
      fp_deposit_stock := 0;
    end if;
  end check_depositstock;

  procedure check_RVH(lv_calcualtionbasis in residualvaluescheme.calculationbasis%type,
                      lv_actualweeksinuse out number) is
  begin
    if lv_calcualtionbasis = 3 then
      lv_actualweeksinuse := 1;
    else
      lv_actualweeksinuse := 0;
    end if;
  end check_RVH;

  procedure calc_residual_value(fp_replacement_price in customerreplacementprice.price%type,
                                fp_rvprecentage      in number,
                                fp_rvamount          out NUMBER) is
  begin
    if fp_replacement_price is not null then
      fp_rvamount := fp_rvprecentage * fp_replacement_price / 100;
    else
      fp_rvamount := null;
    end if;
  end calc_residual_value;

  procedure get_resvalueschemedef(fp_residual_valueid  in resvalschemedefinition.residualvaluescheme_id%type,
                                  fp_age               in number,
                                  fp_resvalschemedefid out resvalschemedefinition.resvalschemedefinition_id%type,
                                  fp_definitiontype    out resvalschemedefinition.definitiontype%type,
                                  fp_startrange        out resvalschemedefinition.rangestart%type,
                                  fp_endrange          out resvalschemedefinition.rangeend%type,
                                  fp_startpercentage   out resvalschemedefinition.startpercentage%type,
                                  fp_endpercentage     out resvalschemedefinition.endpercentage%type,
                                  fp_fixpercentage     out resvalschemedefinition.fixedpercentage%type) is
  begin

    select rvsd.resvalschemedefinition_id,
           rvsd.definitiontype,
           rvsd.rangestart,
           rvsd.rangeend,
           rvsd.startpercentage,
           rvsd.endpercentage,
           rvsd.fixedpercentage
      into fp_resvalschemedefid,
           fp_definitiontype,
           fp_startrange,
           fp_endrange,
           fp_startpercentage,
           fp_endpercentage,
           fp_fixpercentage
      from resvalschemedefinition rvsd
     where rvsd.residualvaluescheme_id = fp_residual_valueid;

     if (fp_age < fp_startrange or fp_age > fp_endrange) then
        write_log(gv_message || ' Uniqueitem age outside residualvaluescheme range. residualvaluescheme_id = ' || fp_residual_valueid,
                  priority_debug);
     end if;
  exception
    when no_data_found then
      begin
        fp_definitiontype := 1;
        write_log('Error CREATESQRESIDUALVALUEHISTORY: ' ||
                  'No resvalschemedefinition record found for residualvaluescheme_id=' ||
                  fp_residual_valueid,
                  priority_error);
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Procedure get_resvalueschemedef for residualvaluescheme_id=' ||
                  fp_residual_valueid,
                  priority_error);
        end_log;
      end;
  end get_resvalueschemedef;

  procedure update_uniqueitem(fp_uniqueitem_id     in uniqueitem.uniqueitem_id%type,
                              fp_rvprecentage      in uniqueitem.residualvalue%type,
                              fp_rvamount          in uniqueitem.residualvalueamount%type,
                              fp_replacement_price in uniqueitem.replacementprice%type,
                              fp_for_correction    in boolean) is
  lv_rvprecentage      uniqueitem.residualvalue%type;
  lv_rvamount          uniqueitem.residualvalueamount%type;
  lv_replacement_price uniqueitem.replacementprice%type;
  lv_message           abslogprocessjobline.message%type;

  begin
    if fp_for_correction then
      select ui.residualvalue, ui.residualvalueamount, ui.replacementprice
        into lv_rvprecentage, lv_rvamount, lv_replacement_price
        from uniqueitem ui
     where ui.uniqueitem_id = fp_uniqueitem_id;

       if (lv_rvprecentage = fp_rvprecentage
           and lv_rvamount is not null and lv_rvamount = fp_rvamount
           and lv_replacement_price is not null and lv_replacement_price = fp_replacement_price) then
         return;
       else
         lv_message := 'Update uniqueitem for correction. UniqueItem_id = ' || fp_uniqueitem_id ||
                  '; Residualvalue: previous = ' || lv_rvprecentage || ' current = ' || fp_rvprecentage ||
                  '; Residualvalueamount: previous = ' || lv_rvamount || ' current = ' || fp_rvamount ||
                  '; Replacementprice: previous = ' || lv_replacement_price || ' current = ' || fp_replacement_price;
         write_log(lv_message, priority_debug);
       end if;
    end if;

    update uniqueitem ui
       set ui.residualvalue       = fp_rvprecentage,
           ui.residualvalueamount = fp_rvamount,
           ui.replacementprice    = fp_replacement_price,
           ui.systemuser_id       = gv_systemUserID,
           ui.timestamp           = sysdate
     where ui.uniqueitem_id = fp_uniqueitem_id;

    IF SQL%ROWCOUNT = 0 THEN
      raise gv_updateexception;
    end if;

  exception
    when gv_updateexception then
      begin
        write_log('Error CREATESQRESIDUALVALUEHISTORY: ' ||
                  'Cannot update uniqueitem. UniqueItem_id=' ||
                  fp_uniqueitem_id || ' Residualvalue = ' ||
                  fp_rvprecentage || ' Residualvalueamount = ' ||
                  fp_rvamount || ' Replacementprice = ' ||
                  fp_replacement_price,
                  priority_error);
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Procedure update_uniqueitem. ' ||
                  'UniqueItem_id=' || fp_uniqueitem_id,
                  priority_error);
        end_log;
      end;
  end update_uniqueitem;

  function Replacement_Price(customerid        in customer.customer_id%type,
                             productid         in product.product_id%type,
                             sizedefinitionid  in sizedefinition.sizedefinition_id%type,
                             pricedate         in pricelistpercustomer.dateactive%type default null)
  return number is
  /* Returns the price, if not found, returns 0.  For use in calculations.  */

    price                   customerreplacementprice.price%type;
    price_found_yn          varchar2(1);
    price_start_date        customerreplacementprice.startdate%type;
    result_code             number;
    result_desc             varchar2(80);
    price_list_type         varchar2(1);
    price_list_code         generalpricelist.code%type;
    price_list_desc         generalpricelist.description%type;

    begin
      pack_price_new.Get_Replacement_Price_Details(customerid,
                                    productid,
                                    sizedefinitionid,
                                    null,
                                    pricedate,
                                    price,
                                    price_found_yn,
                                    price_start_date,
                                    result_code,
                                    result_desc,
                                    price_list_type,
                                    price_list_code,
                                    price_list_desc);
      if (nvl(price,0) = 0) then
        gv_message := gv_message || ' Replacement price not found. ' || result_desc || '. Result code = ' || result_code;
        write_log(gv_message);
      end if;
      return(nvl(price,0));
    end Replacement_Price;

  procedure CREATESQRESIDUALVALUEHISTORY(fp_processPlantID      plant.plant_id%type,
                                         fp_abslogprocessjob_id abslogprocessjob.abslogprocessjob_id%type,
                                         fp_systemUserID        systemuser.systemuser_id%type) is

    -- cursor for process items in circulation woth RVH
    cursor get_ui_rvh(fp_wearerinventory_id in NUMBER) is
      select a.uniqueitem_id,
             a.product_id,
             a.sizedefinition_id,
             a.finishingmethod_id,
             a.washestotal,
             a.residualvalue,
             nvl(a.residualvalueamount, 0) residualvalueamount,
             b.daysincircprevissue,
             b.daysinstockprevious,
             b.lastissuedate,
             b.firstissuedate,
             b.histreplacementpricefirstissue,
             b.histreplacementpricelastissue,
             c.weareremployment_id,
             a.distributionpoint_id,
             b.currency_id,
             a.replacementprice
        from uniqueitem a, uniqueitemfixedinfo b, uniqueitemnonpool c
       where a.uniqueitem_id = b.uniqueitem_id
         and a.uniqueitem_id = c.uniqueitem_id
         and c.wearerinventory_id = fp_wearerinventory_id
         and a.status_id in (select status_id
                               from status
                              where statustype = 'UI'
                                and code in ('20', '30'))
         and a.customerowned = 'N'
         and a.poolitem = 2
         and nvl(a.leaseweeks, 0) = 0
         and a.businessunit_id in
             (select bu.businessunit_id
                from businessunit bu
               where bu.plant_id = gv_plantid)
         and exists
       (select max(rvh.calculationdate)
                from residualvaluehistory rvh
               where rvh.uniqueitem_link_id = a.uniqueitem_id having
               max(trunc(rvh.calculationdate)) <= trunc(sysdate) - 7);

    -- cursor for process items in circulation
    cursor get_wid is
      select d.customer_id,
             d.department_id,
             wi.wearerinventory_id,
             p.product_id,
             sd.sizedefinition_id,
             fm.finishingmethod_id
        from customer           c,
             customeractivities ca,
             department         d,
             wearer             w,
             weareremployment   we,
             wearerinventory    wi,
             distributionpoint  di,
             product            p,
             productgroup       pg,
             sizedefinition     sd,
             finishingmethod    fm
       where c.customer_id = d.customer_id
         and d.department_id = di.department_id
         and d.customer_id = ca.customer_id
         and ca.activity_id = pg.activity_id
         and pg.productgroup_id = p.productgroup_id
         and p.product_id = wi.product_id
         and sd.sizedefinition_id = wi.sizedefinition_id
         and fm.finishingmethod_id = wi.finishingmethod_id
         and wi.weareremployment_id = we.weareremployment_id
         and we.wearer_id = w.wearer_id
         and we.distributionpoint_id = di.distributionpoint_id
         and (wi.circinventory > 0 or wi.freeofchargeqty > 0)
         and exists (select 1 from uniqueitem ui, uniqueitemnonpool uinp, businessunit bu
           where uinp.wearerinventory_id = wi.wearerinventory_id
             and ui.uniqueitem_id = uinp.uniqueitem_id
             and ui.status_id in (select status_id
                                   from status
                                  where statustype = 'UI'
                                    and code in ('20', '30'))
             and ui.customerowned = 'N'
             and ui.poolitem = 2
             and nvl(ui.leaseweeks, 0) = 0
             and ui.businessunit_id = bu.businessunit_id and bu.plant_id = gv_plantid)
        group by d.customer_id,
                d.department_id,
                wi.wearerinventory_id,
                p.product_id,
                sd.sizedefinition_id,
                fm.finishingmethod_id
       order by d.customer_id,
                d.department_id,
                wi.wearerinventory_id,
                p.product_id,
                sd.sizedefinition_id,
                fm.finishingmethod_id;

    cursor get_uid(fp_wearerinventory_id in NUMBER) is
      select a.uniqueitem_id,
             a.product_id,
             a.sizedefinition_id,
             a.finishingmethod_id,
             a.washestotal,
             a.residualvalue,
             nvl(a.residualvalueamount, 0) residualvalueamount,
             b.daysincircprevissue,
             b.daysinstockprevious,
             b.lastissuedate,
             b.firstissuedate,
             b.histreplacementpricefirstissue,
             b.histreplacementpricelastissue,
             c.weareremployment_id,
             a.distributionpoint_id,
             b.currency_id,
             a.replacementprice
        from uniqueitem a, uniqueitemfixedinfo b, uniqueitemnonpool c
       where a.uniqueitem_id = b.uniqueitem_id
         and a.uniqueitem_id = c.uniqueitem_id
         and c.wearerinventory_id = fp_wearerinventory_id
         and a.status_id in (select status_id
                               from status
                              where statustype = 'UI'
                                and code in ('20', '30'))
         and a.customerowned = 'N'
         and a.poolitem = 2
         and nvl(a.leaseweeks, 0) = 0
         and a.businessunit_id in
             (select bu.businessunit_id
                from businessunit bu
               where bu.plant_id = gv_plantid);

    -- cursor for process items in stock with RVH
    cursor get_uid_stk_RVH is
      select a.uniqueitem_id,
             a.product_id,
             a.sizedefinition_id,
             a.finishingmethod_id,
             a.washestotal,
             a.residualvalue,
             nvl(a.residualvalueamount, 0) residualvalueamount,
             b.daysincircprevissue,
             b.daysinstockprevious,
             b.lastissuedate,
             b.firstissuedate,
             b.lastonstockdate,
             b.histreplacementpricefirstissue,
             b.histreplacementpricelastissue,
             a.lastweareremployment_link_id,
             a.distributionpoint_id,
             b.currency_id
        from uniqueitem a, uniqueitemfixedinfo b
       where a.uniqueitem_id = b.uniqueitem_id
         and a.status_id in (select status_id
                               from status
                              where statustype = 'UI'
                                and code in ('10', '25'))
         and a.customerowned = 'N'
         and a.poolitem = 0
         and a.stay_id = (select s.stay_id
                            from stay s
                           where s.staytype = 1
                             and s.staynr = 10)
         and a.businessunit_id in
             (select bu.businessunit_id
                from businessunit bu
               where bu.plant_id = gv_plantid)
         and b.firstissuedate is not null
         and exists
       (select max(rvh.calculationdate)
                from residualvaluehistory rvh
               where rvh.uniqueitem_link_id = a.uniqueitem_id having
               max(trunc(rvh.calculationdate)) <= trunc(sysdate) - 7);

    -- cursor for process items in stock
    cursor get_uid_stk is
      select a.uniqueitem_id,
             a.product_id,
             a.sizedefinition_id,
             a.finishingmethod_id,
             a.washestotal,
             a.residualvalue,
             nvl(a.residualvalueamount, 0) residualvalueamount,
             b.daysincircprevissue,
             b.daysinstockprevious,
             b.lastissuedate,
             b.firstissuedate,
             b.lastonstockdate,
             b.histreplacementpricefirstissue,
             b.histreplacementpricelastissue,
             a.lastweareremployment_link_id,
             a.distributionpoint_id,
             b.currency_id
        from uniqueitem a, uniqueitemfixedinfo b
       where a.uniqueitem_id = b.uniqueitem_id
         and a.status_id in (select status_id
                               from status
                              where statustype = 'UI'
                                and code in ('10', '25'))
          and a.customerowned = 'N'
         and a.poolitem = 0
         and a.stay_id = (select s.stay_id
                            from stay s
                           where s.staytype = 1
                             and s.staynr = 10)
         and a.businessunit_id in
             (select bu.businessunit_id
                from businessunit bu
               where bu.plant_id = gv_plantid)
         and b.firstissuedate is not null;

    lv_plpc_id_initial            productlistpercustomer.productlistpercustomer_id%type;
    lv_plpc_id                    productlistpercustomer.productlistpercustomer_id%type;
    lv_residual_valueid           residualvaluescheme.residualvaluescheme_id%type;
    lv_price_type                 residualvaluescheme.replacementpricetype%type;
    lv_replacement_price          customerreplacementprice.price%type;
    lv_wearer_inactive            number;
    lv_customer_rentstop          number;
    lv_rentstop                   number;
    lv_season_inactive            number;
    lv_passive_stock              number := 0;
    lv_deposit_stock              number;
    lv_rvprecentage               number;
    lv_actualweeksinuse           number;
    lv_weeksincirc                number;
    lv_calculatedweeks            number;
    lv_weeklydep                  NUMBER;
    lv_weeksonstock               number;
    lv_depreciation               number;
    lv_calculationdate            date;
    lv_rvamount                   NUMBER(28, 6);
    lv_residualvaluecode          residualvaluescheme.code%type;
    lv_calcualtionbasis           residualvaluescheme.calculationbasis%type;
    lv_resvalschemedefid          resvalschemedefinition.resvalschemedefinition_id%type;
    lv_definitiontype             resvalschemedefinition.definitiontype%type;
    lv_startrange                 resvalschemedefinition.rangestart%type;
    lv_endrange                   resvalschemedefinition.rangeend%type;
    lv_startpercentage            resvalschemedefinition.startpercentage%type;
    lv_endpercentage              resvalschemedefinition.endpercentage%type;
    lv_fixpercentage              resvalschemedefinition.fixedpercentage%type;
    lv_calculationweeks           residualvaluescheme.calculationweeks%type;
    lv_residualvaluehistory_id    residualvaluehistory.residualvaluehistory_id%type := null;
    lv_record                     residualvaluehistory%rowtype;
    lv_customer_id                customer.customer_id%type;
    lv_temporaryrentstopstartdate wearerinventory.temporaryrentstopstartdate%type;
    lv_temporaryrentstopenddate   wearerinventory.temporaryrentstopenddate%type;
    lv_season_id                  wearerinventory.season_id%type;
    lv_dateinactive               wearerinventory.dateactive%type;
    --
    lv_prev_customer_id        customer.customer_id%type := 0;
    lv_prev_product_id         product.product_id%type := 0;
    lv_prev_sizedefinition_id  sizedefinition.sizedefinition_id%type := 0;
    lv_prev_finishingmethod_id finishingmethod.finishingmethod_id%type := 0;
    lv_prev_typeprice          number := 0;
    lv_decimals                number;
    lv_ui_age                  number := 0;

  begin
    -- Initialization
    gv_abslogprocessjobid := fp_abslogprocessjob_id;
    gv_systemuserid       := fp_systemUserID;
    gv_plantid            := fp_processPlantID;
    gv_processname        := 'PACK_RESIDUALVALUEHISTORY.CREATESQRESIDUALVALUEHISTORY';

    --check parameter not null
    if fp_processPlantID is null then
      gv_message := 'Parameter fp_processPlantID cannot be left empty!';
      write_log(gv_message, priority_error);
      raise gv_userexception;
    end if;

    if fp_abslogprocessjob_id is null then
      gv_message := 'Parameter fp_abslogprocessjob_id cannot be left empty!';
      write_log(gv_message, priority_error);
      Raise gv_userexception;
    end if;

    if fp_systemUserID is null then
      gv_message := 'Parameter fp_systemUserID cannot be left empty!';
      write_log(gv_message, priority_error);
      Raise gv_userexception;
    end if;

    write_log('START PACK_RESIDUALVALUEHISTORY.CREATESQRESIDUALVALUEHISTORY');
    write_log('Processing items in ciculation(or assigned) with RVH');

    select c.decimals into lv_decimals
    from currency c, plant, country cc
    where plant.country_id = cc.country_id
    and cc.defaultcurrency_id = c.currency_id
    and plant.plant_id = fp_processPlantID;
    --processing items in ciculation(or assigned) with RVH
    for wid_rec in get_wid loop
      gv_message := '';
      --get wearer inventory details
      get_wi(wid_rec.wearerinventory_id,
             lv_temporaryrentstopstartdate,
             lv_temporaryrentstopenddate,
             lv_season_id,
             lv_dateinactive);
      --determine the active plpc
      get_plpc(wid_rec.product_id,
               wid_rec.sizedefinition_id,
               wid_rec.finishingmethod_id,
               wid_rec.customer_id,
               lv_plpc_id_initial);
      if lv_plpc_id_initial is not null then
        for uid_rec_rvh in get_ui_rvh(wid_rec.wearerinventory_id) loop
          gv_message := ' UniqueItem ID = ' || uid_rec_rvh.uniqueitem_id;
          --check if the unique items has a finishing method
          if nvl(uid_rec_rvh.finishingmethod_id, wid_rec.finishingmethod_id)  <> wid_rec.finishingmethod_id then
            get_plpc_no_fm(wid_rec.customer_id,
                           wid_rec.product_id,
                           wid_rec.sizedefinition_id,
                           lv_plpc_id);
            gv_message := gv_message || ' Plpc ID (no FM) = ' || lv_plpc_id;
          else
            lv_plpc_id := lv_plpc_id_initial;
            gv_message := gv_message || ' Plpc ID = ' || lv_plpc_id;
          end if;
          --get the residual value scheme  for PLPC found
          get_residualvalue(lv_plpc_id,
                            uid_rec_rvh.daysincircprevissue,
                            uid_rec_rvh.lastissuedate,
                            uid_rec_rvh.washestotal,
                            lv_residual_valueid,
                            lv_residualvaluecode,
                            lv_calcualtionbasis,
                            lv_calculationweeks,
                            lv_price_type,
                            lv_rvprecentage);

          --get replacement price
          if lv_price_type = 1 then
            if (lv_prev_customer_id <> wid_rec.customer_id or
               lv_prev_product_id <> wid_rec.product_id or
               lv_prev_sizedefinition_id <> wid_rec.sizedefinition_id or
               lv_prev_finishingmethod_id <> wid_rec.finishingmethod_id or
               lv_prev_typeprice <> lv_price_type) then

               lv_replacement_price := Replacement_Price(wid_rec.customer_id,
                                                                   wid_rec.product_id,
                                                                   wid_rec.sizedefinition_id);
            end if;
          elsif lv_price_type = 2 then
            lv_replacement_price := uid_rec_rvh.histreplacementpricefirstissue;
          elsif lv_price_type = 3 then
            lv_replacement_price := uid_rec_rvh.histreplacementpricelastissue;
          end if;

          lv_prev_customer_id        := wid_rec.customer_id;
          lv_prev_product_id         := wid_rec.product_id;
          lv_prev_sizedefinition_id  := wid_rec.sizedefinition_id;
          lv_prev_finishingmethod_id := wid_rec.sizedefinition_id;
          lv_prev_typeprice          := lv_price_type;

          --check if residual value might have to be frozen
          check_RVH(lv_calcualtionbasis, lv_actualweeksinuse);

          --check of wearer is(temporarly) inactive
          check_wearer(lv_dateinactive, lv_wearer_inactive);

          --check if customer rent stop is active
          check_cust_rent_stop(wid_rec.customer_id, lv_customer_rentstop);

          --check if wearer inventory rent stop is active
          check_wi_rent_stop(lv_temporaryrentstopstartdate,
                             lv_temporaryrentstopenddate,
                             lv_rentstop);

          --check if season is defined that is not active for current week
          check_season(lv_season_id, lv_plpc_id, lv_season_inactive);

          --check if items is in deposit stock
          check_depositstock(lv_plpc_id,
                             uid_rec_rvh.uniqueitem_id,
                             lv_deposit_stock);
          --calculate depreciation
          select decode(lv_calculationweeks,
                        0,
                        0,
                        lv_replacement_price / lv_calculationweeks)
            into lv_weeklydep
            from dual;

          --get residual value history
          get_rvh_weekly(uid_rec_rvh.uniqueitem_id,
                         lv_residualvaluehistory_id);

          if (lv_calcualtionbasis = 3 and gv_alwaysrecalculaterv = 0) then
            --get residual value history info
            get_rvh_info(lv_residualvaluehistory_id, lv_record);

            if (lv_wearer_inactive = 0 and lv_customer_rentstop = 0 and
               lv_rentstop = 0 and lv_season_inactive = 0 and
               lv_deposit_stock = 0) then
                  lv_weeksincirc     := greatest(0, ceil((trunc(sysdate) -
                                             uid_rec_rvh.lastissuedate)/ 7));
                  lv_calculatedweeks := ceil((trunc(sysdate) -
                                             lv_record.calculationdate) / 7);
                  lv_weeksonstock    := lv_record.weeksonstock;
                  lv_depreciation    := round((lv_weeklydep *
                                              lv_calculatedweeks),lv_decimals);
                  lv_rvamount        := uid_rec_rvh.residualvalueamount - lv_depreciation;

                  if (uid_rec_rvh.residualvalueamount = 0 and lv_record.replacementprice = uid_rec_rvh.replacementprice) then
                         lv_rvamount        := lv_record.residualvalueamount - lv_depreciation;
                  end if;

                  if lv_rvamount < 0 then lv_rvamount := 0; end if;

                  select decode(lv_replacement_price,
                                0,
                                0,
                                (lv_rvamount / lv_replacement_price)*100)
                    into lv_rvprecentage
                    from dual;
            else
              lv_replacement_price := lv_record.replacementprice;
              lv_rvprecentage      := lv_record.residualvaluepercentage;
              lv_rvamount          := lv_record.residualvalueamount;
              lv_weeksincirc       := lv_record.weeksincirc;
              lv_calculatedweeks   := lv_record.calculationweeks;
              lv_weeksonstock      := lv_record.weeksonstock;

            end if;
          else
            lv_weeksincirc     := greatest(0, ceil(((trunc(sysdate) - uid_rec_rvh.lastissuedate) + uid_rec_rvh.daysincircprevissue) / 7));
            lv_calculatedweeks := lv_weeksincirc;
            lv_weeksonstock    := ceil((uid_rec_rvh.daysinstockprevious / 7));
            lv_rvprecentage    := get_depreciation_percent(lv_residual_valueid, lv_calculatedweeks, 3);
            lv_rvamount        := (lv_replacement_price * (lv_rvprecentage / 100));

          end if;

          --select resvalueschemedefinitiondetails
          lv_ui_age := get_ui_age(lv_calcualtionbasis,
                                  uid_rec_rvh.daysincircprevissue,
                                  uid_rec_rvh.lastissuedate,
                                  uid_rec_rvh.washestotal);
          get_resvalueschemedef(lv_residual_valueid,
                                lv_ui_age,
                                lv_resvalschemedefid,
                                lv_definitiontype,
                                lv_startrange,
                                lv_endrange,
                                lv_startpercentage,
                                lv_endpercentage,
                                lv_fixpercentage);
          begin
            insert into residualvaluehistory
              (residualvaluehistory_id,
               uniqueitem_link_id,
               customer_link_id,
               department_link_id,
               distributionpoint_link_id,
               weareremployment_link_id,
               product_link_id,
               sizedefinition_link_id,
               finishingmethod_id,
               calculationdate,
               transactiontype,
               year,
               week,
               residualvaluescheme_id,
               residualvalueschemecode,
               calculationbasis,
               basecalculationweeks,
               replacementpricetype,
               resvalschemedefinition_id,
               definitiontype,
               startrange,
               endrange,
               startpercentage,
               endpercentage,
               fixedpercentage,
               replacementprice,
               residualvaluepercentage,
               residualvalueamount,
               currency_id,
               calculationweeks,
               weeksincirc,
               weeksonstock,
               washes,
               customerrentstop,
               rentstop,
               wearerinactive,
               seasoninactive,
               onpassivestock,
               indepositstock,
               systemuser_id,
               timestamp)
            values
              (seq_residualvaluehistory.nextval,
               uid_rec_rvh.uniqueitem_id,
               wid_rec.customer_id,
               wid_rec.department_id,
               uid_rec_rvh.distributionpoint_id,
               uid_rec_rvh.weareremployment_id,
               uid_rec_rvh.product_id,
               uid_rec_rvh.sizedefinition_id,
               uid_rec_rvh.finishingmethod_id,
               sysdate,
               0,
               getyearofweek(sysdate),
               getweeknumber(sysdate),
               lv_residual_valueid,
               lv_residualvaluecode,
               lv_calcualtionbasis,
               lv_calculationweeks,
               lv_price_type,
               lv_resvalschemedefid,
               coalesce(lv_definitiontype, 1),
               lv_startrange,
               lv_endrange,
               lv_startpercentage,
               lv_endpercentage,
               decode(lv_definitiontype, 2, null, lv_fixpercentage),
               lv_replacement_price,
               lv_rvprecentage,
               lv_rvamount,
               uid_rec_rvh.currency_id,
               lv_calculatedweeks,
               lv_weeksincirc,
               lv_weeksonstock,
               uid_rec_rvh.washestotal,
               lv_customer_rentstop,
               lv_rentstop,
               lv_wearer_inactive,
               lv_season_inactive,
               lv_passive_stock,
               lv_deposit_stock,
               fp_systemUserID,
               Current_Timestamp);

          --if residual value should not be frozen
          if (lv_actualweeksinuse = 0 or
             (lv_actualweeksinuse = 1 and lv_wearer_inactive = 0 and
             lv_customer_rentstop = 0 and lv_rentstop = 0 and
             lv_season_inactive = 0 and lv_deposit_stock = 0)) then

            --update uniqueitem table
            update_uniqueitem(uid_rec_rvh.uniqueitem_id,
                              lv_rvprecentage,
                              lv_rvamount,
                              lv_replacement_price,
                              false);
          else
            -- check & update uniqueitem table only if RV data is inconsistent
            update_uniqueitem(uid_rec_rvh.uniqueitem_id,
                            lv_rvprecentage,
                            lv_rvamount,
                            lv_replacement_price,
                            true);
          end if;
          exception
            when others then
              begin
                write_log(sqlerrm, priority_debug);
                write_log('Error CREATESQRESIDUALVALUEHISTORY:  Insert into residualvaluehistory. ' ||
                          'UniqueItem_id=' || uid_rec_rvh.uniqueitem_id,
                          priority_error);
              end;
          end;

        end loop;
        commit;
      end if;
    end loop;

    write_log('Processing items in stock with RVH');
    --processing items in stock with RVH
    for uid_rec_stk_rvh in get_uid_stk_RVH loop
      gv_message := ' UniqueItem ID = ' || uid_rec_stk_rvh.uniqueitem_id;
      --check for existing residual value history record
      get_rvh_weekly(uid_rec_stk_rvh.uniqueitem_id,
                     lv_residualvaluehistory_id);

      select *
        into lv_record
        from residualvaluehistory rvh
       where rvh.residualvaluehistory_id = lv_residualvaluehistory_id;

      select seq_residualvaluehistory.nextval
        into lv_record.residualvaluehistory_id
        from dual;
      lv_record.calculationdate  := sysdate;
      lv_record.transactiontype  := 0;
      lv_record.year             := getyearofweek(sysdate);
      lv_record.week             := getweeknumber(sysdate);
      lv_record.weeksonstock     := coalesce(ceil((uid_rec_stk_rvh.daysinstockprevious +
                                                  (trunc(sysdate) -
                                                  uid_rec_stk_rvh.lastonstockdate)) / 7),
                                             0);
      lv_record.customerrentstop := 0;
      lv_record.rentstop         := 0;
      lv_record.wearerinactive   := 0;
      lv_record.seasoninactive   := 0;
      lv_record.onpassivestock   := 1;
      lv_record.indepositstock   := 0;
      lv_record.systemuser_id    := fp_systemUserID;
      lv_record.timestamp        := Current_Timestamp;

      insert into residualvaluehistory values lv_record;

      -- check & update uniqueitem table only if RV data is inconsistent
      update_uniqueitem(uid_rec_stk_rvh.uniqueitem_id,
                      lv_record.residualvaluepercentage,
                      lv_record.residualvalueamount,
                      lv_record.replacementprice,
                      true);
     commit;
    end loop;

    write_log('Processing items in ciculation(or assigned)');
    --processing items in ciculation(or assigned)
    for wid_rec in get_wid loop
      --get wearer inventory details
      get_wi(wid_rec.wearerinventory_id,
             lv_temporaryrentstopstartdate,
             lv_temporaryrentstopenddate,
             lv_season_id,
             lv_dateinactive);
      --determine the active plpc
      get_plpc(wid_rec.product_id,
               wid_rec.sizedefinition_id,
               wid_rec.finishingmethod_id,
               wid_rec.customer_id,
               lv_plpc_id_initial);
      if lv_plpc_id_initial is not null then
        --process all unique non-pool items for the wearer inventory
        for uid_rec in get_uid(wid_rec.wearerinventory_id) loop
          gv_message := ' UniqueItem ID = ' || uid_rec.uniqueitem_id;
          --get residual value history
          get_residualvaluehistory(uid_rec.uniqueitem_id,
                                   lv_residualvaluehistory_id,
                                   lv_calculationdate);

          if (lv_residualvaluehistory_id is null and
             lv_calculationdate is null) or (lv_residualvaluehistory_id is not null and
             lv_calculationdate is not null) then
            --check if the unique items has a finishing method
            if nvl(uid_rec.finishingmethod_id, wid_rec.finishingmethod_id) <> wid_rec.finishingmethod_id then
              get_plpc_no_fm(wid_rec.customer_id,
                             wid_rec.product_id,
                             wid_rec.sizedefinition_id,
                             lv_plpc_id);
              gv_message := gv_message || ' Plpc ID (no FM) = ' || lv_plpc_id;
            else
              lv_plpc_id := lv_plpc_id_initial;
              gv_message := gv_message || ' Plpc ID = ' || lv_plpc_id;
            end if;
            --get the residual value scheme  for PLPC found
            get_residualvalue(lv_plpc_id,
                              uid_rec.daysincircprevissue,
                              uid_rec.lastissuedate,
                              uid_rec.washestotal,
                              lv_residual_valueid,
                              lv_residualvaluecode,
                              lv_calcualtionbasis,
                              lv_calculationweeks,
                              lv_price_type,
                              lv_rvprecentage);

            --get replacement price
            if lv_price_type = 1 then
              if (lv_prev_customer_id <> wid_rec.customer_id or
                 lv_prev_product_id <> wid_rec.product_id or
                 lv_prev_sizedefinition_id <> wid_rec.sizedefinition_id or
                 lv_prev_finishingmethod_id <> wid_rec.finishingmethod_id or
                 lv_prev_typeprice <> lv_price_type) then

                 lv_replacement_price := Replacement_Price(wid_rec.customer_id,
                                                                     wid_rec.product_id,
                                                                     wid_rec.sizedefinition_id);
              end if;
            elsif lv_price_type = 2 then
              lv_replacement_price := uid_rec.histreplacementpricefirstissue;
            elsif lv_price_type = 3 then
              lv_replacement_price := uid_rec.histreplacementpricelastissue;
            end if;

            lv_prev_customer_id        := wid_rec.customer_id;
            lv_prev_product_id         := wid_rec.product_id;
            lv_prev_sizedefinition_id  := wid_rec.sizedefinition_id;
            lv_prev_finishingmethod_id := wid_rec.sizedefinition_id;
            lv_prev_typeprice          := lv_price_type;

            --check if residual value might have to be frozen
            check_RVH(lv_calcualtionbasis, lv_actualweeksinuse);

            --check of wearer is(temporarly) inactive
            check_wearer(lv_dateinactive, lv_wearer_inactive);

            --check if customer rent stop is active
            check_cust_rent_stop(wid_rec.customer_id, lv_customer_rentstop);

            --check if wearer inventory rent stop is active
            check_wi_rent_stop(lv_temporaryrentstopstartdate,
                               lv_temporaryrentstopenddate,
                               lv_rentstop);

            --check if season is defined that is not active for current week
            check_season(lv_season_id, lv_plpc_id, lv_season_inactive);

            --check if items is in deposit stock
            check_depositstock(lv_plpc_id,
                               uid_rec.uniqueitem_id,
                               lv_deposit_stock);

            --calculate depreciation
            select decode(lv_calculationweeks,
                          0,
                          0,
                          lv_replacement_price / lv_calculationweeks)
              into lv_weeklydep
              from dual;

            --calculate residual value amount when a last RVH was found
            if lv_residualvaluehistory_id is not null then
              if (lv_calcualtionbasis = 3 and gv_alwaysrecalculaterv = 0) then
                --get residual value history info
                get_rvh_info(lv_residualvaluehistory_id, lv_record);

                if (lv_wearer_inactive = 0 and lv_customer_rentstop = 0 and
                   lv_rentstop = 0 and lv_season_inactive = 0 and
                   lv_deposit_stock = 0) then
                      lv_weeksincirc     := greatest(0, ceil((trunc(sysdate) -
                                                 uid_rec.lastissuedate)));
                      lv_calculatedweeks := ceil((trunc(sysdate) -
                                                 lv_record.calculationdate) / 7);
                      lv_weeksonstock    := lv_record.weeksonstock;
                      lv_depreciation    := round((lv_weeklydep *
                                                  lv_calculatedweeks), lv_decimals);
                      lv_rvamount        := uid_rec.residualvalueamount -   lv_depreciation;
                      if (uid_rec.residualvalueamount = 0 and lv_record.replacementprice = uid_rec.replacementprice) then
                         lv_rvamount        := lv_record.residualvalueamount - lv_depreciation;
                      end if;

                      if lv_rvamount < 0 then lv_rvamount := 0; end if;

                      select decode(lv_replacement_price,
                                    0,
                                    0,
                                    (lv_rvamount / lv_replacement_price)*100)
                        into lv_rvprecentage
                        from dual;
                else
                  lv_replacement_price := lv_record.replacementprice;
                  lv_rvprecentage      := lv_record.residualvaluepercentage;
                  lv_rvamount          := lv_record.residualvalueamount;
                  lv_weeksincirc       := lv_record.weeksincirc;
                  lv_calculatedweeks   := lv_record.calculationweeks;
                  lv_weeksonstock      := lv_record.weeksonstock;

                end if;
              else
                lv_weeksincirc     := greatest(0, ceil(((trunc(sysdate) - uid_rec.lastissuedate) + uid_rec.daysincircprevissue) / 7));
                lv_calculatedweeks := lv_weeksincirc;
                lv_weeksonstock    := ceil((uid_rec.daysinstockprevious / 7));
                lv_rvprecentage    := get_depreciation_percent(lv_residual_valueid, lv_calculatedweeks, 3);
                lv_rvamount        := (lv_replacement_price * (lv_rvprecentage / 100));
              end if;
            end if;

            --calculate residual value amount when a last RVH was not found
            if lv_residualvaluehistory_id is null then
              if (uid_rec.lastissuedate is null) then
                 write_log('Error CREATESQRESIDUALVALUEHISTORY:  Insert into residualvaluehistory. Weeks in circulation can not be determined. ' ||
                            'UniqueItem_id = ' || uid_rec.uniqueitem_id, priority_error);
                 continue;
              end if;
              if (lv_calcualtionbasis = 3 and gv_alwaysrecalculaterv = 0) then
                lv_weeksincirc     := greatest(0, ceil((trunc(sysdate) - uid_rec.lastissuedate) / 7));
                lv_calculatedweeks := lv_weeksincirc;
                lv_weeksonstock    := ceil((uid_rec.daysinstockprevious / 7));
                lv_depreciation    := round((lv_weeklydep *
                                            lv_calculatedweeks),lv_decimals);
                lv_rvamount        := greatest(0, uid_rec.residualvalueamount - lv_depreciation);

                select decode(lv_replacement_price,
                              0,
                              0,
                              (lv_rvamount / lv_replacement_price)*100)
                  into lv_rvprecentage
                  from dual;
              else
                lv_weeksincirc     := greatest(0, ceil(((trunc(sysdate) - uid_rec.lastissuedate) + uid_rec.daysincircprevissue) / 7));
                lv_calculatedweeks := lv_weeksincirc;
                lv_weeksonstock    := ceil(uid_rec.daysinstockprevious / 7);
                lv_rvprecentage    := get_depreciation_percent(lv_residual_valueid, lv_calculatedweeks, 3);
                lv_rvamount        := (lv_replacement_price * (lv_rvprecentage / 100));
              end if;
            end if;
            ----------------------------------------------------------------------------------------


            --select resvalueschemedefinitiondetails
            lv_ui_age := get_ui_age(lv_calcualtionbasis,
                                    uid_rec.daysincircprevissue,
                                    uid_rec.lastissuedate,
                                    uid_rec.washestotal);
            get_resvalueschemedef(lv_residual_valueid,
                                  lv_ui_age,
                                  lv_resvalschemedefid,
                                  lv_definitiontype,
                                  lv_startrange,
                                  lv_endrange,
                                  lv_startpercentage,
                                  lv_endpercentage,
                                  lv_fixpercentage);

            --if residual value should be frozen then only a new RVH iscreated
            --insert into residualvaluehistorytable
            begin
              insert into residualvaluehistory
                (residualvaluehistory_id,
                 uniqueitem_link_id,
                 customer_link_id,
                 department_link_id,
                 distributionpoint_link_id,
                 weareremployment_link_id,
                 product_link_id,
                 sizedefinition_link_id,
                 finishingmethod_id,
                 calculationdate,
                 transactiontype,
                 year,
                 week,
                 residualvaluescheme_id,
                 residualvalueschemecode,
                 calculationbasis,
                 basecalculationweeks,
                 replacementpricetype,
                 resvalschemedefinition_id,
                 definitiontype,
                 startrange,
                 endrange,
                 startpercentage,
                 endpercentage,
                 fixedpercentage,
                 replacementprice,
                 residualvaluepercentage,
                 residualvalueamount,
                 currency_id,
                 calculationweeks,
                 weeksincirc,
                 weeksonstock,
                 washes,
                 customerrentstop,
                 rentstop,
                 wearerinactive,
                 seasoninactive,
                 onpassivestock,
                 indepositstock,
                 systemuser_id,
                 timestamp)
              values
                (seq_residualvaluehistory.nextval,
                 uid_rec.uniqueitem_id,
                 wid_rec.customer_id,
                 wid_rec.department_id,
                 uid_rec.distributionpoint_id,
                 uid_rec.weareremployment_id,
                 uid_rec.product_id,
                 uid_rec.sizedefinition_id,
                 uid_rec.finishingmethod_id,
                 sysdate,
                 0,
                 getyearofweek(sysdate),
                 getweeknumber(sysdate),
                 lv_residual_valueid,
                 lv_residualvaluecode,
                 lv_calcualtionbasis,
                 lv_calculationweeks,
                 lv_price_type,
                 lv_resvalschemedefid,
                 coalesce(lv_definitiontype, 1),
                 lv_startrange,
                 lv_endrange,
                 lv_startpercentage,
                 lv_endpercentage,
                 decode(lv_definitiontype, 2, null, lv_fixpercentage),
                 lv_replacement_price,
                 lv_rvprecentage,
                 lv_rvamount,
                 uid_rec.currency_id,
                 lv_calculatedweeks,
                 lv_weeksincirc,
                 lv_weeksonstock,
                 uid_rec.washestotal,
                 lv_customer_rentstop,
                 lv_rentstop,
                 lv_wearer_inactive,
                 lv_season_inactive,
                 lv_passive_stock,
                 lv_deposit_stock,
                 fp_systemUserID,
                 Current_Timestamp);

              --if residual value should not be frozen
            if (lv_actualweeksinuse = 0 or
               (lv_actualweeksinuse = 1 and lv_wearer_inactive = 0 and
               lv_customer_rentstop = 0 and lv_rentstop = 0 and
               lv_season_inactive = 0 and lv_deposit_stock = 0)) then

              --update uniqueitem table
              update_uniqueitem(uid_rec.uniqueitem_id,
                                lv_rvprecentage,
                                lv_rvamount,
                                lv_replacement_price,
                                false);
            else
              -- check & update uniqueitem table only if RV data is inconsistent
              update_uniqueitem(uid_rec.uniqueitem_id,
                              lv_rvprecentage,
                              lv_rvamount,
                              lv_replacement_price,
                              true);
            end if;
            exception

              when others then
                begin
                  write_log(sqlerrm, priority_debug);
                  write_log('Error CREATESQRESIDUALVALUEHISTORY:  Insert into residualvaluehistory. ' ||
                            'UniqueItem_id=' || uid_rec.uniqueitem_id,
                            priority_error);
                end;
            end;
          end if;
        end loop;
        commit;
      end if;
    end loop; --Processing items in ciculation(or assigned)

    write_log('Processing items in stock');
    --processing items in stock
    -- Initialization
    lv_residualvaluehistory_id := null;

    for uid_rec_stk in get_uid_stk loop
      gv_message := ' UniqueItem ID = ' || uid_rec_stk.uniqueitem_id;
      --check for existing residual value history record
      get_residualvaluehistory(uid_rec_stk.uniqueitem_id,
                               lv_residualvaluehistory_id,
                               lv_calculationdate);

      if (lv_residualvaluehistory_id is not null and lv_calculationdate is null) then
        continue;
      end if;
      if (lv_residualvaluehistory_id is not null) then

        begin
          select *
            into lv_record
            from residualvaluehistory rvh
           where rvh.residualvaluehistory_id = lv_residualvaluehistory_id;
        end;

        select seq_residualvaluehistory.nextval
          into lv_record.residualvaluehistory_id
          from dual;
        lv_record.calculationdate  := sysdate;
        lv_record.transactiontype  := 0;
        lv_record.year             := getyearofweek(sysdate);
        lv_record.week             := getweeknumber(sysdate);
        lv_record.weeksonstock     := coalesce(ceil((uid_rec_stk.daysinstockprevious +
                                                  (trunc(sysdate) -
                                                  uid_rec_stk.lastonstockdate)) / 7),
                                             0);
        lv_record.customerrentstop := 0;
        lv_record.rentstop         := 0;
        lv_record.wearerinactive   := 0;
        lv_record.seasoninactive   := 0;
        lv_record.onpassivestock   := 1;
        lv_record.indepositstock   := 0;
        lv_record.systemuser_id    := fp_systemUserID;
        lv_record.timestamp        := Current_Timestamp;

        insert into residualvaluehistory values lv_record;
        commit;
      else
        -- create record
        select seq_residualvaluehistory.nextval
          into lv_record.residualvaluehistory_id
          from dual;

        lv_record.uniqueitem_link_id := uid_rec_stk.uniqueitem_id;
        if uid_rec_stk.distributionpoint_id is not null then
          select dil.department_link_id
            into lv_record.department_link_id
            from distributionpoint_link dil
           where dil.distributionpoint_link_id =
                 uid_rec_stk.distributionpoint_id;
        else
          lv_record.department_link_id := null;
        end if;
        lv_record.distributionpoint_link_id := uid_rec_stk.distributionpoint_id;
        lv_record.weareremployment_link_id  := uid_rec_stk.lastweareremployment_link_id;
        lv_record.product_link_id           := uid_rec_stk.product_id;
        lv_record.sizedefinition_link_id    := uid_rec_stk.sizedefinition_id;
        lv_record.finishingmethod_id        := uid_rec_stk.finishingmethod_id;
        lv_record.calculationdate           := sysdate;
        lv_record.transactiontype           := 0;
        lv_record.year                      := getyearofweek(sysdate);
        lv_record.week                      := getweeknumber(sysdate);

        if uid_rec_stk.lastweareremployment_link_id is not null then
          -- select last customer that used the item
          select w.customer_id, wel.distributionpoint_link_id
            into lv_customer_id, lv_record.distributionpoint_link_id
            from weareremployment      we,
                 wearer                w,
                 weareremployment_link wel
           where  we.wearer_id = w.wearer_id
             and we.weareremployment_id = wel.weareremployment_id
             and wel.weareremployment_id =
                 uid_rec_stk.lastweareremployment_link_id;

          lv_record.customer_link_id := lv_customer_id;

          -- get product list per customer
          get_plpc(uid_rec_stk.product_id,
                   uid_rec_stk.sizedefinition_id,
                   uid_rec_stk.finishingmethod_id,
                   lv_customer_id,
                   lv_plpc_id_initial);

          if lv_plpc_id_initial is null then
            get_plpc_no_fm(lv_customer_id,
                           uid_rec_stk.product_id,
                           uid_rec_stk.sizedefinition_id,
                           lv_plpc_id);
            gv_message := gv_message || ' Plpc ID (no FM) = ' || lv_plpc_id;
          else
            lv_plpc_id := lv_plpc_id_initial;
            gv_message := gv_message || ' Plpc ID = ' || lv_plpc_id;
          end if;
          -- get residual value scheme
          if lv_plpc_id is not null then
            select rsv.residualvaluescheme_id,
                   rsv.code,
                   rsv.calculationbasis,
                   rsv.replacementpricetype,
                   rsv.calculationweeks,
                   rsv.calculationweeks
              into lv_record.residualvaluescheme_id,
                   lv_record.residualvalueschemecode,
                   lv_record.calculationbasis,
                   lv_record.replacementpricetype,
                   lv_record.calculationweeks,
                   lv_record.basecalculationweeks
              from productlistpercustomer plpc, residualvaluescheme rsv
             where plpc.residualvaluescheme_id = rsv.residualvaluescheme_id
               and plpc.productlistpercustomer_id = lv_plpc_id;

            --select resvalueschemedefinitiondetails
            lv_ui_age := get_ui_age(lv_record.calculationbasis,
                                    uid_rec_stk.daysincircprevissue,
                                    uid_rec_stk.lastissuedate,
                                    uid_rec_stk.washestotal);
            get_resvalueschemedef(lv_record.residualvaluescheme_id,
                                  lv_ui_age,
                                  lv_record.resvalschemedefinition_id,
                                  lv_record.definitiontype,
                                  lv_record.startrange,
                                  lv_record.endrange,
                                  lv_record.startpercentage,
                                  lv_record.endpercentage,
                                  lv_record.fixedpercentage);
            -- get price
            if lv_record.replacementpricetype = 1 and
               lv_record.resvalschemedefinition_id is not null then
               lv_replacement_price := Replacement_Price(lv_customer_id,
                                                                   uid_rec_stk.product_id,
                                                                   uid_rec_stk.sizedefinition_id);
            elsif lv_record.replacementpricetype = 2 then
              lv_replacement_price := uid_rec_stk.histreplacementpricefirstissue;
            elsif lv_record.replacementpricetype = 3 then
              lv_replacement_price := uid_rec_stk.histreplacementpricelastissue;
            end if;
            lv_record.replacementprice := lv_replacement_price;
          end if;
        end if;
        if (uid_rec_stk.lastweareremployment_link_id is null) or (lv_plpc_id is null) then
          lv_record.distributionpoint_link_id := null;
          lv_record.customer_link_id          := null;
          lv_record.residualvaluescheme_id    := null;
          lv_record.residualvalueschemecode   := null;
          lv_record.calculationbasis          := null;
          lv_record.replacementpricetype      := 1;
          lv_record.calculationweeks          := 0;
          lv_record.basecalculationweeks      := 0;
          lv_record.resvalschemedefinition_id := null;
          lv_record.definitiontype            := 1;
          lv_record.startrange                := null;
          lv_record.endrange                  := null;
          lv_record.startpercentage           := null;
          lv_record.endpercentage             := null;
          lv_record.fixedpercentage           := null;
          lv_record.replacementprice          := uid_rec_stk.residualvalueamount;
        end if;

        lv_record.residualvaluepercentage := uid_rec_stk.residualvalue;
        lv_record.residualvalueamount     := uid_rec_stk.residualvalueamount;
        lv_record.currency_id             := uid_rec_stk.currency_id;
        lv_record.calculationweeks        := coalesce(ceil(uid_rec_stk.daysincircprevissue / 7),
                                                      0);
        lv_record.weeksincirc             := coalesce(ceil(uid_rec_stk.daysincircprevissue / 7),
                                                      0);
        lv_record.weeksonstock            := coalesce(ceil((uid_rec_stk.daysinstockprevious +
                                                           (trunc(sysdate) -
                                                           uid_rec_stk.lastonstockdate)) / 7),
                                                      0);
        lv_record.washes                  := uid_rec_stk.washestotal;
        lv_record.customerrentstop        := 0;
        lv_record.rentstop                := 0;
        lv_record.wearerinactive          := 0;
        lv_record.seasoninactive          := 0;
        lv_record.onpassivestock          := 1;
        lv_record.indepositstock          := 0;
        lv_record.exported                := 0;
        lv_record.systemuser_id           := fp_systemUserID;
        lv_record.timestamp               := current_timestamp;

        insert into residualvaluehistory values lv_record;
      end if;

      -- check & update uniqueitem table only if RV data is inconsistent
      update_uniqueitem(uid_rec_stk.uniqueitem_id,
                      lv_record.residualvaluepercentage,
                      lv_record.residualvalueamount,
                      lv_record.replacementprice,
                      true);

      commit;
    end loop;
    write_log('END PACK_RESIDUALVALUEHISTORY.CREATESQRESIDUALVALUEHISTORY SUCCESSFUL');
    --close files
    end_log;
  exception
    when gv_userexception then
      begin
        write_log('Error CREATESQRESIDUALVALUEHISTORY: ', priority_error);
        end_log;
        rollback;
      end;
    when others then
      begin
        write_log(sqlerrm, priority_debug);
        write_log('Error CREATESQRESIDUALVALUEHISTORY: Others ' || '; Last message: ' || gv_message,
                  priority_error);
        end_log;
        rollback;
      end;
  end createSQResidualValueHistory;
begin
  -- Initialization
  begin
    select sy.systemuser_id
      into gv_systemuserid
      from systemuser sy
     where sy.username = 'SYSADM';
  exception
    when no_data_found then
      begin
        select sy.systemuser_id
          into gv_systemuserid
          from systemuser sy
         where sy.username = 'ABSADM';
      exception
        when no_data_found then
          begin
            select min(sy.systemuser_id)
              into gv_systemuserid
              from systemuser sy;
          end;
      end;
  end;

  begin
    select decode(d.code, 'JSG', 1, 0)
      into gv_alwaysrecalculaterv
      from databasesettings d
     where rownum = 1
       and exists (select 1
              from residualvaluescheme rvs
             where rvs.calculationbasis = 3);
  exception
    when no_data_found then
      gv_alwaysrecalculaterv := 0;
  end;
end PACK_RESIDUALVALUEHISTORY;
/
create or replace package pack_routetransaction is

  /*********************************************************************************************\
  * -- Author   : ABS                                                                           *
  * -- Version  : 2.3                                                                           *
  * -- Created  : 19-10-2009                                                                    *
  * -- Updated  : 12-05-2011 removed parameters transaction                                     *
  *               18-04-2012 always use stopnumber as passed, check delscheme                   *
  *                          with change stop same as with move stop                            *
  *               23-04-2012 use previous stop deliveryscheme in change route stop procedure    *
  *               04-09-2012 Added changes after testing package with ABSSolute                 *
  *               26-09-2012 Extra checks and changes for move route                            *
  *               13-10-2012 Less restrictions in the move route dates EMG                      *
  *               15-10-2012 Now do NOT delete productdeliveryday                               *
  *               16-10-2012 Added * to messages                                                *
  *               17-10-2012 Added = sign to change stopnumber check/update                     *
  *               30-10-2012 Updated move stop, extra start date and dyas check                 *
  *               01-11-2012 Updated selection for old stops removed = sign                     *
  *               05-11-2012 Stops,cancel only when no invoice for routecontrol                 *
  *               07-11-2012 Old stop from today possible.Update deliveryscans                  *
  *               31-01-2013 Extra check for move route todo 21976 from EMG                     *
  *               15-02-2013 (GSCTD21292)System_user passed as parameter in onlineroutechange   *
  *               27-02-2013 TD 22185 extra check routecontrol upd.analyse EMG                  *
  *               01-03-2013 TD 22196 remove check for NLI only upd.analyse EMG                 *
  *               08-03-2013 TD 22388 removed complete check pd.analyse EMG                     *
  *               19-04-2013 TD 22357 new system setting DIRECTSTOPCHANGE                       *
  *               22-05-2013 TS 21976 make active customerdeliveryscheme                        *
  *               16-01-2015 change stopnumber when routenumber length = 5   LST only           *
  *               28-01-2015 better logging with routetransactionid in logging                  *
  *               07-04-2015 merged with live version of packroutetransaction                   *
  *               27-07-2015 ABS-7284 lv_computedNextDrivingDate replaced by fp_changestartdate *
  *               08-02-2016 LST001-15 issue after merge, updated check update deliveryvariation*
  *               20-07-2016 ABS-24052 unique constraint error when moving route / ABS-24058    *
  *               08-12-2017 ABS-58723, ABS-58725 Add HOW ignoring restriction in PACK_Routetran*
  *               29-07-2020 ABS-105058 Correct move routestop functionality for                *
  *                          setting DIRECTSTOPCHANGE = 1                                       *
  *               10-12-2020 ABS-111557 package pack_routetransaction causes an error           *
  *               30-06-2022 ABS-132326 stop OLD route, on change start date                    *
  *               18-08-2022 ABS-118246 Cant move route stop to new route with stopnumber       *
  *               12-01-2022 ABS-145143 change when there are multiple stops to move            *
  *                          ABS-138148 Route move inactivate route stops - merge packages      *
  *               03-04-2024 ABS-160939 Moving a stop only allows move within one week          *
  * -- Purpose  : Route transactions, the option to change routes                               *
  *               Basis is the ROUTECHANGETRANSACTION table                                     *
  * -- Status   : 0 New not processed                                                           *
  *               1 Succesfully processed                                                       *
  *               2 Error                                                                       *
  *               3 Not processed because of batch rejection                                    *
  *               4 Cancel                                                                      *
  \*********************************************************************************************/

  procedure addroutechange(fp_changestartdate          in routechangetransaction.changestartdate%type,
                           fp_oldroutelastdrivingdate  in date,
                           fp_customernumber           in customer.customernumber%type,
                           fp_deliverypointcode        in deliverypoint.code%type,
                           fp_plantcode                in plant.code%type,
                           fp_drivingday               in day.daynumber%type,
                           fp_routenumber              in route.routenumber%type,
                           fp_depotcode                in depot.code%type,
                           fp_stopnumber               in routestop.stopnumber%type,
                           fp_deliveryschemecode       in deliveryscheme.code%type,
                           fp_newdrivingday            in day.daynumber%type,
                           fp_newroutenumber           in route.routenumber%type,
                           fp_newstopnumber            in routestop.stopnumber%type,
                           fp_newdeliveryscheme        in deliveryscheme.code%type,
                           fp_productgroupcode         in productgroup.code%type,
                           fp_errmsg                   out routechangetransaction.errormsg%type,
                           fp_routechangetransactionid out routechangetransaction.routechangetransaction_id%type);

  procedure getroutechangestatus(fp_routechangetransactionid in routechangetransaction.routechangetransaction_id%type,
                                 fp_errmsg                   out routechangetransaction.errormsg%type,
                                 fp_status                   out routechangetransaction.status%type);

  procedure processroutechanges(fp_plantcode              in plant.code%type,
                                fp_batchtransactionnumber out routechangetransaction.batchtransactionnumber%type,
                                fp_status                 out routechangetransaction.status%type);

  procedure reprocessroutechanges(fp_batchtransactionnumber in routechangetransaction.batchtransactionnumber%type,
                                  fp_status                 out routechangetransaction.status%type);

  procedure onlineroutechange(fp_changestartdate         in routechangetransaction.changestartdate%type,
                              fp_oldroutelastdrivingdate in date,
                              fp_customernumber          in customer.customernumber%type,
                              fp_deliverypointcode       in deliverypoint.code%type,
                              fp_plantcode               in plant.code%type,
                              fp_drivingday              in day.daynumber%type,
                              fp_routenumber             in route.routenumber%type,
                              fp_depotcode               in depot.code%type,
                              fp_stopnumber              in routestop.stopnumber%type,
                              fp_deliveryschemecode      in deliveryscheme.code%type,
                              fp_newdrivingday           in day.daynumber%type,
                              fp_newroutenumber          in route.routenumber%type,
                              fp_newstopnumber           in routestop.stopnumber%type,
                              fp_newdeliveryscheme       in deliveryscheme.code%type,
                              fp_productgroupcode        in productgroup.code%type,
                               fp_sortSequence            in routestop.sortsequence%type,
                              fp_errmsg                  out routechangetransaction.errormsg%type,
                              fp_onlineroutechange       out number,
                              fp_systemuserid            in systemuser.systemuser_id%type default 0);

  procedure cancelroutechange(fp_routechangetransactionid in routechangetransaction.routechangetransaction_id%type,
                              fp_status                   out routechangetransaction.status%type);
  function getssmovedeliveredstop(fp_plantcode in plant.code%type) return number;
end pack_routetransaction;
/
create or replace package body pack_routetransaction is
  gv_defaultuserid         systemuser.systemuser_id%type := 0;
  gv_message               abslog.message%type;
  gv_stopnrunique          systemsetting.value%type;
  gv_databasecode          databasesettings.code%type;
  gv_ss_directstopchange      systemsetting.value%type;
  gv_deliverydetermination systemsetting.value%type;
  ge_wrongvalue exception;
  ge_general    exception;
  gv_ss_movedeliveredstop systemsetting.value%type;
  gv_ss_movestopmoveup 		 systemsetting.value%type;

  type RouteChangeTransactionIdTable is table of number index by binary_integer;
  type MovestopmoveupStopNumberTable is table of number index by binary_integer;

  procedure write_log(fp_message  in abslog.message%type,
                      fp_priority in abslog.priority%type default 1) is
  begin
    /*
    Write message in ABSLOG with these priorities
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info
    */
    abslogwrite.abslog_write(5, 'pack_routetransaction', null, fp_priority, fp_message,
                             gv_defaultuserid);
  end write_log;

  function get_max_deliveryschemeid return number is
    lv_max_deliveryscheme deliveryscheme.deliveryscheme_id%type;
  begin
    --get max deliveryscheme, frequency 1 is the highest
    gv_message := 'get_max_deliveryschemeID';
    select min(ds.deliveryscheme_id)
    into   lv_max_deliveryscheme
    from   deliveryscheme ds
    where  ds.frequency = 1
    and    ds.offsetweek = 0;
    return lv_max_deliveryscheme;
  end get_max_deliveryschemeid;

  function get_plant_id(fp_plantcode in plant.code%type) return number is
    lv_plantid plant.plant_id%type;
  begin
    --get id for plant code
    gv_message := 'inactive plant code / plant code does not exist ' || nvl(fp_plantcode, 'NULL');
    select pt.plant_id
    into   lv_plantid
    from   plant pt
    where  pt.code = fp_plantcode
    and    pt.active = 'Y';
    return lv_plantid;
  end get_plant_id;

  function getssmovedeliveredstop(fp_plantcode in plant.code%type) return number is
    lv_value systemsetting.value%type;
  begin
    --get id for route
    gv_message := 'inactive route id / route id does not exist !';
    select ss.value
    into   lv_value
    from   systemsetting ss
    where  ss.name like 'MOVEDELIVEREDSTOP'
    and    ss.plant_id = (select p.plant_id from plant p where p.code = fp_plantcode);
    return lv_value;
  exception
    when no_data_found then
      begin
        return 0;
      end;
  end getssmovedeliveredstop;

  function get_systemsetting(fp_plantcode in plant.code%type, fp_settingname in systemsetting.name%type) return number is
    lv_value systemsetting.value%type;
  begin
    select ss.value
    into   lv_value
    from   SYSTEMSETTING ss
    where  ss.name = fp_settingname
    and    ss.plant_id = (select p.plant_id from plant p where p.code = fp_plantcode);
    return lv_value;
  exception
    when no_data_found then
      return 0;
  end get_systemsetting;

  function is_plant_active(fp_plantid in plant.plant_id%type) return boolean is
    lv_active plant.active%type;
  begin
    --check if plant is active
    select pt.active into lv_active from plant pt where pt.plant_id = fp_plantid;
    if lv_active = 'Y' then
      return true;
    else
      gv_message := ' Plant must be active';
      return false;
    end if;
  end is_plant_active;

  function get_route_id(fp_routenumber in route.routenumber%type,
                        fp_drivingday  in route.drivingday_id%type,
                        fp_plantid     in route.plant_id%type) return number is
    lv_routeid route.route_id%type;
    lv_active  route.active%type;
  begin
    --get rout id
    gv_message := 'Route does not exist, route ' || fp_routenumber || ' day ' || fp_drivingday ||
                  ' plantID ' || fp_plantid;
    select r.route_id, r.active
    into   lv_routeid, lv_active
    from   route r
    where  r.routenumber = fp_routenumber
    and    r.plant_id = fp_plantid
    and    r.drivingday_id = fp_drivingday;
    if lv_active <> 'Y' then
      gv_message := 'Route ' || fp_routenumber || ' day ' || fp_drivingday || ' plantID ' ||
                    fp_plantid || ' is not active';
      raise ge_general;
    end if;
    return lv_routeid;
  end get_route_id;

  function get_routestopid(fp_routeid         in route.route_id%type,
                           fp_customerid      in customer.customer_id%type,
                           fp_deliverypointid in deliverypoint.deliverypoint_id%type,
                           fp_stopnumber      in routestop.stopnumber%type,
                           fp_changedate      in routechangetransaction.changestartdate%type,
                           fp_transaction     in routechangetransaction.transactionnumber%type default 0)
    return routestop.routestop_id%type is
    lv_routestopid routestop.routestop_id%type;
    lv_counter     number;
  begin
    --check if stop exists for customer / deliverypoint
    gv_message := 'get active stop number ' || fp_stopnumber || ' for routeID ' || fp_routeid ||
                  ' for customerID ' || fp_customerid || ' deliverypointID ' ||
                  nvl(to_char(fp_deliverypointid), 'NULL') || ' for change date ' ||
                  to_char(fp_changedate, 'dd-mon-yyyy') || ' for transaction number ' ||
                  to_char(fp_transaction);
    begin
      select routestop_id
      into   lv_routestopid
      from   (select rs.routestop_id
               from   routestop rs
               where  rs.route_id = fp_routeid
               and    rs.customer_id = fp_customerid
               and    rs.stopnumber = fp_stopnumber
               and    ((fp_deliverypointid is null and rs.deliverypoint_id is null) or
                     fp_deliverypointid = rs.deliverypoint_id)
               and    ((gv_ss_directstopchange = 0 and
                     ((fp_changedate between rs.dateactive and rs.dateinactive-1) or
                     (fp_transaction in (5, 6) and gv_databasecode not in ('LST')))) or
                     (gv_ss_directstopchange = 1 and trunc(sysdate) between rs.dateactive and
                     rs.dateinactive))
               order  by rs.dateactive desc) ---now take the most recent active one, in case there is more then 1...
      where  rownum = 1;
    exception
      when no_data_found then
        begin
          if fp_transaction = 99 then
            --not found on the right date, lets ignore that..8-6-2015 wbo/simo/pvd
            gv_message := 'get active stop number ' || fp_stopnumber || ' for routeID ' ||
                          fp_routeid || ' for customerID ' || fp_customerid || ' deliverypointID ' ||
                          nvl(to_char(fp_deliverypointid), 'NULL') || ' for JIT stop number change';
            select routestop_id
            into   lv_routestopid
            from   (select rs.routestop_id
                     from   routestop rs
                     where  rs.route_id = fp_routeid
                     and    rs.customer_id = fp_customerid
                     and    rs.stopnumber = fp_stopnumber
                     and    ((fp_deliverypointid is null and rs.deliverypoint_id is null) or
                           fp_deliverypointid = rs.deliverypoint_id)
                     and    rs.movedroutestop_id is null
                     order  by rs.dateactive desc)
            where  rownum = 1;
          else
            raise no_data_found;
          end if;
        end;
    end;
    --26-09-2012 extra check for more stops
    if fp_changedate > trunc(sysdate) and gv_ss_directstopchange = 0 then
      begin
        select count(1)
        into   lv_counter
        from   routestop rs
        where  rs.route_id = fp_routeid
        and    rs.customer_id = fp_customerid
        and    rs.stopnumber = fp_stopnumber
        and    fp_changedate between rs.dateactive and rs.dateinactive-1
        and    ((fp_deliverypointid is null and rs.deliverypoint_id is null) or
              fp_deliverypointid = rs.deliverypoint_id); --check if more then one future route is found
        if lv_counter > 1 then
          gv_message := 'More than one future route stop exists. Stop cannot be moved/changed/deleted';
          raise ge_general;
        end if;
      end;
    end if;
    --
    return lv_routestopid;
  end get_routestopid;

  function check_dup_stop_route(fp_routeid    in route.route_id%type,
                                fp_stopnumber in routestop.stopnumber%type,
                                fp_changedate in routechangetransaction.changestartdate%type)
    return boolean is
    lv_routestopid routestop.routestop_id%type;
  begin
    --check if stop exists
    gv_message := 'check if stop number ' || fp_stopnumber || ' for routeID ' || fp_routeid ||
                  ' already exists';
    select max(rs.routestop_id)
    into   lv_routestopid
    from   routestop rs
    where  rs.route_id = fp_routeid
    and    rs.stopnumber = fp_stopnumber
    and    fp_changedate between rs.dateactive and rs.dateinactive;
    if lv_routestopid is null then
      return false;
    else
      return true;
    end if;
  end check_dup_stop_route;

  function get_district_id(fp_plantid in plant.plant_id%type) return number is
    lv_districtid district.district_id%type;
  begin
    --get district id of plant
    gv_message := 'get_district_id for plantID ' || fp_plantid;
    select min(dp.district_id)
    into   lv_districtid
    from   districtplant dp
    where  dp.plant_id = fp_plantid;
    return lv_districtid;
  end get_district_id;

  function get_max_batchtransactionnumber return number is
    lv_batchtransactionnumber routechangetransaction.batchtransactionnumber%type;
  begin
    --get_max_batchtransactionnumber
    select max(rct.batchtransactionnumber) + 1
    into   lv_batchtransactionnumber
    from   routechangetransaction rct;
    return lv_batchtransactionnumber;
  end get_max_batchtransactionnumber;

  function get_depot_id(fp_depotcode in depot.code%type, fp_plantid in plant.plant_id%type)
    return number is
    lv_depotid        depot.depot_id%type;
    lv_plantaddressid plant.address_id%type;
  begin
    --get or create depot id
    gv_message := 'depot code ' || nvl(fp_depotcode, 'NULL') || ' for plantID ' ||
                  to_char(fp_plantid);
    if fp_depotcode is null then
      return null;
    else
      select dt.depot_id
      into   lv_depotid
      from   depot dt
      where  dt.code = fp_depotcode
      and    dt.plant_id = fp_plantid;
      return lv_depotid;
    end if;
  exception
    when no_data_found then
      begin
        --create depot if it does not yet exist
        select pt.address_id into lv_plantaddressid from plant pt where pt.plant_id = fp_plantid;
        --get next sequence
        select seq_depot.nextval into lv_depotid from dual;
        --insert into depot
        insert into depot
          (depot_id, plant_id, code, description, systemuser_id, address_id, timestamp, phoneno,
           faxno)
        values
          (lv_depotid, fp_plantid, fp_depotcode, fp_depotcode, gv_defaultuserid, lv_plantaddressid,
           sysdate, null, null);
        return lv_depotid;
      end;
  end get_depot_id;

     function updateDuplicateDVAmount(fp_changestartdate deliveryvariations.deliverydate%type,
                                  fp_oldstopid       packingnote.stop_id%type,
                                  fp_processed       deliveryvariations.processed%type,
                                  fp_oldroutestopid  routestop.routestop_id%type
                                   )

   return number is
   lv_duplicateDeliveryVarId deliveryvariations.deliveryvariations_id%type;
   lv_count number;
 begin

 if (fp_processed = 'Y') then

      for xdv in (select *
                 from deliveryvariations dv
                where dv.processed = fp_processed
                  and dv.deliverydate <> fp_changestartdate
                  and dv.packingnote_id in
                      (select pk.packingnote_id
                         from packingnote pk
                        where pk.stop_id = fp_oldstopid)) loop
     begin
       update deliveryvariations dv
          set dv.deliverydate  = fp_changestartdate,
              dv.systemuser_id = gv_defaultuserid,
              dv.timestamp     = sysdate
        where dv.deliveryvariations_id = xdv.deliveryvariations_id;
     exception
       when dup_val_on_index then
         select max(dv.deliveryvariations_id)
           into lv_duplicateDeliveryVarId
           from deliveryvariations dv
          where dv.distributionpoint_id = xdv.distributionpoint_id
            and dv.product_id = xdv.product_id
            and dv.sizedefinition_id = xdv.sizedefinition_id
            and dv.finishingmethod_id = xdv.finishingmethod_id
            and dv.packingnote_id is null
            and dv.processed = fp_processed
            and dv.deliverydate = fp_changestartdate
            and dv.origin = xdv.origin
            and nvl(dv.causenote_id, 0) = nvl(xdv.causenote_id, 0)
            and dv.updaterentqty = xdv.updaterentqty
            and dv.soilcountsubtype = xdv.soilcountsubtype
            and nvl(dv.weborderline_id, 0) = nvl(xdv.weborderline_id, 0)
            and nvl(dv.reference, 0) = nvl(xdv.reference, 0)
            and nvl(dv.adjustmentreason_id, 0) =
                nvl(xdv.adjustmentreason_id, 0)
            and nvl(dv.reasoncode_id, 0) = nvl(xdv.reasoncode_id, 0);

         update deliveryvariations dv
            set dv.amount        = dv.amount + xdv.amount,
                dv.systemuser_id = gv_defaultuserid,
                dv.timestamp     = sysdate
          where dv.deliveryvariations_id = lv_duplicateDeliveryVarId;

         delete from deliveryvariations dv
          where dv.deliveryvariations_id = xdv.deliveryvariations_id;

     end;
   end loop; -- xdv

   else

    select count(*)
           into lv_count
                 from deliveryvariations dv
                where dv.processed = fp_processed
				and dv.origin <> 3
                  and  getabsdaynumber(dv.deliverydate) = (select r.drivingday_id
                                                          from routestop rss join route r on r.route_id=rss.route_id
                                                          where rss.routestop_id=fp_oldroutestopid)
                   and    dv.distributionpoint_id =  (select dp.distributionpoint_id
                    from   distributionpoint dp, department d
                    where  d.customer_id = (select st.customer_link_id from stop st where st.stop_id = fp_oldstopid )
                    and    d.department_id = dp.department_id
					and    dp.distributionpoint_id = dv.distributionpoint_id);


     for xdv in (select *
                 from deliveryvariations dv
                where dv.processed = fp_processed
				and dv.origin <> 3
                  and  getabsdaynumber(dv.deliverydate) = (select r.drivingday_id
                                                          from routestop rss join route r on r.route_id=rss.route_id
                                                          where rss.routestop_id=fp_oldroutestopid)
                   and    dv.distributionpoint_id = (select dp.distributionpoint_id
                    from   distributionpoint dp, department d
                    where
                    d.customer_id = (select st.customer_link_id from stop st where st.stop_id = fp_oldstopid )
                    and    d.department_id = dp.department_id
                    and    dp.distributionpoint_id = dv.distributionpoint_id) ) loop
     begin
       update deliveryvariations dv
          set dv.deliverydate  = fp_changestartdate,
              dv.systemuser_id = gv_defaultuserid,
              dv.timestamp     = sysdate
        where dv.deliveryvariations_id = xdv.deliveryvariations_id;
     exception
       when dup_val_on_index then
         select max(dv.deliveryvariations_id)
           into lv_duplicateDeliveryVarId
           from deliveryvariations dv
          where dv.distributionpoint_id = xdv.distributionpoint_id
            and dv.product_id = xdv.product_id
            and dv.sizedefinition_id = xdv.sizedefinition_id
            and dv.finishingmethod_id = xdv.finishingmethod_id
            and dv.processed = xdv.processed
            and dv.deliverydate = fp_changestartdate
            and dv.origin = xdv.origin
            and nvl(dv.causenote_id, 0) = nvl(xdv.causenote_id, 0)
            and dv.updaterentqty = xdv.updaterentqty
            and dv.soilcountsubtype = xdv.soilcountsubtype
            and nvl(dv.weborderline_id, 0) = nvl(xdv.weborderline_id, 0)
            and nvl(dv.reference, 0) = nvl(xdv.reference, 0)
            and nvl(dv.adjustmentreason_id, 0) =
                nvl(xdv.adjustmentreason_id, 0)
            and nvl(dv.reasoncode_id, 0) = nvl(xdv.reasoncode_id, 0);

         update deliveryvariations dv
            set dv.amount        = dv.amount + xdv.amount,
                dv.systemuser_id = gv_defaultuserid,
                dv.timestamp     = sysdate
          where dv.deliveryvariations_id = lv_duplicateDeliveryVarId;

         delete from deliveryvariations dv
          where dv.deliveryvariations_id = xdv.deliveryvariations_id;

     end;
   end loop; -- xdv


   end if;

   return lv_duplicateDeliveryVarId;
 end updateDuplicateDVAmount;


  procedure init_route(fp_routerec in out route%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init route';
    --fill the route row with default values from its table
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'ROUTE'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_routerec;
    close rcur_typ;
    fp_routerec.systemuser_id := gv_defaultuserid;
    fp_routerec.timestamp     := sysdate;
    --get route sequence
    gv_message := 'get sequence for route';
    select seq_route.nextval into fp_routerec.route_id from dual;
    --other default values
    fp_routerec.putupreportpercustomer := 0;
    fp_routerec.putupreportperroute    := 'N';
    fp_routerec.putupreportperdepot    := 'N';
    fp_routerec.putupreportroutestop   := 0;
    fp_routerec.printsoilticket        := 'N';
    fp_routerec.printorderform         := 0;
    fp_routerec.bundletagsflatw        := 0;
    fp_routerec.bundletagsgarm         := 0;
  end init_route;

  procedure init_routestop(fp_routestoprec in out routestop%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init routestop';
    --fill the route row with default values from its table
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'ROUTESTOP'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_routestoprec;
    close rcur_typ;
    fp_routestoprec.systemuser_id := gv_defaultuserid;
    fp_routestoprec.timestamp     := sysdate;
    --get route sequence
    gv_message := 'get sequence for routestop';
    select seq_routestop.nextval into fp_routestoprec.routestop_id from dual;
    --other default values
    fp_routestoprec.stoptype       := 3;
    fp_routestoprec.returnroute_id := fp_routestoprec.route_id;
    fp_routestoprec.soiltickets    := 0;
  end init_routestop;

  procedure init_stop(fp_stoprec in out stop%rowtype) is
    lv_query varchar2(1000);
    type cur_typ is ref cursor;
    rcur_typ cur_typ;
  begin
    gv_message := 'init stop';
    --fill the route row with default values from its table
    for rec in (select data_default, data_type
                from   user_tab_columns
                where  table_name = 'STOP'
                order  by column_id) loop
      if rec.data_default is null then
        lv_query := lv_query || ', null';
      else
        lv_query := lv_query || ', ' || rec.data_default;
      end if;
    end loop;
    lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
    open rcur_typ for lv_query;
    fetch rcur_typ
      into fp_stoprec;
    close rcur_typ;
    fp_stoprec.systemuser_id := gv_defaultuserid;
    fp_stoprec.timestamp     := sysdate;
    --get route sequence
    gv_message := 'get sequence for stop';
    select seq_stop.nextval into fp_stoprec.stop_id from dual;
    --other default values
    fp_stoprec.status            := 0;
    fp_stoprec.chargedeliveryfee := 0;
    fp_stoprec.visitminutes      := 0;
    fp_stoprec.travelminutes     := 0;
    fp_stoprec.stoptype          := 3;
  end init_stop;

  procedure create_cpltransition(fp_oldstandarddeliverylineid in standarddeliveryline.standarddeliveryline_id%type,
                                 fp_newstandarddeliverylineid in standarddeliveryline.standarddeliveryline_id%type) is
  begin
    --create_cpltransition
    gv_message := 'insert cpltransition';
    insert into cpltransition
      (oldstandarddeliveryline_id, newstandarddeliveryline_id, systemuser_id, timestamp)
    values
      (fp_oldstandarddeliverylineid, fp_newstandarddeliverylineid, gv_defaultuserid, sysdate);
  exception
    when dup_val_on_index then
      null; --no problem is already there
  end create_cpltransition;

  function get_new_stopnumber(fp_routeid     in route.route_id%type,
                              fp_stopnumber  in routestop.stopnumber%type,
                              fp_changedate  in routechangetransaction.changestartdate%type,
                              fp_routenumber in route.routenumber%type) return number is
  begin
    --get_new_stopnumber
    gv_message := 'get_new_stopnumber';
    if gv_stopnrunique = 1 then
      --double numbers allowed
      return fp_stopnumber;
    else
      begin
        if check_dup_stop_route(fp_routeid, fp_stopnumber, fp_changedate) then
          --stop already found try with stop 0
          write_log('Stopnumber ' || to_char(fp_stopnumber) || ' already used for route ' ||
                    to_char(fp_routenumber), 2);
          return fp_stopnumber;
        else
          return fp_stopnumber;
        end if;
      exception
        when no_data_found then
          return fp_stopnumber;
      end;
    end if;
  end get_new_stopnumber;

  function check_customer_active(fp_customerid in customer.customer_id%type) return date is
    lv_active         customer.active%type;
    lv_customernumber customer.customernumber%type;
    lv_dateactive     customer.dateactive%type;
    lv_dateinactive   customer.dateinactive%type;
  begin
    --check if customer is active
    select c.customernumber, c.active, c.dateactive, c.dateinactive
    into   lv_customernumber, lv_active, lv_dateactive, lv_dateinactive
    from   customer c
    where  c.customer_id = fp_customerid;
    if (lv_active <> 'Y') or not (sysdate between lv_dateactive and lv_dateinactive) then
      gv_message := 'Customer ' || lv_customernumber || ' is not active';
      raise ge_general;
    end if;
    return lv_dateinactive;
  end check_customer_active;

  procedure check_deliverypoint_active(fp_deliverypointid in deliverypoint.deliverypoint_id%type) is
    lv_active deliverypoint.active%type;
  begin
    --check_deliverypoint_active
    if fp_deliverypointid is not null then
      gv_message := 'check_deliverypoint_active ' || fp_deliverypointid;
      select dp.active
      into   lv_active
      from   deliverypoint dp
      where  dp.deliverypoint_id = fp_deliverypointid;
      if lv_active <> 'Y' then
        gv_message := 'Deliverypoint is not active ' || fp_deliverypointid;
        raise ge_general;
      end if;
    end if;
  end check_deliverypoint_active;

  procedure check_customer_bu(fp_customerid in customer.customer_id%type,
                              fp_plantid    in plant.plant_id%type) is
    lv_plantid plant.plant_id%type;
  begin
    --check BU's via plants
    select bu.plant_id
    into   lv_plantid
    from   customer c, businessunit bu
    where  c.customer_id = fp_customerid
    and    c.defaultbusinessunit_id = bu.businessunit_id;
    if lv_plantid <> fp_plantid then
      begin
        select bu.plant_id
        into   lv_plantid
        from   customeractivities ca, businessunit bu
        where  ca.customer_id = fp_customerid
        and    ca.processbusinessunit_id = bu.businessunit_id
        and    bu.plant_id = fp_plantid;
      exception
        when no_data_found then
          gv_message := 'Customer not processed in this plant';
          raise ge_general;
      end;
    end if;
  end check_customer_bu;

  procedure check_deliveryschemes(fp_newdeliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                  fp_routeid             in route.route_id%type,
                                  fp_routedeliveryscheme in out route.deliveryscheme_id%type) is
    lv_newfrequency   deliveryscheme.frequency%type;
    lv_routefrequency deliveryscheme.frequency%type;
    lv_newoffset      deliveryscheme.offsetweek%type;
    lv_routeoffset    deliveryscheme.offsetweek%type;
  begin
    --check_deliveryschemes
    gv_message := 'check_deliveryschemes for routeID ' || fp_routeid;
    --get route deliveryscheme
    if fp_routedeliveryscheme is null then
      select r.deliveryscheme_id
      into   fp_routedeliveryscheme
      from   route r
      where  r.route_id = fp_routeid;
    end if;
    if fp_newdeliveryschemeid is not null then
      --get data fp_newdeliveryschemeid
      select ds.frequency, ds.offsetweek
      into   lv_newfrequency, lv_newoffset
      from   deliveryscheme ds
      where  ds.deliveryscheme_id = fp_newdeliveryschemeid;
      --get data fp_routedeliveryscheme
      select ds.frequency, ds.offsetweek
      into   lv_routefrequency, lv_routeoffset
      from   deliveryscheme ds
      where  ds.deliveryscheme_id = fp_routedeliveryscheme;
      if gv_databasecode <> 'LST' then
        begin
          --08-04-2015 no checks for LST
          --checks
          if lv_newfrequency < lv_routefrequency then
            gv_message := 'Stop has a higher frequency then the route';
            raise ge_general;
          end if;
          if mod(lv_newfrequency, lv_routefrequency) > 0 then
            gv_message := 'Frequency of the stop does not match the frequency of the route';
            raise ge_general;
          end if;
          if mod((lv_newoffset - lv_routeoffset), lv_routefrequency) > 0 then
            gv_message := 'Offset of the stop does not match the offset of the route';
            raise ge_general;
          end if;
        end;
      end if;
    end if;
  end check_deliveryschemes;

  procedure check_sortbatch(fp_routestopid in routestop.routestop_id%type,
                            fp_changedate  in routechangetransaction.changestartdate%type) is
    lv_countsortbatch number;
  begin
    if gv_ss_directstopchange = 0 then
      --check_sortbatch
      gv_message := 'check_sortbatch';
      select count(1)
      into   lv_countsortbatch
      from   sortbatchcontents sbc
      where  sbc.routestop_id = fp_routestopid
      and    exists (select 1
              from   sortbatch sb
              where  sb.sortbatch_id = sbc.sortbatch_id
              and    sb.status in (1, 2)
              and    sb.batchdate >= fp_changedate);
      if lv_countsortbatch > 0 then
        gv_message := 'There is a sortbatch from this stop that must be sorted first';
        raise ge_general;
      end if;
    end if;
  exception
    when no_data_found then
      null;
  end check_sortbatch;

  procedure add_customer_deldays_movestop(fp_customerid       in customer.customer_id%type,
                                          fp_deliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                          fp_dayid            in customerdeliveryscheme.day_id%type,
                                          fp_olddayid         in customerdeliveryscheme.day_id%type,
                                          fp_oldroutestopid   in routestop.routestop_id%type,
                                          fp_changedate       in date,
                                          fp_old_delschemeid  in deliveryscheme.deliveryscheme_id%type,
                                          fp_deliverypointid  in deliverypoint.deliverypoint_id%type) is
    old_deliverytype customerdeliveryday.deliverytype%type;
    to_deliverytype  customerdeliveryday.deliverytype%type;
    autosoilqty autosoilquantity.quantity%type;
  begin
    --copy the productdeliveryday PLPC, only existing records, new is not needed
    for x in (select l.productlistpercustomer_id, pdd.deliverytype
              from   productlistpercustomer l, productdeliveryday pdd
              where  l.customer_id = fp_customerid
              and    l.productlistpercustomer_id = pdd.productlistpercustomer_id
              and    l.dateinactive >= fp_changedate
              and    pdd.day_id = fp_olddayid
              and    not exists
               (select 1
                      from   productdeliveryday pddx
                      where  pddx.productlistpercustomer_id = pdd.productlistpercustomer_id
                      and    pddx.day_id = fp_dayid
                      and    pddx.deliverytype = pdd.deliverytype)) loop
      begin
        insert into productdeliveryday
          (productlistpercustomer_id, day_id, timestamp, systemuser_id, deliverytype)
        values
          (x.productlistpercustomer_id, fp_dayid, sysdate, gv_defaultuserid, x.deliverytype);
      exception
        when dup_val_on_index then
          begin
            --already did exist, wrong delivery type, so update it, will be type B only
            if x.deliverytype = 'B' then
              begin
                update productdeliveryday pdd
                set    pdd.deliverytype = x.deliverytype,
                       pdd.systemuser_id = gv_defaultuserid,
                       pdd.timestamp = sysdate
                where  pdd.productlistpercustomer_id = x.productlistpercustomer_id
                and    pdd.day_id = fp_dayid;
              end;
            end if;
          end;
      end;
    end loop; --x PLPC loop

 for xc in (  select l.productlistpercustomer_id
              from   productlistpercustomer l, customerdeliveryday cd, product p
              where  l.customer_id = fp_customerid
              and    cd.customer_id = fp_customerid
              and    l.dateinactive >= fp_changedate
              and    cd.day_id = fp_olddayid
              and    cd.typeofmerchadise = p.typeofmerchandise
              and    l.product_id = p.product_id
              and    not exists
               (select 1
                      from   customerdeliveryday cdx
                      where  cdx.customer_id = fp_customerid
                      and    cdx.day_id = fp_dayid
                      ))loop
      begin

        select aq.quantity
        into autosoilqty
          from autosoilquantity aq
          where aq.productlistpercustomer_id = xc.productlistpercustomer_id
          and aq.day_id = fp_olddayid;
       exception
        when no_data_found then
          null;
      end;
       if autosoilqty is not null then
            begin
              update autosoilquantity aq
                 set aq.day_id        = fp_dayid,
                     aq.systemuser_id = gv_defaultuserid,
                     aq.timestamp     = sysdate
               where aq.productlistpercustomer_id = xc.productlistpercustomer_id
                     and aq.day_id = fp_olddayid;
              end;
              end if;

    end loop; --xc Autosoil loop
    --add_customer_deliveryscheme_and_days
    gv_message := 'add_customer_deldays_movestop for customerID ' || fp_customerid ||
                  ' deliveryschemeID ' || fp_deliveryschemeid || ' day ' || fp_dayid;
    if fp_deliveryschemeid is not null then
      --try to add, if it already exists no problem
      begin
        insert into customerdeliveryscheme
          (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
        values
          (fp_customerid, fp_deliveryschemeid, fp_dayid, gv_defaultuserid, sysdate);
      exception
        when dup_val_on_index then
          update customerdeliveryscheme ds
          set    ds.active = 'Y',
                 ds.systemuser_id = gv_defaultuserid,
                 ds.timestamp = sysdate
          where  ds.active <> 'Y'
          and    ds.customer_id = fp_customerid
          and    ds.deliveryscheme_id = fp_deliveryschemeid
          and    ds.day_id = fp_dayid;
      end;
    end if;
    --loop add customerdeliveryschemes
    for x in (select dsprs.deliveryscheme_id
              from   deliveryschemesperstop dsprs
              where  dsprs.routestop_id = fp_oldroutestopid
              and    (dsprs.deliveryscheme_id <> fp_old_delschemeid)-- or fp_old_delschemeid is null)
              group  by dsprs.deliveryscheme_id) loop
      begin
        insert into customerdeliveryscheme
          (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
        values
          (fp_customerid, x.deliveryscheme_id, fp_dayid, gv_defaultuserid, sysdate);
      exception
        when dup_val_on_index then
          update customerdeliveryscheme ds
          set    ds.active = 'Y',
                 ds.systemuser_id = gv_defaultuserid,
                 ds.timestamp = sysdate
          where  ds.active <> 'Y'
          and    ds.customer_id = fp_customerid
          and    ds.deliveryscheme_id = x.deliveryscheme_id
          and    ds.day_id = fp_dayid;
      end;
    end loop;
    -- linen days
    begin
      select customerdeliveryday.deliverytype
      into   old_deliverytype
      from   customerdeliveryday
      where  customerdeliveryday.customer_id = fp_customerid
      and    customerdeliveryday.day_id = fp_olddayid
      and    customerdeliveryday.typeofmerchadise = 1;
    exception
      when no_data_found then
        old_deliverytype := null;
    end;
    gv_message := 'move_stop old_deliverytype=' || old_deliverytype || ' for day ' || fp_olddayid ||
                  ' and TOM = 1';
    begin
      to_deliverytype := null;
      select customerdeliveryday.deliverytype
      into   to_deliverytype
      from   customerdeliveryday
      where  customerdeliveryday.customer_id = fp_customerid
      and    customerdeliveryday.day_id = fp_dayid
      and    customerdeliveryday.typeofmerchadise = 1;
      --departments day should be activated /deactivated:
      begin
        for xd in (select t.department_id
                   from   department t
                   where  t.customer_id = fp_customerid
                   and    not exists (select 1
                           from   distributionpoint dp
                           where  dp.department_id = t.department_id
                           and    (dp.deliverypoint_id = fp_deliverypointid or
                                 fp_deliverypointid is null))
                         -- to not exists a route stop for that day already and the department should not be inactivate
                   and    not exists (select 1
                           from   routestop rs, distributionpoint dp, route r
                           where  dp.department_id = t.department_id
                           and    (dp.deliverypoint_id = rs.deliverypoint_id or
                                 rs.deliverypoint_id is null)
                           and    rs.route_id = r.route_id
                           and    rs.customer_id = t.customer_id
                           and    r.drivingday_id = fp_dayid)) loop
          begin
            insert into deliveryday
              (day_id, department_id, systemuser_id, timestamp)
            values
              (fp_dayid, xd.department_id, gv_defaultuserid, sysdate);
          exception
            when dup_val_on_index then
              null;
          end;
        end loop; --xd
      exception
        when no_data_found then
          null;
      end;
      begin
        for xd in (select t.department_id
                   from   department t
                   where  t.customer_id = fp_customerid
                   minus
                   select t.department_id
                   from   department t
                   where  t.customer_id = fp_customerid
                   and    not exists (select 1
                           from   distributionpoint dp
                           where  dp.department_id = t.department_id
                           and    (dp.deliverypoint_id = fp_deliverypointid or
                                 fp_deliverypointid is null))
                         -- to not exists a route stop for that day already and the department should not be inactivate
                   and    not exists (select 1
                           from   routestop rs, distributionpoint dp, route r
                           where  dp.department_id = t.department_id
                           and    (dp.deliverypoint_id = rs.deliverypoint_id or
                                 rs.deliverypoint_id is null)
                           and    rs.route_id = r.route_id
                           and    rs.customer_id = t.customer_id
                           and    r.drivingday_id = fp_dayid)) loop
          begin
            delete from deliveryday
            where  day_id = fp_dayid
            and    department_id = xd.department_id;
          exception
            when others then
              null;
          end;
        end loop; --xd
      end;
      begin
        for xd in (select t.department_id
                   from   department t, deliveryday dd
                   where  t.customer_id = fp_customerid
                   and    t.department_id = dd.department_id
                   and    dd.day_id = fp_olddayid) loop
          begin
            insert into deliveryday
              (day_id, department_id, systemuser_id, timestamp)
            values
              (fp_dayid, xd.department_id, gv_defaultuserid, sysdate);
          exception
            when dup_val_on_index then
              null;
          end;
        end loop; --xd
      exception
        when no_data_found then
          null;
      end;
    exception
      when no_data_found then
        --no customer delivery days found
        begin
          if old_deliverytype is not null then
            gv_message := 'move_stop insert line in customer dv days for ' || old_deliverytype ||
                          ' for day ' || fp_dayid || ' and TOM = 1';
            insert into customerdeliveryday
              (customer_id, day_id, timestamp, systemuser_id, deliverytype, typeofmerchadise)
            values
              (fp_customerid, fp_dayid, sysdate, gv_defaultuserid, old_deliverytype, 1);
            --copy deliverydays as well
            for xd in (select t.department_id
                       from   department t
                       where  t.customer_id = fp_customerid
                       and    not exists (select 1
                               from   distributionpoint dp
                               where  dp.department_id = t.department_id
                               and    (dp.deliverypoint_id = fp_deliverypointid or
                                     fp_deliverypointid is null))
                             -- to not exists a route stop for that day already and the department should not be inactivate
                       and    not exists (select 1
                               from   routestop rs, distributionpoint dp, route r
                               where  dp.department_id = t.department_id
                               and    (dp.deliverypoint_id = rs.deliverypoint_id or
                                     rs.deliverypoint_id is null)
                               and    rs.route_id = r.route_id
                               and    rs.customer_id = t.customer_id
                               and    r.drivingday_id = fp_dayid)) loop
              begin
                insert into deliveryday
                  (day_id, department_id, systemuser_id, timestamp)
                values
                  (fp_dayid, xd.department_id, gv_defaultuserid, sysdate);
              exception
                when dup_val_on_index then
                  null;
              end;
            end loop; --xd
            for xd in (select t.department_id
                       from   department t
                       where  t.customer_id = fp_customerid
                       minus
                       select t.department_id
                       from   department t
                       where  t.customer_id = fp_customerid
                       and    not exists (select 1
                               from   distributionpoint dp
                               where  dp.department_id = t.department_id
                               and    (dp.deliverypoint_id = fp_deliverypointid or
                                     fp_deliverypointid is null))
                             -- to not exists a route stop for that day already and the department should not be inactivate
                       and    not exists (select 1
                               from   routestop rs, distributionpoint dp, route r
                               where  dp.department_id = t.department_id
                               and    (dp.deliverypoint_id = rs.deliverypoint_id or
                                     rs.deliverypoint_id is null)
                               and    rs.route_id = r.route_id
                               and    rs.customer_id = t.customer_id
                               and    r.drivingday_id = fp_dayid)) loop
              begin
                delete from deliveryday
                where  day_id = fp_dayid
                and    department_id = xd.department_id;
              exception
                when others then
                  null;
              end;
            end loop; --xd
            begin
              --keep the same departments delivery by inserting in destination day a record in deliveriday
              for xd in (select t.department_id
                         from   department t, deliveryday dd
                         where  t.customer_id = fp_customerid
                         and    t.department_id = dd.department_id
                         and    dd.day_id = fp_olddayid) loop
                begin
                  insert into deliveryday
                    (day_id, department_id, systemuser_id, timestamp)
                  values
                    (fp_dayid, xd.department_id, gv_defaultuserid, sysdate);
                exception
                  when dup_val_on_index then
                    null;
                end;
              end loop; --xd
            exception
              when no_data_found then
                null;
            end;
          end if;
        end;
    end;
    if to_deliverytype is not null then
      gv_message := 'move_stop to_deliverytype = ' || to_deliverytype || ' for day ' || fp_dayid ||
                    ' and TOM = 1';
      if (old_deliverytype = 'B' and to_deliverytype <> 'B') or
         (old_deliverytype = 'D' and to_deliverytype = 'P') then
        update customerdeliveryday
        set    timestamp = sysdate, systemuser_id = gv_defaultuserid,
               deliverytype = old_deliverytype
        where  customerdeliveryday.customer_id = fp_customerid
        and    customerdeliveryday.day_id = fp_dayid
        and    customerdeliveryday.typeofmerchadise = 1;
      end if;
    end if;
    -- garments days
    begin
      old_deliverytype := null;
      select customerdeliveryday.deliverytype
      into   old_deliverytype
      from   customerdeliveryday
      where  customerdeliveryday.customer_id = fp_customerid
      and    customerdeliveryday.day_id = fp_olddayid
      and    customerdeliveryday.typeofmerchadise = 2;
    exception
      when no_data_found then
        old_deliverytype := null;
    end;
    gv_message := 'move_stop old_deliverytype=' || old_deliverytype || ' for day ' || fp_olddayid ||
                  ' and TOM = 2';
    begin
      to_deliverytype := null;
      select customerdeliveryday.deliverytype
      into   to_deliverytype
      from   customerdeliveryday
      where  customerdeliveryday.customer_id = fp_customerid
      and    customerdeliveryday.day_id = fp_dayid
      and    customerdeliveryday.typeofmerchadise = 2;
    exception
      when no_data_found then
        begin
          if old_deliverytype is not null then
            gv_message := 'move_stop insert line in customer dv days for ' || old_deliverytype ||
                          ' for day ' || fp_dayid || ' and TOM = 2';
            insert into customerdeliveryday
              (customer_id, day_id, timestamp, systemuser_id, deliverytype, typeofmerchadise)
            values
              (fp_customerid, fp_dayid, sysdate, gv_defaultuserid, old_deliverytype, 2);
          end if;
        end;
    end;
    if to_deliverytype is not null then
      gv_message := 'move_stop to_deliverytype = ' || to_deliverytype || ' for day ' || fp_dayid ||
                    ' and TOM = 2';
      if (old_deliverytype = 'B' and to_deliverytype <> 'B') or
         (old_deliverytype = 'D' and to_deliverytype = 'P') then
        update customerdeliveryday
        set    timestamp = sysdate, systemuser_id = gv_defaultuserid,
               deliverytype = old_deliverytype
        where  customerdeliveryday.customer_id = fp_customerid
        and    customerdeliveryday.day_id = fp_dayid
        and    customerdeliveryday.typeofmerchadise = 2;
      end if;
    end if;
    -- residential days
    begin
      old_deliverytype := null;
      select customerdeliveryday.deliverytype
      into   old_deliverytype
      from   customerdeliveryday
      where  customerdeliveryday.customer_id = fp_customerid
      and    customerdeliveryday.day_id = fp_olddayid
      and    customerdeliveryday.typeofmerchadise = 5;
    exception
      when no_data_found then
        old_deliverytype := null;
    end;
    gv_message := 'move_stop old_deliverytype=' || old_deliverytype || ' for day ' || fp_olddayid ||
                  ' and TOM = 5';
    begin
      to_deliverytype := null;
      select customerdeliveryday.deliverytype
      into   to_deliverytype
      from   customerdeliveryday
      where  customerdeliveryday.customer_id = fp_customerid
      and    customerdeliveryday.day_id = fp_dayid
      and    customerdeliveryday.typeofmerchadise = 5;
    exception
      when no_data_found then
        begin
          if old_deliverytype is not null then
            gv_message := 'move_stop insert line in customer dv days for ' || old_deliverytype ||
                          ' for day ' || fp_dayid || ' and TOM = 5';
            insert into customerdeliveryday
              (customer_id, day_id, timestamp, systemuser_id, deliverytype, typeofmerchadise)
            values
              (fp_customerid, fp_dayid, sysdate, gv_defaultuserid, old_deliverytype, 5);
          end if;
        end;
    end;
    if to_deliverytype is not null then
      gv_message := 'move_stop to_deliverytype = ' || to_deliverytype || ' for day ' || fp_dayid ||
                    ' and TOM = 5';
      if (old_deliverytype = 'B' and to_deliverytype <> 'B') or
         (old_deliverytype = 'D' and to_deliverytype = 'P') then
        update customerdeliveryday
        set    timestamp = sysdate, systemuser_id = gv_defaultuserid,
               deliverytype = old_deliverytype
        where  customerdeliveryday.customer_id = fp_customerid
        and    customerdeliveryday.day_id = fp_dayid
        and    customerdeliveryday.typeofmerchadise = 5;
      end if;
    end if;
  end add_customer_deldays_movestop;

  procedure add_customer_delscheme_days(fp_customerid       in customer.customer_id%type,
                                        fp_deliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                        fp_dayid            in customerdeliveryscheme.day_id%type) is
    lv_numberofwearers number;
  begin
    --add_customer_deliveryscheme_and_days
    gv_message := 'add_customer_deliveryscheme_and_days for customerID ' || fp_customerid ||
                  ' deliveryschemeID ' || fp_deliveryschemeid || ' day ' || fp_dayid;
    --try to add, if it already exists no problem
    begin
      insert into CUSTOMERDELIVERYSCHEME
        (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
      values
        (fp_customerid, fp_deliveryschemeid, fp_dayid, gv_defaultuserid, sysdate);
    exception
      when dup_val_on_index then
        update customerdeliveryscheme ds
        set    ds.active = 'Y',
               systemuser_id = gv_defaultuserid,
               timestamp = sysdate
        where  ds.active <> 'Y'
        and    ds.customer_id = fp_customerid
        and    ds.deliveryscheme_id = fp_deliveryschemeid
        and    ds.day_id = fp_dayid;
    end;
    --add to customer deliveryday, for linnen
    begin
      insert into CUSTOMERDELIVERYDAY
        (customer_id, day_id, timestamp, systemuser_id, deliverytype, typeofmerchadise)
      values
        (fp_customerid, fp_dayid, sysdate, gv_defaultuserid, 'D', 1);
    exception
      when dup_val_on_index then
        null;
    end;
    --add if need be customer deliveryday, for garments
    select count(1) into lv_numberofwearers from wearer w where w.customer_id = fp_customerid;
    if lv_numberofwearers >= 1 then
      begin
        insert into CUSTOMERDELIVERYDAY
          (customer_id, day_id, timestamp, systemuser_id, deliverytype, typeofmerchadise)
        values
          (fp_customerid, fp_dayid, sysdate, gv_defaultuserid, 'D', 2);
      exception
        when dup_val_on_index then
          null;
      end;
    end if;
  end add_customer_delscheme_days;

  procedure inactivate_stop_routcontrol(fp_routeid         in route.route_id%type,
                                        fp_routestopid     in routestop.routestop_id%type,
                                        fp_changestartdate in routechangetransaction.changestartdate%type) is
    lv_routealreadypackedcount number;
  begin
    --inactivate_stop_routcontrol
    gv_message := 'inactivate_stop_routcontrol';
    --check if stop is packed already
    select count(1)
    into   lv_routealreadypackedcount
    from   routecontrol rc, stop st
    where  rc.route_id = fp_routeid
    and    rc.drivingdate >= fp_changestartdate
    and    rc.routecontrol_id = st.routecontrol_id
    and    st.routestop_id = fp_routestopid
    and    (rc.packingstatus >= 3 or gv_ss_movedeliveredstop = 1)
    and    st.status not in (1, 2, 3); --not cancelled/moved out/moved in
    if lv_routealreadypackedcount > 0 then
      gv_message := 'Routestop is being packed / delivered, stop will not be cancelled';
      raise ge_general;
    end if;
    --cancel stops from route status control
    for xs in (select st.stop_id
               from   routecontrol rc, stop st
               where  rc.route_id = fp_routeid
               and    (rc.packingstatus in (1, 2) or gv_ss_movedeliveredstop = 1)
               and    rc.drivingdate > fp_changestartdate
               and    rc.invoicesgenerated = 1 --cancel only when no invoice
               and    st.routecontrol_id = rc.routecontrol_id
               and    st.routestop_id = fp_routestopid) loop
      begin
        --update stop make cancelled
        update stop st
        set    st.status = 1, st.systemuser_id = gv_defaultuserid, st.timestamp = sysdate
        where  st.stop_id = xs.stop_id;
        --update all packing notes, remove all stop/route/routecontrol id's set to null
        update packingnote pk
        set    pk.routecontrol_id = null, pk.route_id = null, pk.stop_id = null, pk.stopnumber = 0,
               pk.systemuser_id = gv_defaultuserid, pk.timestamp = sysdate
        where  pk.stop_id = xs.stop_id;
        --update all client delivery notes, remove all stop/route/routecontrol id's set to null
        update clientdeliverynote cdn
        set    cdn.routecontrol_id = null, cdn.route_id = null, cdn.stop_id = null,
               cdn.stopnumber = 0, cdn.systemuser_id = gv_defaultuserid, cdn.timestamp = sysdate
        where  cdn.stop_id = xs.stop_id;
        --update straightevenreturn
        update straightevenreturn sr
        set    sr.stop_id = null, sr.systemuser_id = gv_defaultuserid, sr.timestamp = sysdate
        where  sr.stop_id = xs.stop_id;
      end;
    end loop; --xs
  end inactivate_stop_routcontrol;

  procedure add_stop_to_routecontrol(fp_newrouteid          in route.route_id%type,
                                     fp_newstopnumber       in routestop.stopnumber%type,
                                     fp_newroutestopid      in routestop.routestop_id%type,
                                     fp_customerid          in customer.customer_id%type,
                                     fp_changestartdate     in routechangetransaction.changestartdate%type,
                                     fp_cancel_oldstopid_yn in varchar2 default 'N', --parameters below only needed for cancel
                                     fp_oldroutestopid      in routestop.routestop_id%type,
                                     fp_oldstopnumber       in stop.stopnumber%type,
                                     fp_canceldate          in date,
                                     fp_deliverypointid     in routechangetransaction.deliverypoint_id%type) is
    lv_stoprec                stop%rowtype;
    lv_stopstatusxs           stop.status%type;
    lv_daycheck               number;
    lv_to_routecontrolid      routecontrol.routecontrol_id%type;
    lv_routecontrol_has_stops boolean;
    lv_duplicatedeliveryvarid number;
    begin
        --add_stop_to_routecontrol
    gv_message := 'add_stop_to_routecontrol';
    --get / check if route control needs to be updated
    for xr in (select rc.routecontrol_id, rc.drivingdate, rc.packingstatus, rc.route_id
               from   routecontrol rc
               where  rc.route_id = fp_newrouteid
               and    (rc.packingstatus < 3 or gv_databasecode = 'NLI' or gv_databasecode = 'SMG' or
                     gv_ss_movedeliveredstop = 1)
               and    rc.drivingdate >= trunc(fp_changestartdate)) loop
      begin
        lv_routecontrol_has_stops := false;
        --update the stops with newroutestopid if found a moved-in stop having also oldroutestopid
        for y in (select s.stop_id, s.stopnumber
                  from   stop s
                  where  s.routecontrol_id = xr.routecontrol_id
                  and    s.customer_link_id = fp_customerid
                        --and    s.stopnumber = case when (gv_databasecode <> 'SMG') then fp_newstopnumber else s.stopnumber end
                  and    s.status not in (1, 2)) loop
          begin
            --only SMG consider also the other stops than newstopnumber
            --(and this case should be logged in abslog table)
            if (y.stopnumber <> fp_newstopnumber) then
              if (gv_databasecode <> 'SMG') then
                continue;
              else
                write_log('SMG Exception: The StopNumber[' || to_char(fp_newstopnumber) ||
                          '] not added to {RC[' || to_char(xr.routecontrol_id) || '] /R[' ||
                          to_char(xr.route_id) || '] /C[' || to_char(fp_customerid) ||
                          ']} (because already existing stop {SN[' || to_char(y.stopnumber) ||
                          '] /S[' || to_char(y.stop_id) || ']} on same route)!', 2);
              end if;
            end if;
            lv_routecontrol_has_stops := true;
            update stop
            set    routestop_id = fp_newroutestopid,
                   systemuser_id = gv_defaultuserid,
                   timestamp = sysdate
            where  routestop_id = fp_oldroutestopid
            and    stop_id = y.stop_id
            and    status = 3;
          end;
        end loop; --y
        --if no stops found then insert one
        if (not lv_routecontrol_has_stops) then
          begin
            if (gv_databasecode = 'NLI' or gv_databasecode = 'SMG') and xr.packingstatus = 4 then
              update routecontrol rc
              set    rc.packingstatus = 3,
                     rc.systemuser_id = gv_defaultuserid,
                     rc.timestamp = sysdate
              where  rc.routecontrol_id = xr.routecontrol_id
              and    xr.packingstatus >= 4;
            end if;
            --check the route stop freq. related to the route frequency, read driving day
            for z in (select ds.frequency, ds.offsetweek
                      from   deliveryschemesperstop de, deliveryscheme ds
                      where  de.routestop_id = fp_newroutestopid
                      and    de.deliveryscheme_id = ds.deliveryscheme_id
                      group  by ds.frequency, ds.offsetweek
                      order  by ds.frequency, ds.offsetweek) loop
              begin
                select mod((getdateforweekyear(getabsdaynumber(xr.drivingdate),
                                                getisoweek(xr.drivingdate),
                                                getyearofweek(xr.drivingdate)) -
                            getdateforweekyear(getabsdaynumber(xr.drivingdate), ds.referenceweek,
                                                ds.referenceyear)), (z.frequency * 7)) -
                        (z.offsetweek * 7)
                into   lv_daycheck
                from   databasesettings ds;
                if lv_daycheck = 0 then
                  begin
                    --insert into stop
                    init_stop(lv_stoprec);
                    lv_stoprec.stopnumber       := fp_newstopnumber;
                    lv_stoprec.routecontrol_id  := xr.routecontrol_id;
                    lv_stoprec.routestop_id     := fp_newroutestopid;
                    lv_stoprec.customer_link_id := fp_customerid;
                    lv_stoprec.deliverypoint_id := fp_deliverypointid;
                    gv_message                  := 'insert into stop';
                    insert into stop values lv_stoprec;
                    exit;
                  end;
                end if;
              end;
            end loop; --z
          end;
        end if;
      end;
    end loop; --xr

    --check if old stop needs to be cancelled
    if fp_cancel_oldstopid_yn = 'Y' then
      begin
        --find the old stops to be cancelled
        for xs in (select st.stop_id oldstopid, st.deliverypoint_id, rc.routecontrol_id,
                          rc.drivingdate
                   from   stop st, routecontrol rc
                   where  st.routestop_id = fp_oldroutestopid
                   and    st.stopnumber = fp_oldstopnumber
                   and    st.customer_link_id = fp_customerid
                   and    st.routecontrol_id = rc.routecontrol_id
                   and    (gv_databasecode = 'NLI' or --todo 22196 EMG, still cancel for NLI
                         (rc.packingstatus < 3 or gv_ss_movedeliveredstop = 1)
                         and rc.invoicesgenerated = 1) --cancel only when no invoice
                   and    rc.drivingdate > nvl(fp_canceldate, fp_changestartdate)) loop
          begin
            --cancel stop
            select st.status into lv_stopstatusxs from stop st where st.stop_id = xs.oldstopid;
            if lv_stopstatusxs not in (1, 2, 3) then
              update stop st
              set    st.status = 1, st.systemuser_id = gv_defaultuserid, st.timestamp = sysdate
              where  st.stop_id = xs.oldstopid;
            end if;
            --find new stop/routecontrol
            select max(rc.routecontrol_id),
                   max((select max(st.stop_id)
                        from   stop st
                        where  st.routecontrol_id = rc.routecontrol_id
                        and    st.customer_link_id = fp_customerid
                        and    st.routestop_id = fp_newroutestopid))
            into   lv_to_routecontrolid, lv_stoprec.stop_id
            from   routecontrol rc
            where  rc.route_id = fp_newrouteid
            and    rc.drivingdate = fp_changestartdate;
            --update ALL delivery variations linked to the packing notes that had old stopid
            --in case of an unique index exception, add DVs to an existing one
            begin
              update deliveryvariations dv
              set    dv.deliverydate = fp_changestartdate, dv.systemuser_id = gv_defaultuserid,
                     dv.timestamp = sysdate
              where  dv.processed = 'Y'
              and    dv.deliverydate <> fp_changestartdate
              and    dv.packingnote_id in
                     (select pk.packingnote_id from packingnote pk where pk.stop_id = xs.oldstopid);
            exception
              when dup_val_on_index then
                --try to update DVs one by one and sum them up when needed
                lv_duplicateDeliveryVarId := updateDuplicateDVAmount (fp_changestartdate, xs.oldstopid, 'Y', fp_oldroutestopid);
            end;
            --update ALL packing notes with new stopid that had old stopid
            update packingnote pk
            set    pk.routecontrol_id = lv_to_routecontrolid, pk.stop_id = lv_stoprec.stop_id,
                   pk.stopnumber = fp_newstopnumber, pk.route_id = fp_newrouteid,
                   pk.deliverydate = fp_changestartdate,
                   pk.systemuser_id = gv_defaultuserid, pk.timestamp = sysdate
            where  pk.stop_id = xs.oldstopid;
            --update ALL client delivery notes with new stopid that had old stopid
            update clientdeliverynote cdn
            set    cdn.routecontrol_id = lv_to_routecontrolid, cdn.stop_id = lv_stoprec.stop_id,
                   cdn.stopnumber = fp_newstopnumber, cdn.route_id = fp_newrouteid,
                   cdn.deliverydate = fp_changestartdate,
                   cdn.systemuser_id = gv_defaultuserid, cdn.timestamp = sysdate
            where  cdn.stop_id = xs.oldstopid;
            -- update ALL delivery variations not processed linked to an old stopid
            begin

            update deliveryvariations dv
            set    dv.deliverydate = fp_changestartdate,
                   dv.systemuser_id = gv_defaultuserid,
                   dv.timestamp = sysdate
            where  dv.processed = 'N'
            and    dv.origin <> 3 --Manual Entry
            and    dv.deliverydate = xs.drivingdate
            and    exists
             (select 1
                    from   stop s
                    join   department t
                    on     t.customer_id = s.customer_link_id
                    join   distributionpoint dp
                    on     dp.department_id = t.department_id
                    where  s.stop_id = xs.oldstopid
                    and    dp.distributionpoint_id = dv.distributionpoint_id
                    and    (s.deliverypoint_id = dp.deliverypoint_id or
                          (s.deliverypoint_id is null and s.customer_link_id = t.customer_id)));

            exception
              when dup_val_on_index then
                --try to update DVs suumarizing the amounts for existing records
                lv_duplicateDeliveryVarId := updateDuplicateDVAmount(fp_changestartdate, xs.oldstopid, 'N', fp_oldroutestopid);
            end;

            --update ALL straightevenreturn with new stopid that had old stopid
            update straightevenreturn str
            set    str.stop_id = lv_stoprec.stop_id,
                   str.systemuser_id = gv_defaultuserid,
                   str.timestamp = sysdate
            where  str.stop_id = xs.oldstopid;
            --update deliveryscans
            update deliveryscan ds
            set    ds.routecontrol_id = lv_to_routecontrolid,
                   ds.planneddeliverydate = fp_changestartdate,
                   ds.systemuser_id = gv_defaultuserid,
                   ds.timestamp = sysdate
            where  ds.routecontrol_id = xs.routecontrol_id
            and    ds.packingnote_id is null
            and    ds.customer_link_id = fp_customerid
            and    (xs.deliverypoint_id is null or ds.deliverypoint_link_id = xs.deliverypoint_id);
            --update ALL bagtags with new stopid that had old stopid
            update bagtag bt
            set    bt.stop_id = lv_stoprec.stop_id, bt.route_id = fp_newrouteid,
                   bt.planneddeliverydate = fp_changestartdate,
                   bt.systemuser_id = gv_defaultuserid,
                   bt.timestamp = sysdate
            where  bt.stop_id = xs.oldstopid;
            --update uniqueitemroute for system setting DELIVERYDETERMINATION = 1
            if gv_deliverydetermination = 1 then
              begin
                update uniqueitem ui
                set    ui.planneddeliverydate = fp_changestartdate,
                       ui.systemuser_id = gv_defaultuserid, ui.timestamp = sysdate
                where  ui.uniqueitem_id =
                       (select uir.uniqueitem_id
                        from   uniqueitemroute uir
                        where  uir.plannedoutstop_id = xs.oldstopid);
                update uniqueitemroute uir
                set    uir.plannedoutroute_id = fp_newrouteid,
                       uir.plannedoutdate = fp_changestartdate,
                       uir.plannedoutstop_id = lv_stoprec.stop_id,
                       uir.systemuser_id = gv_defaultuserid, uir.timestamp = sysdate
                where  uir.plannedoutstop_id = xs.oldstopid;
                update uniqueitemroute uir
                set    uir.lastoutroute_id = fp_newrouteid, uir.lastoutdate = fp_changestartdate,
                       uir.lastoutstop_id = lv_stoprec.stop_id,
                       uir.systemuser_id = gv_defaultuserid,
                       uir.timestamp = sysdate
                where  uir.lastoutstop_id = xs.oldstopid
                and    exists (select 1
                        from   deliveryscan ds
                        left   outer join packingnote pn
                        on     ds.packingnote_id = pn.packingnote_id
                        where  ds.uniqueitem_link_id = uir.uniqueitem_id
                        and    pn.status_id = (select status_id
                                               from   status
                                               where  statustype = 'PN'
                                               and    code = '10'));
              end;
            end if;
          end;
        end loop; --xs
      end;
    end if; --fp_cancel_oldstopid_yn = 'Y'
  end add_stop_to_routecontrol;


  procedure copy_child_records(fp_oldstandarddeliveryid in standarddelivery.standarddelivery_id%type,
                               fp_newstandarddeliveryid in standarddelivery.standarddelivery_id%type) is
    lv_temporarydeliverystoprec temporarydeliverystop%rowtype;
    lv_temporaryrentstoprec     temporaryrentstop%rowtype;
  begin
    --copy_child_records
    gv_message := 'copy_child_records';
    for xf in (select *
               from   temporarydeliverystop td
               where  td.standarddeliveryline_id = fp_oldstandarddeliveryid) loop
      begin
        --temporarydeliverystop
        lv_temporarydeliverystoprec                         := xf;
        lv_temporarydeliverystoprec.standarddeliveryline_id := fp_newstandarddeliveryid;
        lv_temporarydeliverystoprec.systemuser_id           := gv_defaultuserid;
        lv_temporarydeliverystoprec.timestamp               := sysdate;
        select seq_temporarydeliverystop.nextval
        into   lv_temporarydeliverystoprec.temporarydeliverystop_id
        from   dual;
        gv_message := 'insert into temporarydeliverystop';
        insert into temporarydeliverystop values lv_temporarydeliverystoprec;
      end;
    end loop; --xf
    for xg in (select *
               from   temporaryrentstop tr
               where  tr.standarddeliveryline_id = fp_oldstandarddeliveryid) loop
      begin
        --temporaryrentstop
        lv_temporaryrentstoprec                         := xg;
        lv_temporaryrentstoprec.standarddeliveryline_id := fp_newstandarddeliveryid;
        lv_temporaryrentstoprec.systemuser_id           := gv_defaultuserid;
        lv_temporaryrentstoprec.timestamp               := sysdate;
        select seq_temporaryrentstop.nextval
        into   lv_temporaryrentstoprec.temporaryrentstop_id
        from   dual;
        gv_message := 'insert into temporaryrentstop';
        insert into temporaryrentstop values lv_temporaryrentstoprec;
      end;
    end loop; --xg
  end copy_child_records;

  procedure putenddate2standarddeliveries(fp_customerid      in customer.customer_id%type,
                                          fp_deliverypointid in deliverypoint.deliverypoint_id%type,
                                          fp_drivingday_id   in day.day_id%type,
                                          fp_changestartdate in date) is
    lv_someotherstopscount         number;
    lv_otherdeliverydayscount      number;
    lv_standarddeliverylinerec     standarddeliveryline%rowtype;
    lv_standarddeliveryamountrec   standarddeliveryamount%rowtype;
    lv_standarddeliveryamntdtlsrec standarddeliveryamntdetails%rowtype;
  begin
    --putenddate2standarddeliveries
    gv_message := 'put end date to standardeliveries';
    --if there is no other stop for this customer/deliverypoint on this driving day
    --then standard deliveries must be stopped as well
    select count(1)
    into   lv_someotherstopscount
    from   routestop rs, route r
    where  rs.customer_id = fp_customerid
    and    (rs.deliverypoint_id = fp_deliverypointid or
          (fp_deliverypointid is null and rs.deliverypoint_id is null))
    and    rs.route_id = r.route_id
    and    r.drivingday_id = fp_drivingday_id
    and    rs.dateinactive > fp_changestartdate;
    --if no other stops then stop standard deliveries
    if lv_someotherstopscount = 0 then
      for xd in (select stl.*
                 from   standarddelivery std, standarddeliveryline stl, distributionpoint dp,
                        department t
                 where  std.standarddelivery_id = stl.standarddelivery_id
                 and    std.distributionpoint_id = dp.distributionpoint_id
                 and    dp.department_id = t.department_id
                 and    t.customer_id = fp_customerid
                 and    (dp.deliverypoint_id = fp_deliverypointid or
                       (fp_deliverypointid is null and dp.deliverypoint_id is null))
                 and    stl.dateinactive > fp_changestartdate
                 and    stl.dateactive <= stl.dateinactive
                 and    exists
                  (select 1
                         from   standarddeliveryamount sta
                         where  sta.standarddeliveryline_id = stl.standarddeliveryline_id
                         and    sta.day_id = fp_drivingday_id)) loop
        begin
          --check for other deliverydays
          select count(1)
          into   lv_otherdeliverydayscount
          from   standarddeliveryamount a
          where  a.standarddeliveryline_id = xd.standarddeliveryline_id
          and    a.day_id <> fp_drivingday_id;
          --if they exist
          if lv_otherdeliverydayscount > 0 then
            --copy standarddeliveryline
            lv_standarddeliverylinerec := xd;
            select seq_standarddeliveryline.nextval
            into   lv_standarddeliverylinerec.standarddeliveryline_id
            from   dual;
            --use max date active
            if lv_standarddeliverylinerec.dateactive < fp_changestartdate then
              begin
                lv_standarddeliverylinerec.dateactive := fp_changestartdate;
                --check if we really need a new record
                if lv_standarddeliverylinerec.dateactive >= lv_standarddeliverylinerec.dateinactive then
                  raise ge_general; --no new record needed
                end if;
              end;
            end if;
            lv_standarddeliverylinerec.systemuser_id := gv_defaultuserid;
            lv_standarddeliverylinerec.timestamp     := sysdate;
            --write new standarddeliveryline
            gv_message := 'insert standarddeliveryline';
            insert into standarddeliveryline values lv_standarddeliverylinerec;
            --create cpl transition record
            create_cpltransition(xd.standarddeliveryline_id,
                                 lv_standarddeliverylinerec.standarddeliveryline_id);
            --copy child records
            for xe in (select *
                       from   standarddeliveryamount sa
                       where  sa.standarddeliveryline_id = xd.standarddeliveryline_id
                       and    sa.day_id <> fp_drivingday_id) loop
              begin
                --standarddeliveryamount
                lv_standarddeliveryamountrec                         := xe;
                lv_standarddeliveryamountrec.standarddeliveryline_id := lv_standarddeliverylinerec.standarddeliveryline_id;
                lv_standarddeliveryamountrec.systemuser_id           := gv_defaultuserid;
                lv_standarddeliveryamountrec.timestamp               := sysdate;
                gv_message                                           := 'insert standarddeliveryamount';
                insert into standarddeliveryamount values lv_standarddeliveryamountrec;
              end;
            end loop; --xe
            for xh in (select *
                       from   standarddeliveryamntdetails sda
                       where  sda.standarddeliveryline_id = xd.standarddeliveryline_id
                       and    sda.day_id <> fp_drivingday_id) loop
              begin
                lv_standarddeliveryamntdtlsrec                         := xh;
                lv_standarddeliveryamntdtlsrec.standarddeliveryline_id := lv_standarddeliverylinerec.standarddeliveryline_id;
                lv_standarddeliveryamntdtlsrec.systemuser_id           := gv_defaultuserid;
                lv_standarddeliveryamntdtlsrec.timestamp               := sysdate;
                select seq_stddeliveryamntdetails.nextval
                into   lv_standarddeliveryamntdtlsrec.standarddeliveryamntdetails_id
                from   dual;
                gv_message := 'insert into standarddeliveryamntdetails';
                insert into standarddeliveryamntdetails values lv_standarddeliveryamntdtlsrec;
              end;
            end loop; --xh
            copy_child_records(xd.standarddeliveryline_id,
                               lv_standarddeliverylinerec.standarddeliveryline_id);
          end if;
        exception
          when ge_general then
            null;
        end;
      end loop; --xd
    end if;
  end putenddate2standarddeliveries;

  procedure insert_standarddeliveryline(fp_standarddeliverylinerec   in standarddeliveryline%rowtype,
                                        fp_drivingday                in routechangetransaction.drivingday_id%type,
                                        fp_newdrivingday             in routechangetransaction.newdrivingday_id%type,
                                        fp_changedate                in routechangetransaction.changestartdate%type,
                                        fp_new_deliveryschemeid      in deliveryscheme.deliveryscheme_id%type,
                                        fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_newstandarddeliverylinerec  standarddeliveryline%rowtype;
    lv_standarddeliveryamountrec   standarddeliveryamount%rowtype;
    lv_standarddeliveryamntdtlsrec standarddeliveryamntdetails%rowtype;
    lv_countstdamountlines         number;
    lv_alreadyexist_new_sdl_id			number;
  begin
    --copy standarddeliveryline
    lv_newstandarddeliverylinerec := fp_standarddeliverylinerec;

    --check if already exists the SDL for the new deliveryschemeid
    --and decide if duplicate the old deliveryschemeid SDL
    --or just update fro the existing new deliveryschemeid SDL
    begin
      lv_alreadyexist_new_sdl_id := 0;
      select sdl.standarddeliveryline_id
        into lv_alreadyexist_new_sdl_id
        from standarddeliveryline sdl
       where sdl.standarddelivery_id = lv_newstandarddeliverylinerec.standarddelivery_id
         and sdl.productlistperdistribpoint_id = lv_newstandarddeliverylinerec.productlistperdistribpoint_id
         and sdl.deliveryscheme_id = fp_new_deliveryschemeid
         and sdl.dateactive = fp_changedate
         and sdl.season_id = lv_newstandarddeliverylinerec.season_id;
    exception
      when NO_DATA_FOUND then
        lv_alreadyexist_new_sdl_id := 0;
    end;
		--if the SDL for the new deliveryschemeid doesn't exist
		if (lv_alreadyexist_new_sdl_id = 0) then
    select seq_standarddeliveryline.nextval
    into   lv_newstandarddeliverylinerec.standarddeliveryline_id
    from   dual;
    else
      lv_newstandarddeliverylinerec.standarddeliveryline_id := lv_alreadyexist_new_sdl_id;
    end if;

    lv_newstandarddeliverylinerec.deliveryscheme_id := fp_new_deliveryschemeid;
    --use max date active, when it was in the future keep that date
    if lv_newstandarddeliverylinerec.dateactive < fp_changedate and
       (lv_newstandarddeliverylinerec.renewal = 'N' or
       (lv_newstandarddeliverylinerec.renewal = 'Y' and
       fp_changedate < lv_newstandarddeliverylinerec.dateinactive)) then
      lv_newstandarddeliverylinerec.dateactive := fp_changedate;
    end if;

    --check if we really need a new record
    if lv_newstandarddeliverylinerec.dateactive > lv_newstandarddeliverylinerec.dateinactive then
      raise ge_general; --no new record needed
    end if;
    lv_newstandarddeliverylinerec.systemuser_id := gv_defaultuserid;
    lv_newstandarddeliverylinerec.timestamp     := sysdate;
    --insert a new SDL record only if doesn't exist
    if (lv_alreadyexist_new_sdl_id = 0) then
      gv_message := 'insert into standarddeliveryline';
      insert into standarddeliveryline values lv_newstandarddeliverylinerec;
		end if;

    --create cpltransition
    create_cpltransition(fp_standarddeliverylinerec.standarddeliveryline_id,
                         lv_newstandarddeliverylinerec.standarddeliveryline_id);
    begin
      insert into customerdeliveryscheme
        (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp, active)
      values
        (fp_routechangetransactionrec.customer_id, lv_newstandarddeliverylinerec.deliveryscheme_id,
         fp_newdrivingday, gv_defaultuserid, sysdate, 'Y');
    exception
      when dup_val_on_index then
        null;
    end;
    --insert or update for standarddeliveryamount table
    for xe in (select *
               from   standarddeliveryamount sa
               where  sa.standarddeliveryline_id =
                      fp_standarddeliverylinerec.standarddeliveryline_id
               and    sa.day_id = fp_drivingday) loop
      begin
        --standarddeliveryamount
        lv_standarddeliveryamountrec                         := xe;
        lv_standarddeliveryamountrec.standarddeliveryline_id := lv_newstandarddeliverylinerec.standarddeliveryline_id;
        lv_standarddeliveryamountrec.day_id                  := nvl(fp_newdrivingday, fp_drivingday);
        lv_standarddeliveryamountrec.systemuser_id           := gv_defaultuserid;
        lv_standarddeliveryamountrec.timestamp               := sysdate;
        gv_message                                           := 'insert into standarddeliveryamount';
        insert into standarddeliveryamount values lv_standarddeliveryamountrec;
      exception
        when dup_val_on_index then
          gv_message := 'update standarddeliveryamount';
          update standarddeliveryamount sa
          set    sa.amount = sa.amount + xe.amount
          where  sa.standarddeliveryline_id = lv_newstandarddeliverylinerec.standarddeliveryline_id
          and    sa.day_id = fp_newdrivingday;
      end;
    end loop; --xe
    --insert or not for standarddeliveryamntdetails table
    for xh in (select *
               from   standarddeliveryamntdetails sda
               where  sda.standarddeliveryline_id =
                      fp_standarddeliverylinerec.standarddeliveryline_id
               and    sda.day_id = fp_drivingday) loop
      begin
        lv_standarddeliveryamntdtlsrec                         := xh;
        lv_standarddeliveryamntdtlsrec.standarddeliveryline_id := lv_newstandarddeliverylinerec.standarddeliveryline_id;
        lv_standarddeliveryamntdtlsrec.day_id                  := nvl(fp_newdrivingday, fp_drivingday);
        lv_standarddeliveryamntdtlsrec.systemuser_id           := gv_defaultuserid;
        lv_standarddeliveryamntdtlsrec.timestamp               := sysdate;
        select seq_stddeliveryamntdetails.nextval
        into   lv_standarddeliveryamntdtlsrec.standarddeliveryamntdetails_id
        from   dual;
        gv_message := 'insert into standarddeliveryamntdetails';
        insert into standarddeliveryamntdetails values lv_standarddeliveryamntdtlsrec;
      exception
        when dup_val_on_index then
          null;
      end;
    end loop; --xh
    --duplicate for temporary stop tables
    copy_child_records(fp_standarddeliverylinerec.standarddeliveryline_id,
                       lv_newstandarddeliverylinerec.standarddeliveryline_id);
    --count standarddeliveryamount lines
    select count(1)
    into   lv_countstdamountlines
    from   standarddeliveryamount sta
    where  sta.standarddeliveryline_id = fp_standarddeliverylinerec.standarddeliveryline_id;
    if lv_countstdamountlines > 1 then
      begin
        if (fp_standarddeliverylinerec.deliveryscheme_id <> fp_new_deliveryschemeid) then
          begin
            --new std del line needed for old del scheme
            select seq_standarddeliveryline.nextval
            into   lv_newstandarddeliverylinerec.standarddeliveryline_id
            from   dual;
            --then create a new std del line, for the old del scheme's
            lv_newstandarddeliverylinerec.deliveryscheme_id := fp_standarddeliverylinerec.deliveryscheme_id; --old del scheme
            --write record, for old delivery scheme
            gv_message := 'write record, for old delivery scheme';
            insert into standarddeliveryline values lv_newstandarddeliverylinerec;
            create_cpltransition(fp_standarddeliverylinerec.standarddeliveryline_id,
                                 lv_newstandarddeliverylinerec.standarddeliveryline_id);
            begin
              insert into customerdeliveryscheme
                (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp, active)
              values
                (fp_routechangetransactionrec.customer_id,
                 lv_newstandarddeliverylinerec.deliveryscheme_id, fp_newdrivingday, gv_defaultuserid,
                 sysdate, 'Y');
            exception
              when dup_val_on_index then
                null;
            end;
          end;
        end if;
        --Now only copy for the other days then the new driving day!
        for xf in (select *
                   from   standarddeliveryamount sa
                   where  sa.standarddeliveryline_id =
                          fp_standarddeliverylinerec.standarddeliveryline_id
                   and    sa.day_id <> fp_drivingday) loop
          begin
            --standarddeliveryamount
            lv_standarddeliveryamountrec                         := xf;
            lv_standarddeliveryamountrec.standarddeliveryline_id := lv_newstandarddeliverylinerec.standarddeliveryline_id;
            lv_standarddeliveryamountrec.systemuser_id           := gv_defaultuserid;
            lv_standarddeliveryamountrec.timestamp               := sysdate;
            gv_message                                           := 'insert into standarddeliveryamount, for other days';
            insert into standarddeliveryamount values lv_standarddeliveryamountrec;
          exception
            when dup_val_on_index then
              if (xf.standarddeliveryline_id != lv_newstandarddeliverylinerec.standarddeliveryline_id
                or xf.day_id != fp_newdrivingday) then
                gv_message := 'update standarddeliveryamount';
                update standarddeliveryamount sa
                set    sa.amount = sa.amount + xf.amount,
                       sa.systemuser_id = gv_defaultuserid,
                       sa.timestamp = sysdate
                where  sa.standarddeliveryline_id = lv_newstandarddeliverylinerec.standarddeliveryline_id
                and    sa.day_id = xf.day_id;
              end if;
          end;
        end loop; --xf
        for xh in (select *
                   from   standarddeliveryamntdetails sda
                   where  sda.standarddeliveryline_id = fp_standarddeliverylinerec.standarddeliveryline_id
                   and    sda.day_id <> fp_drivingday) loop
          begin
            lv_standarddeliveryamntdtlsrec                         := xh;
            lv_standarddeliveryamntdtlsrec.standarddeliveryline_id := lv_newstandarddeliverylinerec.standarddeliveryline_id;
            lv_standarddeliveryamntdtlsrec.systemuser_id           := gv_defaultuserid;
            lv_standarddeliveryamntdtlsrec.timestamp               := sysdate;
            select seq_stddeliveryamntdetails.nextval
            into   lv_standarddeliveryamntdtlsrec.standarddeliveryamntdetails_id
            from   dual;
            gv_message := 'insert into standarddeliveryamntdetails, for other days';
            insert into standarddeliveryamntdetails values lv_standarddeliveryamntdtlsrec;
          end;
        end loop; --xh
      end;
    end if;
    --stop original standarddeliveryline
    update standarddeliveryline sl
    set    sl.dateinactive = fp_changedate - 1,
           sl.renewal = 'N',
				 /*sl.renewalstartdate = null, sl.renewalenddate = null,*/
    			 sl.systemuser_id = gv_defaultuserid,
           sl.timestamp = sysdate
    where  sl.standarddeliveryline_id = fp_standarddeliverylinerec.standarddeliveryline_id;
    ---Always update renewal
    update standarddeliveryline sta
    set    sta.renewalstddeliveryline_id = nvl((select max(cplt.newstandarddeliveryline_id)
                                                from   cpltransition cplt
                                                where  cplt.oldstandarddeliveryline_id = sta.renewalstddeliveryline_id),
                                                       sta.renewalstddeliveryline_id),
           sta.systemuser_id = gv_defaultuserid,
           sta.timestamp = sysdate
    where  sta.renewalstddeliveryline_id = fp_standarddeliverylinerec.standarddeliveryline_id;
    --delete wrong records
    delete from standarddeliveryline stl
    where  stl.standarddeliveryline_id = fp_standarddeliverylinerec.standarddeliveryline_id
    and    stl.dateactive > stl.dateinactive;
  exception
    when ge_general then
      null;
  end insert_standarddeliveryline;

  procedure copy_standarddeliverylines(fp_routechangetransactionrec in routechangetransaction%rowtype,
                                       fp_olddeliveryschemeid       deliveryscheme.deliveryscheme_id%type) is
    lv_intervalcheckmoveroute number;
    lv_sdl_start_date         date; ---start date for the new standard delivery line
  begin
    --determine interval, the minimum interval for the routestop
    select (nvl(min(ds.frequency), 1) * 7)
    into   lv_intervalcheckmoveroute
    from   deliveryschemesperstop dsp
    join   deliveryscheme ds
    on     ds.deliveryscheme_id = dsp.deliveryscheme_id
    where  dsp.routestop_id = fp_routechangetransactionrec.routestop_id;
    --determine new start date
    lv_sdl_start_date := fp_routechangetransactionrec.oldroutelastdrivingdate + lv_intervalcheckmoveroute;
    if lv_sdl_start_date > fp_routechangetransactionrec.changestartdate then
      lv_sdl_start_date := fp_routechangetransactionrec.changestartdate;
    end if;
    --copy_standarddeliverylines
    gv_message := 'copy_standarddeliverylines';
    if (fp_routechangetransactionrec.drivingday_id <> fp_routechangetransactionrec.newdrivingday_id) or
       (nvl(fp_routechangetransactionrec.deliveryscheme_id, fp_olddeliveryschemeid) <>
       nvl(fp_routechangetransactionrec.newdeliveryscheme_id, fp_olddeliveryschemeid)) then
      begin
        for xg in (select sl.*
                   from   standarddelivery std, standarddeliveryline sl, distributionpoint dp,
                          department t, productlistperdistribpoint plpd, product p, customer c
                   where  std.standarddelivery_id = sl.standarddelivery_id
                   and    std.distributionpoint_id = dp.distributionpoint_id
                   and    dp.department_id = t.department_id
                   and    t.customer_id = fp_routechangetransactionrec.customer_id
                   and    (dp.deliverypoint_id = fp_routechangetransactionrec.deliverypoint_id or
                         fp_routechangetransactionrec.deliverypoint_id is null)
                   and    (sl.dateinactive is null or fp_routechangetransactionrec.changestartdate < case
                           when (sl.renewalstddeliveryline_id is null and sl.renewal = 'Y') then
                            nvl(sl.renewalenddate, sl.dateinactive)
                           else
                            sl.dateinactive
                         end)
                   and    sl.deliveryscheme_id =
                          nvl(fp_routechangetransactionrec.deliveryscheme_id, fp_olddeliveryschemeid) ---select only with right delscheme
                   and    plpd.productlistperdistribpoint_id = sl.productlistperdistribpoint_id
                   and    plpd.product_id = p.product_id
                   and    sl.dateactive <= sl.dateinactive
                   and    (p.productgroup_id = fp_routechangetransactionrec.productgroup_id or
                         fp_routechangetransactionrec.productgroup_id is null)
                   and    t.customer_id = c.customer_id
                   and    not (c.allocationmethod > 0 and t.bulkdeliveriesdept = 'N' and
                          t.excludefrombulkdelivery = 'N')
                   and    exists
                    (select 1
                           from   standarddeliveryamount sa
                           where  sa.standarddeliveryline_id = sl.standarddeliveryline_id
                           and    sa.day_id = fp_routechangetransactionrec.drivingday_id)
                   order  by sl.dateactive desc, sl.standarddeliveryline_id asc /*process the new lines first*/
                   ) loop
          begin
            gv_message := 'copy_standarddeliverylines';
            --copy the standarddelivery line
            insert_standarddeliveryline(xg,
                              fp_routechangetransactionrec.drivingday_id,
                                        fp_routechangetransactionrec.newdrivingday_id,
                                        lv_sdl_start_date,
                              nvl(fp_routechangetransactionrec.newdeliveryscheme_id,fp_olddeliveryschemeid),
                              fp_routechangetransactionrec);
          end;
        end loop; --xg
      end;
    end if;
  end copy_standarddeliverylines;

  procedure update_return_routes(fp_customer_id     in customer.customer_id%type,
                                 fp_routstopenddate routestop.dateinactive%type,
                                 fp_routeid         in route.route_id%type,
                                 fp_routenumber     in route.routenumber%type) is
    lv_rec_newroutestop routestop%rowtype;
  begin
    --update_return_routes
    gv_message := 'update_return_routes for customer id ' || fp_customer_id ||
                  ' routestop end date ' || to_char(fp_routstopenddate, 'DD-MM-YYYY') ||
                  ' route id ' || fp_routeid;
    for x in (select rs.*
              from   routestop rs
              where  rs.customer_id = fp_customer_id
              and    rs.returnroute_id = fp_routeid
              and    rs.dateinactive > fp_routstopenddate
              and    rs.route_id <> fp_routeid) loop
      begin
        if x.dateactive < fp_routstopenddate then
          begin
            --create new routestop for future with self reference route as return route
            lv_rec_newroutestop := x;
            select seq_routestop.nextval into lv_rec_newroutestop.routestop_id from dual;
            lv_rec_newroutestop.dateactive     := fp_routstopenddate;
            lv_rec_newroutestop.returnroute_id := x.route_id;
            insert into routestop values lv_rec_newroutestop;
            --also replicate for the new routestop_id the old routestop_id referenced rows in deliveryschemesperstop table
            for y in (select deliveryscheme_id, day_id
                      from   deliveryschemesperstop
                      where  routestop_id = x.routestop_id
                      and    customer_id = x.customer_id) loop
              insert into deliveryschemesperstop
                (routestop_id, deliveryscheme_id, day_id, customer_id, systemuser_id, timestamp)
              values
                (lv_rec_newroutestop.routestop_id, y.deliveryscheme_id, y.day_id, x.customer_id,
                 gv_defaultuserid, sysdate);
            end loop; --y
            --link the future stops to the new routestop
            update stop s
            set    routestop_id = lv_rec_newroutestop.routestop_id,
                   s.systemuser_id = gv_defaultuserid,
                   s.timestamp = sysdate
            where  routestop_id = x.routestop_id
            and    exists (select 1
                    from   routecontrol
                    where  routecontrol_id = s.routecontrol_id
                    and    drivingdate >= fp_routstopenddate);
            --enddate the old routestop
            update routestop rs
            set    rs.dateinactive = fp_routstopenddate,
                   rs.systemuser_id = gv_defaultuserid,
                   rs.timestamp = sysdate
            where  rs.routestop_id = x.routestop_id;
          end;
        else
          begin
            update routestop rs
            set    rs.returnroute_id = rs.route_id, --self referring
                   rs.systemuser_id = gv_defaultuserid,
                   rs.timestamp = sysdate
            where  rs.routestop_id = x.routestop_id;
          end;
        end if;
        write_log('Changed the return route from route / stop ' || fp_routenumber || ' / ' ||
                  x.stopnumber, 1);
      end;
    end loop; --x
  end update_return_routes;

  procedure new_route(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_routerec route%rowtype;
  begin
    --new_route
    gv_message := 'new_route';
    if is_plant_active(fp_routechangetransactionrec.plant_id) = false then
      raise ge_wrongvalue;
    end if;
    --init route record
    init_route(lv_routerec);
    --fill other values
    lv_routerec.plant_id      := fp_routechangetransactionrec.plant_id;
    lv_routerec.routenumber   := fp_routechangetransactionrec.newroutenumber;
    lv_routerec.description   := fp_routechangetransactionrec.newroutenumber;
    lv_routerec.drivingday_id := fp_routechangetransactionrec.newdrivingday_id;
    lv_routerec.depot_id      := get_depot_id(fp_routechangetransactionrec.depotcode,
                                              fp_routechangetransactionrec.plant_id);
    if fp_routechangetransactionrec.deliveryscheme_id is null then
      lv_routerec.deliveryscheme_id := get_max_deliveryschemeid;
    else
      lv_routerec.deliveryscheme_id := fp_routechangetransactionrec.deliveryscheme_id;
    end if;
    lv_routerec.district_id := get_district_id(fp_routechangetransactionrec.plant_id);
    --insert route
    gv_message := 'new_route insert route';
    insert into route values lv_routerec;
  exception
    when dup_val_on_index then
      gv_message := 'Route already exists';
      raise;
  end new_route;

  procedure change_depot(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_depotid depot.depot_id%type;
  begin
    --change_depot
    gv_message := 'change_depot';
    if is_plant_active(fp_routechangetransactionrec.plant_id) = false then
      raise ge_wrongvalue;
    end if;
    --get depot
    lv_depotid := get_depot_id(fp_routechangetransactionrec.depotcode,
                               fp_routechangetransactionrec.plant_id);
    --update depot for route
    update route r
    set    r.depot_id = lv_depotid, r.timestamp = sysdate, r.systemuser_id = gv_defaultuserid
    where  r.route_id = fp_routechangetransactionrec.route_id;
  end change_depot;

  procedure new_stop(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_routeid               route.route_id%type;
    lv_routedeliveryschemeid route.deliveryscheme_id%type;
    lv_routestoprec          routestop%rowtype;
  begin
    --new_stop
    gv_message := 'new_stop';
    if is_plant_active(fp_routechangetransactionrec.plant_id) = false then
      raise ge_wrongvalue;
    end if;
    --check route id
    lv_routeid := get_route_id(fp_routechangetransactionrec.routenumber,
                               fp_routechangetransactionrec.drivingday_id,
                               fp_routechangetransactionrec.plant_id);
    --check deliverypoint active
    check_deliverypoint_active(fp_routechangetransactionrec.deliverypoint_id);
    --check customer bu
    check_customer_bu(fp_routechangetransactionrec.customer_id,
                      fp_routechangetransactionrec.plant_id);
    --check delivery scheme's
    check_deliveryschemes(fp_routechangetransactionrec.newdeliveryscheme_id, lv_routeid,
                          lv_routedeliveryschemeid);
    --init routestop
    init_routestop(lv_routestoprec);
    --check customer
    lv_routestoprec.dateinactive := check_customer_active(fp_routechangetransactionrec.customer_id);
    --fill other values
    lv_routestoprec.route_id         := lv_routeid;
    lv_routestoprec.returnroute_id   := lv_routeid;
    lv_routestoprec.stopnumber       := get_new_stopnumber(lv_routeid,
                                                           fp_routechangetransactionrec.newstopnumber,
                                                           fp_routechangetransactionrec.changestartdate,
                                                           fp_routechangetransactionrec.routenumber);
    lv_routestoprec.customer_id      := fp_routechangetransactionrec.customer_id;
    lv_routestoprec.deliverypoint_id := fp_routechangetransactionrec.deliverypoint_id;
    lv_routestoprec.dateactive       := fp_routechangetransactionrec.changestartdate;
    lv_routestoprec.sortsequence     := nvl(fp_routechangetransactionrec.sortsequence,0);
    --add customer deliveryscheme
    add_customer_delscheme_days(fp_routechangetransactionrec.customer_id,
                                nvl(fp_routechangetransactionrec.newdeliveryscheme_id,
                                     lv_routedeliveryschemeid),
                                fp_routechangetransactionrec.drivingday_id);
    --insert routestop
    gv_message := 'new_stop insert routestop';
    insert into routestop values lv_routestoprec;
    --insert into deliveryschemeperstop
    gv_message := 'new_stop insert deliveryschemesperstop';
    --try to add, if it already exists no problem
    begin
      insert into customerdeliveryscheme
        (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
      values
        (lv_routestoprec.customer_id,
         nvl(fp_routechangetransactionrec.newdeliveryscheme_id, lv_routedeliveryschemeid),
         fp_routechangetransactionrec.drivingday_id, gv_defaultuserid, sysdate);
    exception
      when dup_val_on_index then
        update customerdeliveryscheme ds
        set    ds.active = 'Y'
        where  ds.active <> 'Y'
        and    ds.customer_id = lv_routestoprec.customer_id
        and    ds.deliveryscheme_id =
               nvl(fp_routechangetransactionrec.newdeliveryscheme_id, lv_routedeliveryschemeid)
        and    ds.day_id = fp_routechangetransactionrec.drivingday_id;
    end;
    insert into deliveryschemesperstop
      (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
    values
      (lv_routestoprec.routestop_id, lv_routestoprec.customer_id,
       nvl(fp_routechangetransactionrec.newdeliveryscheme_id, lv_routedeliveryschemeid),
       fp_routechangetransactionrec.drivingday_id, gv_defaultuserid, sysdate);
    --add stop to routecontrol
    add_stop_to_routecontrol(lv_routestoprec.route_id, lv_routestoprec.stopnumber,
                             lv_routestoprec.routestop_id, lv_routestoprec.customer_id,
                             fp_routechangetransactionrec.changestartdate, 'N', null, null, null,
                             fp_routechangetransactionrec.deliverypoint_id); --no cancel so other parameters can be null
  exception
    when dup_val_on_index then
      gv_message := 'Stop already exists';
      raise;
  end new_stop;

  procedure remove_stopnumber(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_routeid         route.route_id%type;
    lv_routestopid     routestop.routestop_id%type;
    lv_routstopenddate routestop.dateinactive%type;
  begin
    --remove_stopnumber
    gv_message := 'remove_stopnumber';
    if is_plant_active(fp_routechangetransactionrec.plant_id) = false then
      raise ge_wrongvalue;
    end if;
    --get new lv_routstopenddate
    if fp_routechangetransactionrec.oldroutelastdrivingdate is null then
      begin
        lv_routstopenddate := fp_routechangetransactionrec.changestartdate;
      end;
    else
      begin
        lv_routstopenddate := fp_routechangetransactionrec.oldroutelastdrivingdate + 1;
      end;
    end if;
    --check route id
    lv_routeid := get_route_id(fp_routechangetransactionrec.routenumber,
                               fp_routechangetransactionrec.drivingday_id,
                               fp_routechangetransactionrec.plant_id);
    --get routestop id
    lv_routestopid := get_routestopid(lv_routeid, fp_routechangetransactionrec.customer_id,
                                      fp_routechangetransactionrec.deliverypoint_id,
                                      fp_routechangetransactionrec.stopnumber,
                                      fp_routechangetransactionrec.changestartdate);
    --Step 1: Inactivate routestop
    update routestop rs
    set    rs.dateinactive = lv_routstopenddate, rs.systemuser_id = gv_defaultuserid,
           rs.timestamp = sysdate
    where  rs.routestop_id = lv_routestopid;
    --Step 2: Cancel stops from route status control
    inactivate_stop_routcontrol(lv_routeid, lv_routestopid, lv_routstopenddate);
    --Step 3: Put end date to standard deliveries
    putenddate2standarddeliveries(fp_routechangetransactionrec.customer_id,
                                  fp_routechangetransactionrec.deliverypoint_id,
                                  fp_routechangetransactionrec.drivingday_id, lv_routstopenddate);
    --Step 4: Update stops that have the route of the ended stop as return route
    update_return_routes(fp_routechangetransactionrec.customer_id, lv_routstopenddate, lv_routeid,
                         fp_routechangetransactionrec.routenumber);
  end remove_stopnumber;

  procedure change_stopnumber(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_routeid               route.route_id%type;
    lv_routestopid           routestop.routestop_id%type;
    lv_newroutestoprec       routestop%rowtype;
    lv_routstopenddate       routestop.dateinactive%type;
    lv_routedeliveryschemeid deliveryscheme.deliveryscheme_id%type;
    lv_changestartdate       date;
    lv_is_movestopmoveup		 boolean := false;
  begin
    --change_stopnumber
    gv_message := 'change_stopnumber';
		write_log('Calling Pack_Routetransaction.CHANGE_STOPNUMBER...');

    --this change_stopnumber is used when movestopmoveup
    if (gv_ss_movestopmoveup = 1 and
      	fp_routechangetransactionrec.newdrivingday_id is null and
      	fp_routechangetransactionrec.newroute_id is null and
        fp_routechangetransactionrec.newdeliveryscheme_id is null)
    then
      lv_is_movestopmoveup := true;
    end if;

    if is_plant_active(fp_routechangetransactionrec.plant_id) = false then
      raise ge_wrongvalue;
    end if;
    if gv_ss_directstopchange = 1 then
      lv_changestartdate := trunc(sysdate);
    else
      lv_changestartdate := fp_routechangetransactionrec.changestartdate;
    end if;
    --get new lv_routstopenddate
    if fp_routechangetransactionrec.oldroutelastdrivingdate is null then
      begin
        lv_routstopenddate := lv_changestartdate;
      end;
    else
      begin
        lv_routstopenddate := fp_routechangetransactionrec.oldroutelastdrivingdate + 1;
      end;
    end if;

    --check route id
    lv_routeid := get_route_id(fp_routechangetransactionrec.routenumber,
                               fp_routechangetransactionrec.drivingday_id,
                               fp_routechangetransactionrec.plant_id);
    --get routestop id
    lv_routestopid := get_routestopid(lv_routeid, fp_routechangetransactionrec.customer_id,
                                      fp_routechangetransactionrec.deliverypoint_id,
                                      fp_routechangetransactionrec.stopnumber,
                                      fp_routechangetransactionrec.changestartdate,
                                      case
                                         when length(fp_routechangetransactionrec.routenumber) = 5 and
                                              gv_databasecode = 'LST' then
                                          99
                                         else
                                          5
                                       end); --copy old into new routestop

    if ((length(fp_routechangetransactionrec.routenumber) = 5 and gv_databasecode = 'LST') or
       gv_ss_directstopchange = 1) then
      --not change any dates, just update the stopnumber request 16-01-2015
      update routestop rs
      set    rs.stopnumber = fp_routechangetransactionrec.newstopnumber,
      			 rs.movedroutestop_id = null,
             rs.systemuser_id = gv_defaultuserid, rs.timestamp = sysdate
      where  rs.routestop_id = lv_routestopid;
      --copy new route data into record
      select * into lv_newroutestoprec from routestop rs where rs.routestop_id = lv_routestopid;
    else
      begin
        --copy old into new routestop
        select * into lv_newroutestoprec from routestop rs where rs.routestop_id = lv_routestopid;
        begin
          --check if new stop number already exists in route for date
          if check_dup_stop_route(lv_routeid, fp_routechangetransactionrec.newstopnumber,
                                  fp_routechangetransactionrec.changestartdate) and gv_stopnrunique = 0
          then
            write_log('Stopnumber ' || to_char(fp_routechangetransactionrec.newstopnumber) || ' already used for route ' ||
                      to_char(fp_routechangetransactionrec.routenumber), 2);
          end if;
        exception
          when no_data_found then
            null;
        end;
        ---Step 1: Create new routestop
        if (not lv_is_movestopmoveup) then
	        select seq_routestop.nextval into lv_newroutestoprec.routestop_id from dual;
        else
          --when have movestopmoveup then uses same routestopid
          lv_newroutestoprec.routestop_id := lv_routestopid;
        end if;
        lv_newroutestoprec.stopnumber    := fp_routechangetransactionrec.newstopnumber;
        lv_newroutestoprec.dateactive    := fp_routechangetransactionrec.changestartdate;
        if lv_newroutestoprec.dateactive > lv_newroutestoprec.dateinactive then
          lv_newroutestoprec.dateinactive := to_date('31-12-2099', 'dd-mm-yyyy');
        end if;
        lv_newroutestoprec.systemuser_id := gv_defaultuserid;
        lv_newroutestoprec.timestamp     := sysdate;
        lv_newroutestoprec.sortsequence  := nvl(fp_routechangetransactionrec.sortsequence,0);
        if (not lv_is_movestopmoveup) then
          gv_message := 'change_stopnumber insert routestop';
          insert into routestop values lv_newroutestoprec;
				end if;

        --Step 2: Put end date to previous routestop
        if (not lv_is_movestopmoveup) then
        	gv_message := 'change_stopnumber update routestop';
        	update routestop rs
        	set    rs.dateinactive = case
                                     when lv_routstopenddate < rs.dateinactive then
                                      lv_routstopenddate
                                     else
                                      rs.dateinactive
                                   end,
                 rs.movedroutestop_id = lv_newroutestoprec.routestop_id,
                 rs.systemuser_id = gv_defaultuserid,
                 rs.timestamp = sysdate
          where  rs.routestop_id = lv_routestopid;
				end if;

        -- Extra Step replacing Step#1 and Step#2 when have movestopmoveup
        if (lv_is_movestopmoveup) then
          gv_message := 'change_stopnumber update routestop (when movestopmoveup)';
          update routestop rs
          set    rs.stopnumber = lv_newroutestoprec.stopnumber,
                 rs.systemuser_id = gv_defaultuserid,
                 rs.timestamp = sysdate
          where  rs.routestop_id = lv_routestopid;
        end if;

        --Step 3a: Update stopnumber in route status control
        gv_message := 'change_stopnumber update stop';
        update stop st
        set    st.stopnumber = lv_newroutestoprec.stopnumber,
               st.routestop_id = lv_newroutestoprec.routestop_id,
               st.systemuser_id = gv_defaultuserid,
               st.timestamp = sysdate
        where  st.routestop_id = lv_routestopid
        and    st.customer_link_id = fp_routechangetransactionrec.customer_id
        and    exists (select 1
                from   routecontrol rc
                where  rc.routecontrol_id = st.routecontrol_id
                and    rc.route_id = lv_routeid
                and    rc.pocketpcstatus = 0
                and    rc.drivingdate >= fp_routechangetransactionrec.changestartdate
                and    rc.routelistprinted = 'N');
        --Step 3b update all packingnotes with new stopnumber
        gv_message := 'change_stopnumber update packingnote';
        update packingnote pk
        set    pk.stopnumber = lv_newroutestoprec.stopnumber,
               pk.systemuser_id = gv_defaultuserid,
               pk.timestamp = sysdate
        where  pk.stop_id in
               (select st.stop_id
                from   stop st
                where  st.routestop_id = lv_newroutestoprec.routestop_id
                and    st.stopnumber = lv_newroutestoprec.stopnumber
                and    st.customer_link_id = fp_routechangetransactionrec.customer_id);
        --Step 3c update all client delivery notes with new stopnumber
        gv_message := 'change_stopnumber update clientdeliverynote';
        update clientdeliverynote cdn
        set    cdn.stopnumber = lv_newroutestoprec.stopnumber,
               cdn.systemuser_id = gv_defaultuserid,
               cdn.timestamp = sysdate
        where  cdn.stop_id in
               (select st.stop_id
                from   stop st
                where  st.routestop_id = lv_newroutestoprec.routestop_id
                and    st.stopnumber = lv_newroutestoprec.stopnumber
                and    st.customer_link_id = fp_routechangetransactionrec.customer_id);

        --Step 4: Update StopNumber in future RouteStops for the same route and Customer
        gv_message := 'change_stopnumber update stopnumber in future routestops for same route/customer';
        update routestop rs
        set    rs.stopnumber = fp_routechangetransactionrec.newstopnumber,
               rs.systemuser_id = gv_defaultuserid,
               rs.timestamp = sysdate
        where  rs.route_id = lv_routeid
        and    (rs.stopnumber = fp_routechangetransactionrec.stopnumber or rs.stopnumber = 0)
        and    rs.customer_id = fp_routechangetransactionrec.customer_id
        and    rs.deliverypoint_id = fp_routechangetransactionrec.deliverypoint_id
        and    rs.dateactive >= fp_routechangetransactionrec.changestartdate;

        --insert into deliveryschemeperstop
        if (not lv_is_movestopmoveup) then
          for wbo in (select dss.deliveryscheme_id, dss.day_id
                      from   deliveryschemesperstop dss
                      where  dss.routestop_id = lv_routestopid
                      and    dss.customer_id = lv_newroutestoprec.customer_id) loop
            begin
              --try to add, if it already exists no problem
              begin
                insert into customerdeliveryscheme
                  (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
                values
                  (lv_newroutestoprec.customer_id,
                   nvl(wbo.deliveryscheme_id, lv_routedeliveryschemeid), wbo.day_id, gv_defaultuserid,
                   sysdate);
              exception
                when dup_val_on_index then
                  update customerdeliveryscheme ds
                  set    ds.active = 'Y',
                         ds.systemuser_id = gv_defaultuserid,
                         ds.timestamp = sysdate
                  where  ds.active <> 'Y'
                  and    ds.customer_id = lv_newroutestoprec.customer_id
                  and    ds.deliveryscheme_id = nvl(wbo.deliveryscheme_id, lv_routedeliveryschemeid)
                  and    ds.day_id = wbo.day_id;
              end;
              gv_message := 'new_stop insert deliveryschemesperstop';
              insert into deliveryschemesperstop
                (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
              values
                (lv_newroutestoprec.routestop_id, lv_newroutestoprec.customer_id,
                 nvl(wbo.deliveryscheme_id, lv_routedeliveryschemeid), wbo.day_id, gv_defaultuserid,
                 sysdate);
            exception
              when dup_val_on_index then
                null;
            end;
          end loop;
        end if;
      end;
    end if;
    write_log('Return from Pack_Routetransaction.CHANGE_STOPNUMBER.');
  end change_stopnumber;

  procedure move_stop(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_routeid               route.route_id%type;
    lv_routestopid           routestop.routestop_id%type;
    lv_routedeliveryschemeid deliveryscheme.deliveryscheme_id%type;
    lv_newrouteid            route.route_id%type;
    lv_newroutestoprec       routestop%rowtype;
    lv_removestop            varchar2(1) := 'N';
    lv_routstopenddate       routestop.dateinactive%type;

    procedure end_previous_stop(fp_removestop                in out varchar2,
                                fp_routechangetransactionrec in routechangetransaction%rowtype,
                                fp_routeid                   in route.route_id%type,
                                fp_routestopid               in routestop.routestop_id%type,
                                fp_newrouteid                in route.route_id%type,
                                fp_newroutestopid            in routestop.routestop_id%type) is
    begin
      --step 4 end previous stop
      --end_previous_stop
      gv_message := 'end_previous_stop';
      if (fp_routechangetransactionrec.productgroup_id is null) then
        begin
          update routestop rs
          set    rs.dateinactive = case
                                     when rs.dateactive > fp_routechangetransactionrec.changestartdate then
                                      rs.dateactive + 1
                                     else
                                      fp_routechangetransactionrec.changestartdate
                                   end,
                 rs.systemuser_id = gv_defaultuserid,
                 rs.timestamp = sysdate,
                 rs.movedroutestop_id = fp_newroutestopid
          where  rs.routestop_id = fp_routestopid;
          --stop ended
          fp_removestop := 'Y';
          --update also all workorders
          update workorder wo
          set    wo.route_id = fp_newrouteid,
                 wo.systemuser_id = gv_defaultuserid,
                 wo.timestamp = sysdate
          where  wo.route_id = fp_routeid
          and    wo.neededdate >= lv_routstopenddate
          and    wo.status_id in (select st.status_id
                                  from   status st
                                  where  st.statustype = 'WO'
                                  and    st.code in ('05', '10', '15', '20', '25'))
          and    wo.customer_link_id = fp_routechangetransactionrec.customer_id;
        end;
      end if;
    end end_previous_stop;

    procedure update_routecontrol(fp_removestop     in varchar2,
                                  fp_customerid     in customer.customer_id%type,
                                  fp_routeid        in route.route_id%type,
                                  fp_routestopid    in routestop.routestop_id%type,
                                  fp_oldstopnumber  in stop.stopnumber%type,
                                  fp_newroutestopid in routestop.routestop_id%type,
                                  fp_newstopnumber  in stop.stopnumber%type) is
    begin
      --step 5 update routestatus control
      --update_routecontrol
      gv_message := 'update_routecontrol';
      if fp_removestop = 'Y' then
        begin
          --add new stop + cancel old stop
          add_stop_to_routecontrol(fp_routeid, fp_newstopnumber, fp_newroutestopid, fp_customerid,
                                   fp_routechangetransactionrec.changestartdate, 'Y', fp_routestopid,
                                   fp_oldstopnumber, lv_routstopenddate,
                                   fp_routechangetransactionrec.deliverypoint_id);
        end;
      else
        begin
          --only add new stop
          add_stop_to_routecontrol(fp_routeid, fp_newstopnumber, fp_newroutestopid, fp_customerid,
                                   lv_routstopenddate, 'N', null, null, null,
                                   fp_routechangetransactionrec.deliverypoint_id); --no cancel so other parameters can be null
        end;
      end if; --fp_removestop = 'Y'
    end update_routecontrol;

    procedure cleanupdays_movestop is
      lv_counter number := 0;
    begin
      --cleanupdays_movestop
      gv_message := 'cleanupdays_movestop';
      if fp_routechangetransactionrec.drivingday_id <>
         fp_routechangetransactionrec.newdrivingday_id then
        begin
          --customer works with route-stops, so ALL days should have route-stops!!
          --EMG: so we can delete days for which there is NO route-stop!
          select count(1)
          into   lv_counter
          from   routestop rs
          join   route r
          on     r.route_id = rs.route_id
          where  r.drivingday_id = fp_routechangetransactionrec.drivingday_id
          and    rs.customer_id = fp_routechangetransactionrec.customer_id;
          if lv_counter = 0 then
            begin
              --delete customer days in related tables see condition above why
              gv_message := 'cleanupdays_movestop delete from customerdeliveryday';
              delete from customerdeliveryday cdd
              where  cdd.day_id = fp_routechangetransactionrec.drivingday_id
              and    cdd.customer_id = fp_routechangetransactionrec.customer_id;
              gv_message := 'cleanupdays_movestop delete from productdeliveryday';
              delete from productdeliveryday pdd
              where  pdd.day_id = fp_routechangetransactionrec.drivingday_id
              and    pdd.productlistpercustomer_id in
                     (select l.productlistpercustomer_id
                       from   productlistpercustomer l
                       where  l.customer_id = fp_routechangetransactionrec.customer_id);
              gv_message := 'cleanupdays_movestop delete from customerdeliveryscheme';
              delete from customerdeliveryscheme cds
              where  cds.day_id = fp_routechangetransactionrec.drivingday_id
              and    cds.customer_id = fp_routechangetransactionrec.customer_id;
            end;
          end if;
        end;
      end if;
    end cleanupdays_movestop;

    procedure update_batchjobcontents(fp_drivingday_id    in route.drivingday_id%type,
                                      fp_newdrivingday_id in route.drivingday_id%type,
                                      fp_deliverypoint_id in deliverypoint.deliverypoint_id%type,
                                      fp_changestartdate  in batchjobcontent.planneddeliverydate%type,
                                      fp_plant_id         in plant.plant_id%type,
                                      fp_customer_id      in customer.customer_id%type) is
      m_diff number := 0;
    begin
      if (fp_drivingday_id <> fp_newdrivingday_id) then
        m_diff := fp_newdrivingday_id - fp_drivingday_id;
        update batchjobcontent bc
        set    bc.planneddeliverydate = bc.planneddeliverydate + m_diff,
        		   bc.timestamp = sysdate,
               bc.systemuser_id = gv_defaultuserid
        where  bc.status = 1
        and    exists (select 1
                from   batchjob b
                where  b.batchjob_id = bc.batchjob_id
                and    b.plant_id = fp_plant_id
                and    b.status = 1)
        and    exists (select 1
                from   department d, distributionpoint dp
                where  d.department_id = bc.department_link_id
                and    d.customer_id = fp_customer_id
                and    dp.department_id = d.department_id
                and    ((dp.deliverypoint_id = fp_deliverypoint_id) or
                      (fp_deliverypoint_id is null)))
        and    bc.planneddeliverydate >= fp_changestartdate;
      end if;
    end update_batchjobcontents;

  begin
    --move_stop step 1
    gv_message := 'move_stop';
    write_log('Calling Pack_Routetransaction.MOVE_STOP...');

    if is_plant_active(fp_routechangetransactionrec.plant_id) = false then
      raise ge_wrongvalue;
    end if;
    --get new lv_routstopenddate
    if fp_routechangetransactionrec.oldroutelastdrivingdate is null then
      begin
        lv_routstopenddate := fp_routechangetransactionrec.changestartdate;
      end;
    else
      begin
        lv_routstopenddate := fp_routechangetransactionrec.oldroutelastdrivingdate + 1;
      end;
    end if;
    --check route id
    lv_routeid := get_route_id(fp_routechangetransactionrec.routenumber,
                               fp_routechangetransactionrec.drivingday_id,
                               fp_routechangetransactionrec.plant_id);
    --get routestop id
    lv_routestopid := get_routestopid(lv_routeid, fp_routechangetransactionrec.customer_id,
                                      fp_routechangetransactionrec.deliverypoint_id,
                                      fp_routechangetransactionrec.stopnumber,
                                      fp_routechangetransactionrec.changestartdate, 6);
    --init routestop->copy old routestop into new routestop
    select * into lv_newroutestoprec from routestop rs where rs.routestop_id = lv_routestopid;
    if gv_ss_directstopchange = 0 then
      --get new routestopID
      select seq_routestop.nextval into lv_newroutestoprec.routestop_id from dual;
    end if;
    --check delivery scheme's
    check_deliveryschemes(fp_routechangetransactionrec.newdeliveryscheme_id,
                          fp_routechangetransactionrec.route_id, lv_routedeliveryschemeid);
    --check sortbatch
    check_sortbatch(lv_routestopid, fp_routechangetransactionrec.changestartdate);
    begin
      --check new route id
      lv_newrouteid := get_route_id(fp_routechangetransactionrec.newroutenumber,
                                    fp_routechangetransactionrec.newdrivingday_id,
                                    fp_routechangetransactionrec.plant_id);
    exception
      when no_data_found then
        if gv_databasecode = 'LST' then
          select seq_route.nextval into lv_newrouteid from dual;
          insert into route
            (route_id, plant_id, drivingday_id, routenumber, description, depot_id, systemuser_id,
             codeonlabel, timestamp, driver_id, truck_id, starttime, endtime, packingday_id,
             packingdeadline, loadingdock, putupreportpercustomer, putupreportperroute,
             putupreportperdepot, putupreportroutestop, printsoilticket, printorderform,
             bundletagsflatw, bundletagsgarm, active, sortbatchdefinition_id,
             commissionpayabledriver, spareroute, splitperpackingdept, deliveryscheme_id,
             printpicklistrsc, printmountingorder, printdismountingorder, printsalesnotes,
             district_id, routemanager_id, printtransportlabels)
            select lv_newrouteid, r.plant_id, fp_routechangetransactionrec.newdrivingday_id,
                   fp_routechangetransactionrec.newroutenumber,
                   to_char(fp_routechangetransactionrec.newroutenumber) /*routedesc*/, r.depot_id,
                   r.systemuser_id, r.codeonlabel, sysdate, r.driver_id, r.truck_id, r.starttime,
                   r.endtime, r.packingday_id, r.packingdeadline, r.loadingdock,
                   r.putupreportpercustomer, r.putupreportperroute, r.putupreportperdepot,
                   r.putupreportroutestop, r.printsoilticket, r.printorderform, r.bundletagsflatw,
                   r.bundletagsgarm, r.active, r.sortbatchdefinition_id, r.commissionpayabledriver,
                   r.spareroute, r.splitperpackingdept,
                   nvl(fp_routechangetransactionrec.newdeliveryscheme_id, r.deliveryscheme_id),
                   r.printpicklistrsc, r.printmountingorder, r.printdismountingorder,
                   r.printsalesnotes, r.district_id, r.routemanager_id, r.printtransportlabels
            from   route r
            where  r.route_id = lv_routeid;
        else
          raise no_data_found;
        end if;
    end;
    if gv_databasecode <> 'LST' then
      lv_newroutestoprec.dateinactive := to_date('31-12-2099', 'DD-MM-YYYY');
    end if;
    --check if routestop is used by another customer...?
    if check_dup_stop_route(lv_newrouteid, fp_routechangetransactionrec.newstopnumber,
                            fp_routechangetransactionrec.changestartdate) and gv_stopnrunique = 0 then
      begin
        --stop already found try with st
        write_log('Move stop: Stopnumber already used. Already exists routstop_id ' ||
                  lv_newroutestoprec.routestop_id, 2);
      end;
    end if;
    --always use the new stopnumber
    lv_newroutestoprec.stopnumber := fp_routechangetransactionrec.newstopnumber;
    if gv_ss_directstopchange = 1 then
      begin
        lv_newroutestoprec.route_id := lv_newrouteid;
        update routestop rs
        set    rs.route_id = lv_newrouteid,
               rs.stopnumber = fp_routechangetransactionrec.newstopnumber,
               rs.systemuser_id = gv_defaultuserid,
               rs.timestamp = sysdate,
               rs.sortsequence = fp_routechangetransactionrec.Sortsequence,
               rs.returnroute_id = case
                                     when rs.returnroute_id = rs.route_id then
                                      lv_newrouteid
                                     else
                                      rs.returnroute_id
                                   end
        where  rs.routestop_id = lv_routestopid;
      end;
    else
      begin
        --check if newroutestop stopnumber already exists for same customer
        lv_newroutestoprec.routestop_id := get_routestopid(lv_newrouteid,
                                                           fp_routechangetransactionrec.customer_id,
                                                           fp_routechangetransactionrec.deliverypoint_id,
                                                           fp_routechangetransactionrec.newstopnumber,
                                                           fp_routechangetransactionrec.changestartdate,
                                                           6);
        --new routestop already exists fill corresponding record
        gv_message := 'move_stop: new routestop already exists fill corresponding record';
        select *
        into   lv_newroutestoprec
        from   routestop rs
        where  rs.routestop_id = lv_newroutestoprec.routestop_id;
        if gv_databasecode <> 'LST' then
          --if existing routestop is not active anymore, make it active till 31-12-2099 (empty)
          if lv_newroutestoprec.dateinactive < fp_routechangetransactionrec.changestartdate then
            begin
              lv_newroutestoprec.dateinactive := to_date('31-12-2099', 'dd-mm-yyyy');
              update routestop rs
              set    rs.dateinactive = lv_newroutestoprec.dateinactive,
                     rs.systemuser_id = gv_defaultuserid,
                     rs.timestamp = sysdate
              where  rs.routestop_id = lv_newroutestoprec.routestop_id;
            end;
          end if;
          --if existing route stop is in future, make it active from the change date
          if lv_newroutestoprec.dateactive > fp_routechangetransactionrec.changestartdate then
            begin
              lv_newroutestoprec.dateactive := fp_routechangetransactionrec.changestartdate;
              update routestop rs
              set    rs.dateactive = fp_routechangetransactionrec.changestartdate,
                     rs.systemuser_id = gv_defaultuserid,
                     rs.timestamp = sysdate
              where  rs.routestop_id = lv_newroutestoprec.routestop_id;
            end;
          end if;
        end if;
      exception
        when no_data_found then
          begin
            --fill other values
            lv_newroutestoprec.route_id         := lv_newrouteid;
            lv_newroutestoprec.returnroute_id   := lv_newrouteid;
            lv_newroutestoprec.customer_id      := fp_routechangetransactionrec.customer_id;
            lv_newroutestoprec.deliverypoint_id := fp_routechangetransactionrec.deliverypoint_id;
            lv_newroutestoprec.dateactive       := fp_routechangetransactionrec.changestartdate;
            lv_newroutestoprec.timestamp        := sysdate;
            lv_newroutestoprec.systemuser_id    := gv_defaultuserid;
            lv_newroutestoprec.Sortsequence     := nvl(fp_routechangetransactionrec.Sortsequence,0);
            --insert newroutestop record
            gv_message := 'move_stop: insert routestop';
            insert into routestop values lv_newroutestoprec;
          end;
      end;
    end if;

    --step 2 add customer deliveryscheme
    add_customer_deldays_movestop(fp_routechangetransactionrec.customer_id,
                                  fp_routechangetransactionrec.newdeliveryscheme_id,
                                  fp_routechangetransactionrec.newdrivingday_id,
                                  fp_routechangetransactionrec.drivingday_id,
                                  lv_routestopid,
                                  case when gv_ss_directstopchange = 0 then
                                    fp_routechangetransactionrec.changestartdate
                                  else
                                    trunc(sysdate)
                                  end,
                                  fp_routechangetransactionrec.deliveryscheme_id,
                                  fp_routechangetransactionrec.deliverypoint_id);

    --extra step check customer deliveryscheme per stop
    --insert into deliveryschemeperstop
    if (fp_routechangetransactionrec.newdeliveryscheme_id is null and
       fp_routechangetransactionrec.deliveryscheme_id is null) then
      --option 1 copy all to new
      --try to add, if it already exists no problem
      begin
        insert into customerdeliveryscheme
          (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
          select dprs.customer_id, dprs.deliveryscheme_id,
                 fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate
          from   deliveryschemesperstop dprs
          where  dprs.routestop_id = lv_routestopid
          and    not exists (select 1
                  from   customerdeliveryscheme cdd
                  where  cdd.customer_id = dprs.customer_id
                  and    cdd.day_id = fp_routechangetransactionrec.newdrivingday_id
                  and    cdd.deliveryscheme_id = dprs.deliveryscheme_id)
          and    not exists
           (select 1
                  from   deliveryschemesperstop dprsx
                  where  dprsx.routestop_id = lv_newroutestoprec.routestop_id
                  and    dprsx.customer_id = dprs.customer_id
                  and    dprsx.deliveryscheme_id = dprs.deliveryscheme_id
                  and    dprsx.day_id = fp_routechangetransactionrec.newdrivingday_id)
          group  by dprs.customer_id, dprs.deliveryscheme_id;
      exception
        when dup_val_on_index then
          null;
      end;
      --unique index ROUTESTOP_ID, CUSTOMER_ID, DELIVERYSCHEME_ID, DAY_ID
      gv_message := 'new_stop insert deliveryschemesperstop, option 1';
      insert into deliveryschemesperstop
        (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
        select lv_newroutestoprec.routestop_id, dprs.customer_id, dprs.deliveryscheme_id,
               fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate
        from   deliveryschemesperstop dprs
        where  dprs.routestop_id = lv_routestopid
        and    not exists
         (select 1
                from   deliveryschemesperstop dprsx
                where  dprsx.routestop_id = lv_newroutestoprec.routestop_id
                and    dprsx.customer_id = dprs.customer_id
                and    dprsx.deliveryscheme_id = dprs.deliveryscheme_id
                and    dprsx.day_id = fp_routechangetransactionrec.newdrivingday_id);
    else
      if (fp_routechangetransactionrec.newdeliveryscheme_id is not null and
         fp_routechangetransactionrec.deliveryscheme_id is null) then
        --option 2
        --insert into the new delscheme deliveryschemeperstop
        begin
          --try to add, if it already exists no problem
          begin
            insert into customerdeliveryscheme
              (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
            values
              (lv_newroutestoprec.customer_id, fp_routechangetransactionrec.newdeliveryscheme_id,
               fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate);
          exception
            when dup_val_on_index then
              update customerdeliveryscheme ds
              set    ds.active = 'Y',
                     ds.systemuser_id = gv_defaultuserid,
                     ds.timestamp = sysdate
              where  ds.active <> 'Y'
              and    ds.customer_id = lv_newroutestoprec.customer_id
              and    ds.deliveryscheme_id = fp_routechangetransactionrec.newdeliveryscheme_id
              and    ds.day_id = fp_routechangetransactionrec.newdrivingday_id;
          end;
          gv_message := 'new_stop insert deliveryschemesperstop, option 2';
          begin
            gv_message := 'new_stop insert deliveryschemesperstop';
            insert into deliveryschemesperstop
              (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
            values
              (lv_newroutestoprec.routestop_id, lv_newroutestoprec.customer_id,
               fp_routechangetransactionrec.newdeliveryscheme_id,
               fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate);
          exception
            when dup_val_on_index then
              null;
          end;
        end;
      else
        if (fp_routechangetransactionrec.newdeliveryscheme_id is null and
           fp_routechangetransactionrec.deliveryscheme_id is not null) then
          --option 3
          --insert into the old delscheme deliveryschemeperstop
          --try to add, if it already exists no problem
          begin
            insert into customerdeliveryscheme
              (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
            values
              (lv_newroutestoprec.customer_id, fp_routechangetransactionrec.deliveryscheme_id,
               fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate);
          exception
            when dup_val_on_index then
              update customerdeliveryscheme ds
              set    ds.active = 'Y',
                     ds.systemuser_id = gv_defaultuserid,
                     ds.timestamp = sysdate
              where  ds.active <> 'Y'
              and    ds.customer_id = lv_newroutestoprec.customer_id
              and    ds.deliveryscheme_id = fp_routechangetransactionrec.deliveryscheme_id
              and    ds.day_id = fp_routechangetransactionrec.newdrivingday_id;
          end;
          begin
            --insert into the old delscheme deliveryschemeperstop
            begin
              gv_message := 'new_stop insert deliveryschemesperstop';
              insert into deliveryschemesperstop
                (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
              values
                (lv_newroutestoprec.routestop_id, lv_newroutestoprec.customer_id,
                 fp_routechangetransactionrec.deliveryscheme_id,
                 fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate);
            exception
              when dup_val_on_index then
                null;
            end;
          end;
        else
          if (fp_routechangetransactionrec.newdeliveryscheme_id is not null and
             fp_routechangetransactionrec.deliveryscheme_id is not null) then
            --option 4
            begin
              insert into customerdeliveryscheme
                (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
                select dprs.customer_id, dprs.deliveryscheme_id,
                       fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate
                from   deliveryschemesperstop dprs
                where  dprs.routestop_id = lv_routestopid
                and    dprs.deliveryscheme_id <> fp_routechangetransactionrec.deliveryscheme_id
                and    not exists
                 (select 1
                        from   customerdeliveryscheme cdd
                        where  cdd.customer_id = dprs.customer_id
                        and    cdd.day_id = fp_routechangetransactionrec.newdrivingday_id
                        and    cdd.deliveryscheme_id = dprs.deliveryscheme_id)
                and    not exists
                 (select 1
                        from   deliveryschemesperstop dprsx
                        where  dprsx.routestop_id = lv_newroutestoprec.routestop_id
                        and    dprsx.customer_id = dprs.customer_id
                        and    dprsx.deliveryscheme_id = dprs.deliveryscheme_id
                        and    dprsx.day_id = fp_routechangetransactionrec.newdrivingday_id)
                group  by dprs.customer_id, dprs.deliveryscheme_id;
            exception
              when dup_val_on_index then
                null;
            end;
            gv_message := 'new_stop insert deliveryschemesperstop, option 4';
            insert into deliveryschemesperstop
              (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
              select lv_newroutestoprec.routestop_id, dprs.customer_id, dprs.deliveryscheme_id,
                     fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate
              from   deliveryschemesperstop dprs
              where  dprs.routestop_id = lv_routestopid
              and    dprs.deliveryscheme_id <> fp_routechangetransactionrec.deliveryscheme_id
              and    not exists
               (select 1
                      from   deliveryschemesperstop dprsx
                      where  dprsx.routestop_id = lv_newroutestoprec.routestop_id
                      and    dprsx.customer_id = dprs.customer_id
                      and    dprsx.deliveryscheme_id = dprs.deliveryscheme_id
                      and    dprsx.day_id = fp_routechangetransactionrec.newdrivingday_id);
            --insert into the new delscheme deliveryschemeperstop
            begin
              insert into customerdeliveryscheme
                (customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
              values
                (lv_newroutestoprec.customer_id, fp_routechangetransactionrec.newdeliveryscheme_id,
                 fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate);
            exception
              when dup_val_on_index then
                update customerdeliveryscheme ds
                set    ds.active = 'Y',
                       ds.systemuser_id = gv_defaultuserid,
                       ds.timestamp = sysdate
                where  ds.active <> 'Y'
                and    ds.customer_id = lv_newroutestoprec.customer_id
                and    ds.deliveryscheme_id = fp_routechangetransactionrec.newdeliveryscheme_id
                and    ds.day_id = fp_routechangetransactionrec.newdrivingday_id;
            end;
            begin
              gv_message := 'new_stop insert deliveryschemesperstop';
              insert into deliveryschemesperstop
                (routestop_id, customer_id, deliveryscheme_id, day_id, systemuser_id, timestamp)
              values
                (lv_newroutestoprec.routestop_id, lv_newroutestoprec.customer_id,
                 fp_routechangetransactionrec.newdeliveryscheme_id,
                 fp_routechangetransactionrec.newdrivingday_id, gv_defaultuserid, sysdate);
            exception
              when dup_val_on_index then
                null;
            end;
          end if;
        end if;
      end if;
    end if;

    --step 3 copy standarddeliverylines to new driving day, all deliveryschemes from old routestop or only selected one
    for DS_FORREC in (select dsp.deliveryscheme_id
               from   deliveryschemesperstop dsp
               where  dsp.routestop_id = lv_routestopid
                      and    (dsp.deliveryscheme_id = fp_routechangetransactionrec.deliveryscheme_id
                     						or fp_routechangetransactionrec.deliveryscheme_id is null)
                      group  by dsp.deliveryscheme_id)
    loop
        copy_standarddeliverylines(fp_routechangetransactionrec, DS_FORREC.deliveryscheme_id);
    end loop;

    if gv_ss_directstopchange = 1 then
      cleanupdays_movestop;
    else
      --step 4 end previous stop
      end_previous_stop(lv_removestop, fp_routechangetransactionrec, lv_routeid, lv_routestopid,
                        lv_newrouteid, lv_newroutestoprec.routestop_id);
      --step 5 update routestatus control
      update_routecontrol(lv_removestop, lv_newroutestoprec.customer_id, lv_newrouteid,
                          lv_routestopid, fp_routechangetransactionrec.stopnumber,
                          lv_newroutestoprec.routestop_id, lv_newroutestoprec.stopnumber);
      --Step 6: Update stops that have the route of the ended stop as return route
      update_return_routes(fp_routechangetransactionrec.customer_id, lv_routstopenddate, lv_routeid,
                           fp_routechangetransactionrec.routenumber);
    end if;
    -- Step 8: Update BatchJobContents
    update_batchjobcontents(fp_routechangetransactionrec.drivingday_id,
                            fp_routechangetransactionrec.newdrivingday_id,
                            fp_routechangetransactionrec.deliverypoint_id,
                            fp_routechangetransactionrec.changestartdate,
                            fp_routechangetransactionrec.plant_id,
                            fp_routechangetransactionrec.customer_id);

		write_log('Return from Pack_Routetransaction.MOVE_STOP.');
  end move_stop;

  procedure change_deliveryscheme(fp_routechangetransactionrec in routechangetransaction%rowtype) is
    lv_route_id               route.route_id%type;
  	lv_is_routeday_change			boolean;
    lv_routestop_is_valid			boolean;
    lv_stop_id								number;
    lv_stoprec                stop%rowtype;
    lv_date									  date;
    lv_number									number;

  begin
    --change deliveryscheme
    gv_message := 'change_deliveryscheme';
		write_log('Calling Pack_Routetransaction.CHANGE_DELIVERYSCHEME...');

    lv_is_routeday_change := (FP_ROUTECHANGETRANSACTIONREC.drivingday_id <> FP_ROUTECHANGETRANSACTIONREC.newdrivingday_id)
    														or (FP_ROUTECHANGETRANSACTIONREC.route_id <> FP_ROUTECHANGETRANSACTIONREC.newroute_id);

    lv_route_id := FP_ROUTECHANGETRANSACTIONREC.route_id;

  --STEP 1: ADD the NEW DELIVERY SCHEME to CUSTOMER
    --add customer deliveryscheme
    add_customer_delscheme_days(fp_routechangetransactionrec.customer_id,
                                fp_routechangetransactionrec.newdeliveryscheme_id,
                                fp_routechangetransactionrec.newdrivingday_id);

  --STEP 2: for eligible ROUTESTOP(s) => REPLACE the OLD DELIVERYSCHEME (delete) with the NEW DELIVERYSCHEME (add)
    if (lv_route_id <> 0) then
    	for RS_FORREC in (
				select 	RS.routestop_id
         from   ROUTESTOP RS
         where  RS.route_id = lv_route_id
         and    RS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
         and    (RS.deliverypoint_id = FP_ROUTECHANGETRANSACTIONREC.deliverypoint_id or FP_ROUTECHANGETRANSACTIONREC.deliverypoint_id is null)
         and 		FP_ROUTECHANGETRANSACTIONREC.changestartdate < RS.dateinactive
         and		exists (select 1
         					from	DELIVERYSCHEMESPERSTOP DSPS
                  where	DSPS.deliveryscheme_id = nvl(FP_ROUTECHANGETRANSACTIONREC.deliveryscheme_id, DSPS.deliveryscheme_id)
                --and   DSPS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
                --and   DSPS.day_id = FP_ROUTECHANGETRANSACTIONREC.drivingday_id
                  and   DSPS.routestop_id = RS.routestop_id))
			loop
        begin
        --Remove the old delivery scheme from stop
          delete from DELIVERYSCHEMESPERSTOP DSPS
          where	DSPS.deliveryscheme_id = nvl(FP_ROUTECHANGETRANSACTIONREC.deliveryscheme_id, DSPS.deliveryscheme_id)
        --and   DSPS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
        --and   DSPS.day_id = FP_ROUTECHANGETRANSACTIONREC.drivingday_id
          and   DSPS.routestop_id = RS_FORREC.routestop_id;

        --Add the new deliveryscheme to stop
          gv_message := 'insert into deliveryschemesperstop';
          insert into DELIVERYSCHEMESPERSTOP(
            customer_id, deliveryscheme_id, day_id,
            routestop_id,
            systemuser_id, timestamp)
          values(
            FP_ROUTECHANGETRANSACTIONREC.customer_id, FP_ROUTECHANGETRANSACTIONREC.newdeliveryscheme_id, FP_ROUTECHANGETRANSACTIONREC.newdrivingday_id,
            RS_FORREC.routestop_id,
            gv_defaultuserid, sysdate);

        exception
          when DUP_VAL_ON_INDEX then null;
        end;
    	end loop;
    end if;

  --STEP 3: INACTIVATE the OLD DELIVERYSCHEME
    --if there is no stop anymore then the CustomerDeliveryScheme is inactivated
    begin
      select	1
      into		lv_number
      from		DELIVERYSCHEMESPERSTOP DSPS
      join		ROUTESTOP RS on RS.routestop_id = DSPS.routestop_id
      where		DSPS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
      and   	DSPS.day_id = FP_ROUTECHANGETRANSACTIONREC.drivingday_id
      and 		DSPS.deliveryscheme_id = nvl(FP_ROUTECHANGETRANSACTIONREC.deliveryscheme_id, DSPS.deliveryscheme_id)
      and   	DSPS.deliveryscheme_id <> FP_ROUTECHANGETRANSACTIONREC.newdeliveryscheme_id
      and 		FP_ROUTECHANGETRANSACTIONREC.changestartdate < RS.dateinactive;
		exception
      when NO_DATA_FOUND then
        update  CUSTOMERDELIVERYSCHEME CDS
        set     CDS.active = 'N',
                CDS.systemuser_id = gv_defaultuserid,
                CDS.timestamp = sysdate
        where   CDS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
        and     CDS.day_id = FP_ROUTECHANGETRANSACTIONREC.drivingday_id
        and     CDS.deliveryscheme_id = nvl(FP_ROUTECHANGETRANSACTIONREC.deliveryscheme_id, CDS.deliveryscheme_id)
        and     CDS.deliveryscheme_id <> FP_ROUTECHANGETRANSACTIONREC.newdeliveryscheme_id;
      when TOO_MANY_ROWS then
        null;
		end;

  --STEP 4: CHANGE for STANDARD DELIVERIES
  --when there is a Route/Day change then Copy_Standarddeliverylines is run within TransNumber = 6
  	if (not lv_is_routeday_change) then
    --looping for old deliveryschemes and copy standarddeliverylines to new deliveryscheme
      --copy_standarddeliverylines(fp_routechangetransactionrec, fp_routechangetransactionrec.deliveryscheme_id);
      for DS_FORREC in (select DSPS.deliveryscheme_id
                        from   DELIVERYSCHEMESPERSTOP DSPS
                        join	 ROUTESTOP RS on RS.routestop_id = DSPS.routestop_id
												where	 RS.route_id = lv_route_id
                        and    RS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
                        and    (RS.deliverypoint_id = FP_ROUTECHANGETRANSACTIONREC.deliverypoint_id or FP_ROUTECHANGETRANSACTIONREC.deliverypoint_id is null)
                        and    DSPS.deliveryscheme_id = nvl(FP_ROUTECHANGETRANSACTIONREC.deliveryscheme_id, DSPS.deliveryscheme_id)
                        and    DSPS.deliveryscheme_id <> FP_ROUTECHANGETRANSACTIONREC.newdeliveryscheme_id)
      loop
          copy_standarddeliverylines(fp_routechangetransactionrec, DS_FORREC.deliveryscheme_id);
      end loop;
    end if;

	--STEP 5: CHECK for FUTURE STOPS AND ROUTECONTROL
    if (lv_route_id <> 0) then
    	for RC_FORREC in (
        select  RC.*
        from    ROUTECONTROL RC
        where   RC.route_id = lv_route_id
        and   	FP_ROUTECHANGETRANSACTIONREC.changestartdate <= RC.drivingdate
        and     RC.packingstatus <= 2
        and     RC.invoicesgenerated = 1
        and     RC.pocketpcstatus = 0)
			loop
        for RS_FORREC in (
          select	*
          from    ROUTESTOP RS
          where   RS.route_id = lv_route_id
          and     RS.customer_id = FP_ROUTECHANGETRANSACTIONREC.customer_id
          and    	(RS.deliverypoint_id = FP_ROUTECHANGETRANSACTIONREC.deliverypoint_id or FP_ROUTECHANGETRANSACTIONREC.deliverypoint_id is null)
          and    	FP_ROUTECHANGETRANSACTIONREC.changestartdate < RS.dateinactive)
        loop
          begin
            begin
              select  nvl(stop_id, 0)
              into    lv_stop_id
              from    STOP
              where   routecontrol_id = RC_FORREC.routecontrol_id
              and     routestop_id = RS_FORREC.routestop_id
              and     (status = 0 or status = 3);
            exception
      				when NO_DATA_FOUND then
                lv_stop_id := 0;
            end;

            lv_routestop_is_valid := PACK_DELIVERYBASICS.ROUTESTOPVALID(
                                                RS_FORREC.RouteStop_ID, RS_FORREC.DeliveryPoint_ID, null, 1,
                                                SYSDATE, RC_FORREC.DrivingDate,
                                                null, null, 0, 0, 'N', true,
                                                lv_date, lv_number, lv_number, lv_number, lv_date);

            if (lv_stop_id <> 0 and not lv_routestop_is_valid) then
              update  STOP
              set     status = 1
              where   stop_id = lv_stop_id;
            end if;

            if (lv_stop_id = 0 and lv_routestop_is_valid) then
            	begin
                init_stop(LV_STOPREC);
                LV_STOPREC.routecontrol_id := RC_FORREC.routecontrol_id;
                LV_STOPREC.routestop_id := RS_FORREC.routestop_id;
                LV_STOPREC.customer_link_id := FP_ROUTECHANGETRANSACTIONREC.customer_id;
                LV_STOPREC.deliverypoint_id := RS_FORREC.deliverypoint_id;
                LV_STOPREC.stopnumber := RS_FORREC.stopnumber;
                LV_STOPREC.status := 0;
                LV_STOPREC.stoptype := 3;
                LV_STOPREC.contactperson_id := RS_FORREC.contactperson_id;
                LV_STOPREC.chargedeliveryfee := RS_FORREC.chargedeliveryfee;
                insert into STOP values LV_STOPREC;
              end;
            end if;
          end;
        end loop;
    	end loop;
    end if;

    write_log('Return from Pack_Routetransaction.CHANGE_DELIVERYSCHEME.');
  end change_deliveryscheme;

  procedure process_1_transaction(fp_routechangetransactionrec in routechangetransaction%rowtype) is
  begin
    --process_1_transaction
    gv_message := 'start process_1_transaction routechangetransaction_id ' ||
                  to_char(fp_routechangetransactionrec.routechangetransaction_id);
    case
      when fp_routechangetransactionrec.transactionnumber = 1 then
        new_route(fp_routechangetransactionrec);
      when fp_routechangetransactionrec.transactionnumber = 2 then
        change_depot(fp_routechangetransactionrec);
      when fp_routechangetransactionrec.transactionnumber = 3 then
        new_stop(fp_routechangetransactionrec);
      when fp_routechangetransactionrec.transactionnumber = 4 then
        remove_stopnumber(fp_routechangetransactionrec);
      when fp_routechangetransactionrec.transactionnumber = 5 then
        change_stopnumber(fp_routechangetransactionrec);
      when fp_routechangetransactionrec.transactionnumber = 6 then
        move_stop(fp_routechangetransactionrec);
      when fp_routechangetransactionrec.transactionnumber = 7 then
        change_deliveryscheme(fp_routechangetransactionrec);
      else
        begin
          gv_message := ' routechangetransaction transactionnumber must be between 1 and 7 it is ' ||
                        fp_routechangetransactionrec.transactionnumber;
          raise ge_wrongvalue;
        end;
    end case;
  end process_1_transaction;

    function create_routechangetransaction(fp_transaction             in routechangetransaction.transactionnumber%type,
                                           fp_changestartdate         in routechangetransaction.changestartdate%type,
                                           fp_customerid              in customer.customer_id%type,
                                           fp_deliverypointid         in deliverypoint.deliverypoint_id%type,
                                           fp_plantid                 in plant.plant_id%type,
                                           fp_routenumber             in route.routenumber%type,
                                           fp_drivingdayid            in day.daynumber%type,
                                           fp_depotcode               in depot.code%type,
                                           fp_routeid                 in route.route_id%type,
                                           fp_stopnumber              in routestop.stopnumber%type,
                                           fp_routestopid             in routestop.routestop_id%type,
                                           fp_oldroutelastdrivingdate in date,
                                           fp_deliveryschemeid        in deliveryscheme.deliveryscheme_id%type,
                                           fp_newdrivingdayid         in day.daynumber%type,
                                           fp_newroutenumber          in route.routenumber%type,
                                           fp_newstopnumber           in routestop.stopnumber%type,
                                           fp_newrouteid              in route.route_id%type,
                                           fp_newdeliveryschemeid     in deliveryscheme.deliveryscheme_id%type,
                                           fp_productgroupid          in productgroup.productgroup_id%type,
                                           fp_sortSequence            in routestop.sortsequence%type default 0)
      return number is
      lv_routechangetransactionid routechangetransaction.routechangetransaction_id%type;
    begin
      gv_message := 'create routechangetransaction record';
      --get new routechangetransaction_id
      select seq_routechangetransaction.nextval into lv_routechangetransactionid from dual;
      --insert into routechangetransaction
      gv_message := 'insert routechangetransaction';
      insert into routechangetransaction
        (routechangetransaction_id, transactionnumber, status, errormsg, batchtransactionnumber,
         changestartdate, customer_id, deliverypoint_id, plant_id, routenumber, drivingday_id,
         depotcode, route_id, stopnumber, routestop_id, oldroutelastdrivingdate, deliveryscheme_id,
         newroute_id, newroutenumber, newstopnumber, newdrivingday_id, newdeliveryscheme_id,
         productgroup_id, creationtimestamp, timestamp, systemuser_id, sortSequence)
      values
        (lv_routechangetransactionid, fp_transaction, 0, null, 0, nvl(fp_changestartdate, sysdate),
         fp_customerid, fp_deliverypointid, fp_plantid, fp_routenumber, fp_drivingdayid,
         fp_depotcode, fp_routeid, fp_stopnumber, fp_routestopid, fp_oldroutelastdrivingdate,
         fp_deliveryschemeid, fp_newrouteid, fp_newroutenumber, fp_newstopnumber, fp_newdrivingdayid,
         fp_newdeliveryschemeid, fp_productgroupid, sysdate, sysdate, gv_defaultuserid, fp_sortSequence);

    write_log('Return from Pack_Routetransaction.CREATE_ROUTECHANGETRANSACTION with RoutechangetransactionId = '||lv_routechangetransactionid);

      return lv_routechangetransactionid;
    end create_routechangetransaction;

  procedure check_parameters(fp_transaction             in routechangetransaction.transactionnumber%type,
                             fp_changestartdate         in out routechangetransaction.changestartdate%type,
                             fp_customernumber          in customer.customernumber%type,
                             fp_deliverypointcode       in deliverypoint.code%type,
                             fp_plantcode               in plant.code%type,
                             fp_drivingday              in day.daynumber%type,
                             fp_routenumber             in route.routenumber%type,
                             fp_depotcode               in depot.code%type,
                             fp_stopnumber              in routestop.stopnumber%type,
                             fp_oldroutelastdrivingdate in routechangetransaction.oldroutelastdrivingdate%type,
                             fp_deliveryschemecode      in deliveryscheme.code%type,
                             fp_newdrivingday           in day.daynumber%type,
                             fp_newroutenumber          in route.routenumber%type,
                             fp_newstopnumber           in routestop.stopnumber%type,
                             fp_newdeliveryscheme       in deliveryscheme.code%type,
                             fp_productgroupcode        in productgroup.code%type,
                             fp_customerid              out customer.customer_id%type,
                             fp_deliverypointid         out deliverypoint.deliverypoint_id%type,
                             fp_plantid                 out plant.plant_id%type,
                             fp_routeid                 out route.route_id%type,
                             fp_depotid                 out depot.depot_id%type,
                             fp_routestopid             out routestop.routestop_id%type,
                             fp_deliveryschemeid        out deliveryscheme.deliveryscheme_id%type,
                             fp_newrouteid              out route.route_id%type,
                             fp_newdeliveryschemeid     out deliveryscheme.deliveryscheme_id%type,
                             fp_productgroupid          out productgroup.productgroup_id%type) is
    lv_intervalcheckmoveroute number;
    lv_route_deliveryschemeid number;
  begin
    write_log('Calling procedure Pack_Routetransaction.CHECK_PARAMETERS...');
    --check transaction number
    if (fp_transaction not between 1 and 7) or fp_transaction is null then
      gv_message := 'transaction must be between 1 and 7 and it is ' ||
                    nvl(to_char(fp_transaction), 'NULL');
      raise ge_wrongvalue;
    end if;
    --check change start date
    if fp_transaction > 2 then
      if (fp_changestartdate is null or trunc(fp_changestartdate) < trunc(sysdate)) then
        gv_message := 'change start date is wrong, must be >= sysdate it is ' ||
                      nvl(to_char(trunc(fp_changestartdate), 'dd-mon-yyyy'), 'NULL');
        raise ge_wrongvalue;
      end if;
    else
      --changestartdate = sysdate for transaction 1 and 2
      fp_changestartdate := trunc(sysdate);
    end if;
    --check customer number
    if fp_transaction > 2 then
      gv_message := 'customer number ' || nvl(to_char(fp_customernumber), 'NULL');
      select c.customer_id
      into   fp_customerid
      from   customer c
      where  c.customernumber = fp_customernumber;
    end if;
    --check deliverypoint code
    if fp_deliverypointcode is not null and fp_transaction > 2 then
      gv_message := 'deliverypoint code ' || fp_deliverypointcode;
      select dp.deliverypoint_id
      into   fp_deliverypointid
      from   deliverypoint dp
      where  dp.customer_id = fp_customerid
      and    dp.code = fp_deliverypointcode;
    else
      fp_deliverypointid := null;
    end if;
    --check plant code
    if fp_plantcode is not null then
      fp_plantid := get_plant_id(fp_plantcode);
    end if;
    --check driving day
    if fp_transaction in (2, 3, 4, 5, 6, 7) and
       ((fp_drivingday is null) or (fp_drivingday not between 1 and 7)) then
      gv_message := 'driving day is ' || nvl(to_char(fp_drivingday), 'NULL');
      raise ge_wrongvalue;
    end if;
    --check deliveryscheme
    if fp_deliveryschemecode is not null then
      gv_message := 'delivery scheme code ' || nvl(fp_deliveryschemecode, 'NULL');
      begin
        select ds.deliveryscheme_id
        into   fp_deliveryschemeid
        from   deliveryscheme ds
        where  ds.code = fp_deliveryschemecode;
      exception
        when no_data_found then
          gv_message := 'Delivery scheme code: ' || nvl(fp_deliveryschemecode, 'NULL') ||
                        ' does not exist! ';
          raise ge_wrongvalue;
      end;
    else
      fp_deliveryschemeid := null;
    end if;
    --check route number
    if fp_transaction in (2, 3, 4, 5, 6, 7) then
      begin
        gv_message := 'route number ' || nvl(to_char(fp_routenumber), 'NULL');
        if fp_routenumber is null then
          raise ge_wrongvalue;
        end if;
        fp_routeid := get_route_id(fp_routenumber, fp_drivingday, fp_plantid);
        if fp_deliveryschemeid is not null and fp_transaction = 2 then
          begin
            select r.deliveryscheme_id
            into   lv_route_deliveryschemeid
            from   route r
            where  r.route_id = fp_routeid;
            if fp_deliveryschemeid <> lv_route_deliveryschemeid then
              begin
                gv_message := 'route number ' || nvl(to_char(fp_routenumber), 'NULL') ||
                              ' has a different delivery scheme then ' || fp_deliveryschemecode;
                raise ge_wrongvalue;
              end;
            end if;
          end;
        end if;
      exception
        when no_data_found then
          raise ge_wrongvalue;
      end;
    end if;
    --check depot code
    if fp_transaction in (1, 2) and fp_depotcode is not null then
      fp_depotid := get_depot_id(fp_depotcode, fp_plantid);
    else
      fp_depotid := null;
    end if;
    --check routestopnumber
    if fp_transaction in (4, 5, 6, 7) then
      fp_routestopid := get_routestopid(fp_routeid, fp_customerid, fp_deliverypointid, fp_stopnumber,
                                        fp_changestartdate,
                                        case
                                           when length(fp_routenumber) = 5 and fp_transaction = 5 and
                                                gv_databasecode = 'LST' then
                                            99
                                           else
                                            fp_transaction
                                         end);
      if fp_deliveryschemeid is not null and fp_routestopid is not null then
        begin
          select dsps.deliveryscheme_id
          into   lv_route_deliveryschemeid
          from   deliveryschemesperstop dsps
          where  dsps.routestop_id = fp_routestopid
          and    dsps.deliveryscheme_id = fp_deliveryschemeid
          and    dsps.customer_id = fp_customerid
          and    dsps.day_id = fp_drivingday;
        exception
          when no_data_found then
            begin
              gv_message := 'route number ' || nvl(to_char(fp_routenumber), 'NULL') ||
                            ' stopnumber ' || nvl(to_char(fp_stopnumber), 'NULL') ||
                            ' has a different delivery scheme then ' || fp_deliveryschemecode;
              raise ge_wrongvalue;
            end;
        end;
      end if;
    else
      fp_routestopid := null;
    end if;
    --check oldroutelastdrivingdate
    if (fp_transaction in (4) and fp_oldroutelastdrivingdate is not null and
       fp_oldroutelastdrivingdate not between trunc(sysdate) and fp_changestartdate) then
      gv_message := 'old last route driving date ' ||
                    nvl(to_char(fp_oldroutelastdrivingdate, 'DD-MON-YYYY'), 'NULL') ||
                    ' is not between today and the changedate!';
      raise ge_wrongvalue;
    end if;
    --check for move routestop the interval chosen 26-09-2012
    if fp_transaction = 6 and gv_ss_directstopchange = 0 and fp_newdeliveryscheme is null and
       gv_databasecode not in ('LST', 'AUJ', 'CBD', 'BNL', 'HOW', 'MME') then
      begin
        select (nvl(min(ds.frequency), 1) * 7) - 1
        into   lv_intervalcheckmoveroute
        from   deliveryschemesperstop dsp
        join   deliveryscheme ds
        on     ds.deliveryscheme_id = dsp.deliveryscheme_id
        where  dsp.routestop_id = fp_routestopid;
        if fp_drivingday = fp_newdrivingday then
          --check oldroutelastdrivingdate
          if fp_oldroutelastdrivingdate < ((trunc(sysdate) - lv_intervalcheckmoveroute)) then
            begin
              gv_message := '*****   Route stop not moved, selected date ' ||
                            nvl(to_char(fp_oldroutelastdrivingdate, 'DD-MON-YYYY'), 'NULL') ||
                            ' must be bigger than ' ||
                            to_char((trunc(sysdate) - lv_intervalcheckmoveroute), 'DD-MON-YYYY') ||
                            '   *****';
              raise ge_wrongvalue;
            end;
          end if;
          if fp_changestartdate not between (fp_oldroutelastdrivingdate + 1) and
             (trunc(fp_oldroutelastdrivingdate + 1) + lv_intervalcheckmoveroute) then
            begin
              gv_message := '*****   Route stop not moved, selected date ' ||
                            nvl(to_char(fp_changestartdate, 'DD-MON-YYYY'), 'NULL') ||
                            ' is not between ' ||
                            to_char((fp_oldroutelastdrivingdate + 1), 'DD-MON-YYYY') || ' and ' ||
                            to_char((trunc(fp_oldroutelastdrivingdate + 1) +
                                    lv_intervalcheckmoveroute), 'DD-MON-YYYY') || '   *****';
              raise ge_wrongvalue;
            end;
          end if;
        else
          --check oldroutelastdrivingdate
          if fp_oldroutelastdrivingdate not between (trunc(sysdate) - lv_intervalcheckmoveroute) and
             trunc(sysdate) then
            begin
              gv_message := '*****   Route stop not moved, selected date ' ||
                            nvl(to_char(fp_oldroutelastdrivingdate, 'DD-MON-YYYY'), 'NULL') ||
                            ' is not between ' ||
                            to_char((trunc(sysdate) - lv_intervalcheckmoveroute), 'DD-MON-YYYY') ||
                            ' and ' || to_char(trunc(sysdate), 'DD-MON-YYYY') || '   *****';
              raise ge_wrongvalue;
            end;
          end if;
          if fp_changestartdate not between trunc(sysdate) and
             (trunc(sysdate) + lv_intervalcheckmoveroute) then
            begin
              gv_message := '*****   Route stop not moved, selected date ' ||
                            nvl(to_char(fp_changestartdate, 'DD-MON-YYYY'), 'NULL') ||
                            ' is not between ' || to_char(trunc(sysdate), 'DD-MON-YYYY') || ' and ' ||
                            to_char((trunc(sysdate) + lv_intervalcheckmoveroute), 'DD-MON-YYYY') ||
                            '   *****';
              raise ge_wrongvalue;
            end;
          end if;
        end if;
      end;
    end if;
    --en 26-09-2012
    --check deliveryscheme
    if (fp_transaction in (1, 6, 7) and fp_deliveryschemecode is not null) then
      gv_message := 'delivery scheme code ' || nvl(fp_deliveryschemecode, 'NULL');
      begin
        select ds.deliveryscheme_id
        into   fp_deliveryschemeid
        from   deliveryscheme ds
        where  ds.code = fp_deliveryschemecode;
      exception
        when no_data_found then
          gv_message := 'Delivery scheme code: ' || nvl(fp_deliveryschemecode, 'NULL') ||
                        ' does not exist! ';
          raise ge_wrongvalue;
      end;
    else
      fp_deliveryschemeid := null;
    end if;
    --check new driving day
    if (fp_transaction in (1, 5, 6, 7)) and
       ((fp_newdrivingday is null) or (fp_newdrivingday not between 1 and 7)) then
      gv_message := 'new driving day is ' || nvl(to_char(fp_newdrivingday), 'NULL');
      raise ge_wrongvalue;
    end if;
    --new route number
    if fp_transaction in (1, 5, 6, 7) and fp_newroutenumber is null then
      gv_message := 'new route number is NULL and must be filled for transaction ' ||
                    to_char(fp_transaction);
      raise ge_wrongvalue;
    end if;
    --get new route id if need be and it is there
    if (fp_transaction in (3, 5, 6, 7)) and fp_routenumber is not null then
      begin
        fp_newrouteid := get_route_id(fp_newroutenumber, fp_newdrivingday, fp_plantid);
      exception
        when no_data_found then
          fp_newrouteid := null;
      end;
    else
      fp_newrouteid := null;
    end if;
    --check new stop number
    if fp_transaction in (3, 5, 6, 7) and fp_newstopnumber is null then
      gv_message := 'new stop number is NULL and must be filled for transaction ' ||
                    to_char(fp_transaction);
      raise ge_wrongvalue;
    end if;
    --check new delivery scheme
    if fp_transaction in (1, 3, 6, 7) then
      gv_message := 'new delivery scheme ' || nvl(fp_newdeliveryscheme, 'NULL');
      if fp_transaction in (1, 3, 6) and fp_newdeliveryscheme is null then
        fp_newdeliveryschemeid := null;
      else
        begin
          select ds.deliveryscheme_id
          into   fp_newdeliveryschemeid
          from   deliveryscheme ds
          where  ds.code = fp_newdeliveryscheme;
        exception
          when no_data_found then
            gv_message := 'new delivery scheme code: ' || nvl(fp_newdeliveryscheme, 'NULL') ||
                          ' does not exist! ';
            raise ge_wrongvalue;
        end;
      end if;
    else
      fp_newdeliveryschemeid := null;
    end if;
    --check productgroup
    if fp_transaction > 5 and fp_productgroupcode is not null then
      begin
        select pg.productgroup_id
        into   fp_productgroupid
        from   productgroup pg
        where  pg.code = fp_productgroupcode;
      exception
        when no_data_found then
          gv_message := 'Product group code ' || fp_productgroupcode || ' does not exist!';
          raise ge_wrongvalue;
      end;
    else
      fp_productgroupid := null;
    end if;

    write_log('Return from Pack_Routetransaction.CHECK_PARAMETERS for TransactionNumber = '||fp_transaction);
  end check_parameters;

  procedure addroutechange(fp_changestartdate          in routechangetransaction.changestartdate%type,
                           fp_oldroutelastdrivingdate  in date,
                           fp_customernumber           in customer.customernumber%type,
                           fp_deliverypointcode        in deliverypoint.code%type,
                           fp_plantcode                in plant.code%type,
                           fp_drivingday               in day.daynumber%type,
                           fp_routenumber              in route.routenumber%type,
                           fp_depotcode                in depot.code%type,
                           fp_stopnumber               in routestop.stopnumber%type,
                           fp_deliveryschemecode       in deliveryscheme.code%type,
                           fp_newdrivingday            in day.daynumber%type,
                           fp_newroutenumber           in route.routenumber%type,
                           fp_newstopnumber            in routestop.stopnumber%type,
                           fp_newdeliveryscheme        in deliveryscheme.code%type,
                           fp_productgroupcode         in productgroup.code%type,
                           fp_errmsg                   out routechangetransaction.errormsg%type,
                           fp_routechangetransactionid out routechangetransaction.routechangetransaction_id%type) is
    lv_transaction         routechangetransaction.transactionnumber%type;
    lv_customerid          customer.customer_id%type;
    lv_deliverypointid     deliverypoint.deliverypoint_id%type;
    lv_plantid             plant.plant_id%type;
    lv_routeid             route.route_id%type;
    lv_depotid             depot.depot_id%type;
    lv_routestopid         routestop.routestop_id%type;
    lv_deliveryschemeid    deliveryscheme.deliveryscheme_id%type;
    lv_newrouteid          route.route_id%type;
    lv_newdeliveryschemeid deliveryscheme.deliveryscheme_id%type;
    lv_productgroupid      productgroup.productgroup_id%type;
    lv_changestartdate     routechangetransaction.changestartdate%type;

    procedure determine_transaction is
    begin
      --determine_transaction
      gv_message := 'determine_transaction';
      case
        when fp_drivingday is null and fp_routenumber is null and fp_stopnumber is null and
             fp_newroutenumber is not null then
          --add route
          lv_transaction := 1;
        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is null and
             fp_newstopnumber is null then
          --change depot
          lv_transaction := 2;
        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is null and
             fp_newstopnumber is not null then
          --add route stop
          lv_transaction := 3;
        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is not null and
             fp_newstopnumber is null and fp_newdeliveryscheme is null then
          --remove route stop
          lv_transaction := 4;
        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is not null and
             fp_newstopnumber is not null and fp_newdeliveryscheme is null and
             ((fp_newroutenumber is null and fp_newdrivingday is null) or
             (fp_newroutenumber = fp_routenumber and fp_newdrivingday = fp_drivingday)) then
          --change stop number within route
          lv_transaction := 5;
        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is not null and
             fp_newstopnumber is not null and fp_newdeliveryscheme is null then
          --move stop
          lv_transaction := 6;
        when fp_drivingday is not null and fp_newdeliveryscheme is not null then
          --change deliveryscheme
          lv_transaction := 7;
        else
          --error transaction not found!?
          lv_transaction := 0;
      end case;
    end determine_transaction;

  begin
    --write log
    write_log('Start procedure pack_routetransaction.addroutechange');
    --check parameters
    lv_changestartdate := fp_changestartdate;
    determine_transaction;
    check_parameters(lv_transaction, lv_changestartdate, fp_customernumber, fp_deliverypointcode,
                     fp_plantcode, fp_drivingday, fp_routenumber, fp_depotcode, fp_stopnumber,
                     fp_oldroutelastdrivingdate, fp_deliveryschemecode, fp_newdrivingday,
                     fp_newroutenumber, fp_newstopnumber, fp_newdeliveryscheme, fp_productgroupcode,
                     lv_customerid, lv_deliverypointid, lv_plantid, lv_routeid, lv_depotid,
                     lv_routestopid, lv_deliveryschemeid, lv_newrouteid, lv_newdeliveryschemeid,
                     lv_productgroupid);
    --create routetransaction
    fp_routechangetransactionid := create_routechangetransaction(lv_transaction, lv_changestartdate,
                                                                 lv_customerid, lv_deliverypointid,
                                                                 lv_plantid, fp_routenumber,
                                                                 fp_drivingday, fp_depotcode,
                                                                 lv_routeid, fp_stopnumber,
                                                                 lv_routestopid,
                                                                 fp_oldroutelastdrivingdate,
                                                                 lv_deliveryschemeid,
                                                                 fp_newdrivingday, fp_newroutenumber,
                                                                 fp_newstopnumber, lv_newrouteid,
                                                                 lv_newdeliveryschemeid,
                                                                 lv_productgroupid);
    --when all is ok
    commit;
    write_log('Procedure pack_routetransaction.addroutechange ran succesfully. For transaction ' ||
              lv_transaction);
  exception
    when no_data_found then
      begin
        fp_errmsg := 'Addroutechange Error No Data Found ' || gv_message;
        write_log(fp_errmsg, 3);
        rollback;
      end;
    when ge_wrongvalue then
      begin
        fp_errmsg := 'Addroutechange Error Wrong value ' || gv_message;
        write_log(fp_errmsg, 3);
        rollback;
      end;
    when dup_val_on_index then
      begin
        fp_errmsg := 'Addroutechange Error Duplicate Value On Index ' || gv_message;
        write_log(fp_errmsg, 3);
        rollback;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        fp_errmsg := 'Addroutechange Error Others ' || gv_message;
        write_log(fp_errmsg, 3);
        fp_errmsg := fp_errmsg || ' ' || sqlerrm;
        rollback;
      end;
  end addroutechange;

  procedure getroutechangestatus(fp_routechangetransactionid in routechangetransaction.routechangetransaction_id%type,
                                 fp_errmsg                   out routechangetransaction.errormsg%type,
                                 fp_status                   out routechangetransaction.status%type) is
  begin
    --write log
    write_log('Start procedure PACK_ROUTETRANSACTION.addroutechange');
    --get record information
    fp_status := -1;
    fp_errmsg := 'routechangetransaction_id ' || fp_routechangetransactionid;
    --get information from routechangetransaction
    select rc.errormsg, rc.status
    into   fp_errmsg, fp_status
    from   routechangetransaction rc
    where  rc.routechangetransaction_id = fp_routechangetransactionid;
    --when all is ok
    write_log('Procedure PACK_ROUTETRANSACTION.getroutechangestatus ran succesfully');
  exception
    when no_data_found then
      begin
        fp_errmsg := 'Getroutechangestatus Invalid ID No record found ' || gv_message;
        write_log(fp_errmsg, 3);
      end;
    when ge_wrongvalue then
      begin
        fp_errmsg := 'Getroutechangestatus Wrong value ' || gv_message;
        write_log(fp_errmsg, 3);
      end;
    when dup_val_on_index then
      begin
        fp_errmsg := 'Getroutechangestatus Duplicate Value On Index ' || gv_message;
        write_log(fp_errmsg, 3);
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        fp_errmsg := 'Getroutechangestatus Error Others ' || gv_message;
        write_log(fp_errmsg, 3);
        fp_errmsg := fp_errmsg || ' ' || sqlerrm;
      end;
  end getroutechangestatus;

  procedure update_routechangetransaction(fp_batchtransactionnumber   in routechangetransaction.batchtransactionnumber%type,
                                          fp_status                   in routechangetransaction.status%type,
                                          fp_routechangetransactionid in routechangetransaction.routechangetransaction_id%type) is
  begin
    --update_routechangetransaction
    case
      when fp_status = 1 then
        --no errors
        update routechangetransaction z
        set    z.batchtransactionnumber = fp_batchtransactionnumber, z.timestamp = sysdate,
               z.status = fp_status, z.errormsg = null
        where  z.routechangetransaction_id = fp_routechangetransactionid;
      else
        --errors update with errormsg as well
        update routechangetransaction z
        set    z.batchtransactionnumber = fp_batchtransactionnumber, z.timestamp = sysdate,
               z.status = fp_status, z.errormsg = gv_message
        where  z.routechangetransaction_id = fp_routechangetransactionid;
    end case;
    commit;
  end update_routechangetransaction;

  procedure processroutechanges(fp_plantcode              in plant.code%type,
                                fp_batchtransactionnumber out routechangetransaction.batchtransactionnumber%type,
                                fp_status                 out routechangetransaction.status%type) is
    lv_plantid plant.plant_id%type;
    lv_counter number := 0;
  begin
    --write log
    write_log('Start procedure PACK_ROUTETRANSACTION.processroutechanges');
    fp_status := 1;
    --get plant id/check plant code
    if fp_plantcode is not null then
      lv_plantid := get_plant_id(fp_plantcode);
    end if;
    --get new batchtransactionnumber
    fp_batchtransactionnumber := get_max_batchtransactionnumber;
    --start processing records
    for x in (select *
              from   routechangetransaction rct
              where  rct.status = 0
              and    ((rct.plant_id = lv_plantid) or (fp_plantcode is null))
              order  by rct.routechangetransaction_id) loop
      begin
        fp_status := 1;
        process_1_transaction(x);
        update_routechangetransaction(fp_batchtransactionnumber, fp_status,
                                      x.routechangetransaction_id);
        lv_counter := lv_counter + 1;
      exception
        when no_data_found then
          begin
            gv_message := 'Processroutechanges No data found ' || gv_message || ' ' || sqlerrm || ' ' ||
                          ' routechangetransaction id ' || x.routechangetransaction_id;
            write_log(gv_message, 3);
            fp_status := 2;
            rollback;
            update_routechangetransaction(fp_batchtransactionnumber, fp_status,
                                          x.routechangetransaction_id);
          end;
        when ge_general then
          begin
            write_log('Processroutechanges ' || gv_message || ' routechangetransaction id ' ||
                      x.routechangetransaction_id || ' ' || sqlerrm, 3);
            fp_status := 2;
            rollback;
            update_routechangetransaction(fp_batchtransactionnumber, fp_status,
                                          x.routechangetransaction_id);
          end;
        when ge_wrongvalue then
          begin
            gv_message := 'Processroutechanges Error Wrong value ' || gv_message ||
                          ' routechangetransaction id ' || x.routechangetransaction_id || ' ' ||
                          sqlerrm;
            write_log(gv_message, 3);
            fp_status := 2;
            rollback;
            update_routechangetransaction(fp_batchtransactionnumber, fp_status,
                                          x.routechangetransaction_id);
          end;
        when dup_val_on_index then
          begin
            gv_message := 'Processroutechanges Error Duplicate Value On Index ' || gv_message || ' ' ||
                          sqlerrm || ' routechangetransaction id ' || x.routechangetransaction_id;
            write_log(gv_message, 3);
            fp_status := 2;
            rollback;
            update_routechangetransaction(fp_batchtransactionnumber, fp_status,
                                          x.routechangetransaction_id);
          end;
        when others then
          begin
            gv_message := 'Processroutechanges Error Others ' || sqlerrm || ' ' || gv_message ||
                          ' routechangetransaction id ' || x.routechangetransaction_id;
            write_log(gv_message, 3);
            fp_status := 2;
            rollback;
            update_routechangetransaction(fp_batchtransactionnumber, fp_status,
                                          x.routechangetransaction_id);
          end;
      end;
    end loop;
    write_log('Procedure PACK_ROUTETRANSACTION.processroutechanges ran succesfully, ' ||
              lv_counter || ' rows processed');
  exception
    when no_data_found then
      begin
        gv_message := 'Processroutechanges Error No data found ' || gv_message;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
      end;
    when ge_general then
      begin
        write_log('Processroutechanges ' || gv_message, 3);
        fp_status := 2;
        rollback;
      end;
    when ge_wrongvalue then
      begin
        gv_message := 'Processroutechanges Error Wrong value ' || gv_message;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
      end;
    when dup_val_on_index then
      begin
        gv_message := 'Processroutechanges Error Duplicate Value On Index ' || gv_message || ' ' ||
                      sqlerrm;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
      end;
    when others then
      begin
        gv_message := 'Processroutechanges Error Others ' || sqlerrm || ' ' || gv_message;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
      end;
  end processroutechanges;

  procedure update_routechangetrans_batch(fp_batchtransactionnumber in routechangetransaction.batchtransactionnumber%type,
                                          fp_status                 in routechangetransaction.status%type) is
  begin
    gv_message := gv_message || ' : update_routechangetrans_batch';
    --update_routechangetransaction
    for x in (select rct.routechangetransaction_id
              from   routechangetransaction rct
              where  rct.batchtransactionnumber = fp_batchtransactionnumber
              order  by rct.routechangetransaction_id) loop
      begin
        case
          when fp_status = 1 then
            --no errors
            update routechangetransaction z
            set    z.timestamp = sysdate, z.status = fp_status, z.errormsg = null
            where  z.routechangetransaction_id = x.routechangetransaction_id;
          else
            --errors update with errormsg as well
            update routechangetransaction z
            set    z.timestamp = sysdate, z.status = fp_status, z.errormsg = gv_message
            where  z.routechangetransaction_id = x.routechangetransaction_id;
        end case;
      end;
    end loop;
    commit;
  end update_routechangetrans_batch;

  procedure reprocessroutechanges(fp_batchtransactionnumber in routechangetransaction.batchtransactionnumber%type,
                                  fp_status                 out routechangetransaction.status%type) is
    lv_counter number := 0;
  begin
    --write log
    write_log('Start procedure PACK_ROUTETRANSACTION.reprocessroutechanges');
    if fp_batchtransactionnumber not between 0 and 8 or fp_batchtransactionnumber is null then
      gv_message := 'Invalid transaction number';
      raise ge_wrongvalue;
    end if;
    --start processing records
    for x in (select *
              from   routechangetransaction rct
              where  rct.batchtransactionnumber = fp_batchtransactionnumber
              and    rct.status in (2, 3)
              order  by rct.routechangetransaction_id) loop
      begin
        process_1_transaction(x);
        lv_counter := lv_counter + 1;
      end;
    end loop;
    --when all is ok
    fp_status := 1;
    update_routechangetrans_batch(fp_batchtransactionnumber, fp_status);
    write_log('Procedure PACK_ROUTETRANSACTION.reprocessroutechanges ran succesfully, ' ||
              lv_counter || ' rows processed');
  exception
    when no_data_found then
      begin
        gv_message := 'Reprocessroutechanges Error No Data Found ' || gv_message;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
        update_routechangetrans_batch(fp_batchtransactionnumber, fp_status);
      end;
    when ge_general then
      begin
        write_log('Reprocessroutechanges ' || gv_message, 3);
        fp_status := 2;
        rollback;
        update_routechangetrans_batch(fp_batchtransactionnumber, fp_status);
      end;
    when ge_wrongvalue then
      begin
        gv_message := 'Reprocessroutechanges Error Wrong value ' || gv_message;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
        update_routechangetrans_batch(fp_batchtransactionnumber, fp_status);
      end;
    when dup_val_on_index then
      begin
        gv_message := 'Reprocessroutechanges Error Duplicate Value On Index ' || gv_message || ' ' ||
                      sqlerrm;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
        update_routechangetrans_batch(fp_batchtransactionnumber, fp_status);
      end;
    when others then
      begin
        gv_message := 'Reprocessroutechanges Error Others ' || sqlerrm || ' ' || gv_message;
        write_log(gv_message, 3);
        fp_status := 2;
        rollback;
        update_routechangetrans_batch(fp_batchtransactionnumber, fp_status);
      end;
  end reprocessroutechanges;

  procedure update_onlineroutechanges(fp_routechangetransactionid in routechangetransaction.routechangetransaction_id%type,
                                      fp_onlineroutechange        in number,
                                      fp_errmsg                   in routechangetransaction.errormsg%type) is
  begin
    gv_message := gv_message || ' update_onlineroutechanges routechangetransaction_id ' || fp_routechangetransactionid;
    update routechangetransaction z
    set    z.timestamp = sysdate, z.status = fp_onlineroutechange, z.errormsg = fp_errmsg,
           z.systemuser_id = gv_defaultuserid
    where  z.routechangetransaction_id = fp_routechangetransactionid;
    --commit;
  end update_onlineroutechanges;

  procedure add_routechanges(fp_changestartdate          in routechangetransaction.changestartdate%type,
                             fp_oldroutelastdrivingdate  in date,
                             fp_customernumber           in customer.customernumber%type,
                             fp_deliverypointcode        in deliverypoint.code%type,
                             fp_plantcode                in plant.code%type,
                             fp_drivingday               in day.daynumber%type,
                             fp_routenumber              in route.routenumber%type,
                             fp_depotcode                in depot.code%type,
                             fp_stopnumber               in routestop.stopnumber%type,
                             fp_deliveryschemecode       in deliveryscheme.code%type,
                             fp_newdrivingday            in day.daynumber%type,
                             fp_newroutenumber           in route.routenumber%type,
                             fp_newstopnumber            in routestop.stopnumber%type,
                             fp_newdeliveryscheme        in deliveryscheme.code%type,
                             fp_productgroupcode         in productgroup.code%type,
                             fp_sortSequence             in routestop.sortsequence%type,
                             fp_errmsg                   out routechangetransaction.errormsg%type,
                             fp_routechangetransid_table out RouteChangeTransactionIdTable)
  is
    lv_routechangetransid  routechangetransaction.routechangetransaction_id%type;
    lv_transactionnumber   routechangetransaction.transactionnumber%type;
    lv_customerid          customer.customer_id%type;
    lv_deliverypointid     deliverypoint.deliverypoint_id%type;
    lv_plantid             plant.plant_id%type;
    lv_routeid             route.route_id%type;
    lv_depotid             depot.depot_id%type;
    lv_routestopid         routestop.routestop_id%type;
    lv_deliveryschemeid    deliveryscheme.deliveryscheme_id%type;
    lv_newrouteid          route.route_id%type;
    lv_newdeliveryschemeid deliveryscheme.deliveryscheme_id%type;
    lv_productgroupid      productgroup.productgroup_id%type;
    lv_changestartdate     routechangetransaction.changestartdate%type;
    lv_logmessage  				 abslog.message%type;
    lv_movestopmoveup_idx			number := 0;
    lv_movestopmoveup_table 	MovestopmoveupStopNumberTable;

    procedure add_rct_number(fp_transactionnumber routechangetransaction.transactionnumber%type) is
      idx_rct integer;
    begin
      idx_rct := FP_ROUTECHANGETRANSID_TABLE.count + 1;
      FP_ROUTECHANGETRANSID_TABLE(idx_rct) := fp_transactionnumber;
    end add_rct_number;

    procedure push_movestopmoveup_stopnumber(fp_stopnumber routestop.stopnumber%type) is
    begin
      lv_movestopmoveup_idx := lv_movestopmoveup_idx + 1;
      LV_MOVESTOPMOVEUP_TABLE(lv_movestopmoveup_idx) := fp_stopnumber;
    end push_movestopmoveup_stopnumber;

    procedure pop_movestopmoveup_stopnumber(fp_stopnumber out routestop.stopnumber%type,
      																		  fp_newstopnumber out routestop.stopnumber%type) is
    begin
      fp_stopnumber := LV_MOVESTOPMOVEUP_TABLE(lv_movestopmoveup_idx);
      if (lv_movestopmoveup_idx < LV_MOVESTOPMOVEUP_TABLE.count) then
      	fp_newstopnumber := LV_MOVESTOPMOVEUP_TABLE(lv_movestopmoveup_idx + 1);
      else
				fp_newstopnumber := fp_stopnumber + 10;
      end if;
      lv_movestopmoveup_idx := lv_movestopmoveup_idx - 1;
    end pop_movestopmoveup_stopnumber;

    procedure determine_movestopmoveup(fp_routenumber				in route.routenumber%type,
                                       fp_stopnumber    		in routestop.stopnumber%type)
    is
    lv_plantid         	 plant.plant_id%type;
    lv_routeid         	 route.route_id%type;
    begin
      if (gv_ss_movestopmoveup = 0 or fp_stopnumber = 0) then
        return;
      end if;
      lv_plantid := get_plant_id(fp_plantcode);
      lv_routeid := get_route_id(fp_newroutenumber, fp_newdrivingday, lv_plantid);
      lv_movestopmoveup_idx := 0;
			for RS_FORREC in (
          select RS.routestop_id, RS.stopnumber
          from   ROUTESTOP RS,
          			 ROUTE R
          where  RS.route_id = R.route_id
          and	 R.routenumber = fp_routenumber
          and	 R.route_id = lv_routeid
          and 	 RS.stopnumber >= fp_stopnumber
          and    sysdate between RS.Dateactive and RS.Dateinactive
          order by RS.stopnumber)
      loop
              add_rct_number(5);
          push_movestopmoveup_stopnumber(RS_FORREC.stopnumber);
      end loop;
    end determine_movestopmoveup;

    function move_stop_moveup(fp_plantid          in plant.plant_id%type,
                               fp_drivingdayid		in day.daynumber%type,
                               fp_routeid         in route.route_id%type,
                               fp_routenumber     in route.routenumber%type)
    return number
    is
      lv_customerid     		customer.customer_id%type;
      lv_deliverypointid		deliverypoint.deliverypoint_id%type;
      lv_stopnumber       	routestop.stopnumber%type;
      lv_newstopnumber      routestop.stopnumber%type;
      lv_routestopid				routestop.routestop_id%type;
      lv_routechangetransid	routechangetransaction.routechangetransaction_id%type;

    begin
      pop_movestopmoveup_stopnumber(lv_stopnumber, lv_newstopnumber);
      select 	RS.customer_id,
              RS.deliverypoint_id,
              RS.routestop_id
       into 	lv_customerid,
              lv_deliverypointid,
              lv_routestopid
       from   ROUTESTOP RS
       where  RS.route_id = fp_routeid
       and 		RS.stopnumber = lv_stopnumber
       and    sysdate between RS.Dateactive and RS.Dateinactive;
       lv_routechangetransid := create_routechangetransaction(5, sysdate,
                                                              lv_customerid, lv_deliverypointid,
                                                              fp_plantid, fp_routenumber,
                                                              fp_drivingdayid, null,
                                                              fp_routeid, lv_stopnumber,
                                                              lv_routestopid,
                                                              null,
                                                              null,
                                                              null, null, lv_newstopnumber, null, null,
                                                              '', fp_sortSequence);
			return lv_routechangetransid;
    end move_stop_moveup;

    procedure determine_transaction is
    begin
    --determine_transaction
      gv_message := 'determine_transaction';
      write_log('Calling procedure Pack_Routetransaction.DETERMINE_TRANSACTION...');
      case
        when fp_drivingday is null and fp_routenumber is null and fp_stopnumber is null and
             fp_newroutenumber is not null then
        --add route
          add_rct_number(1);

        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is null and
             fp_newstopnumber is null then
        --change depot
          add_rct_number(2);

        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is null and
             fp_newstopnumber is not null then
        --add route stop
          add_rct_number(3);

        when fp_drivingday is not null and fp_routenumber is not null and fp_stopnumber is not null and
             fp_newstopnumber is null and fp_newdeliveryscheme is null then
        --remove route stop
          add_rct_number(4);

        when (fp_drivingday is not null) and (fp_routenumber is not null) and (fp_stopnumber is not null) and
          (fp_newdrivingday is not null and fp_newroutenumber is not null) and
          (fp_newstopnumber is not null)
        then
          if ((fp_newdrivingday = fp_drivingday) and (fp_newroutenumber = fp_routenumber))
          then
            if (fp_newstopnumber <> fp_stopnumber) then
            --change stop number within route
              add_rct_number(5);
            end if;
            if (fp_newdeliveryscheme is not null) then
            --change deliveryscheme
              add_rct_number(7);
            end if;
          else
          --change stop number(s) when movestopmoveup
            determine_movestopmoveup(fp_newroutenumber, fp_newstopnumber);
          --move stop
            add_rct_number(6);
            if (fp_newdeliveryscheme is not null) then
            --change deliveryscheme
              add_rct_number(7);
            end if;
          end if;
      end case;
    end determine_transaction;

  begin
    --write log
    write_log('Calling procedure Pack_Routetransaction.ADD_ROUTECHANGES...');

    lv_changestartdate := fp_changestartdate;

    --add the RCT Number(s)
    determine_transaction;

    for idx_rct in FP_ROUTECHANGETRANSID_TABLE.first .. FP_ROUTECHANGETRANSID_TABLE.last loop
      lv_transactionnumber := FP_ROUTECHANGETRANSID_TABLE(idx_rct);

    --validate parameters and fill out the next using local parameters
      check_parameters(lv_transactionnumber, lv_changestartdate, fp_customernumber, fp_deliverypointcode,
                       fp_plantcode, fp_drivingday, fp_routenumber, fp_depotcode, fp_stopnumber,
                       fp_oldroutelastdrivingdate, fp_deliveryschemecode, fp_newdrivingday,
                       fp_newroutenumber, fp_newstopnumber, fp_newdeliveryscheme, fp_productgroupcode,
                       lv_customerid, lv_deliverypointid, lv_plantid, lv_routeid, lv_depotid,
                       lv_routestopid, lv_deliveryschemeid, lv_newrouteid, lv_newdeliveryschemeid,
                       lv_productgroupid);

    --create routetransaction
    	if (FP_ROUTECHANGETRANSID_TABLE(idx_rct) = 5 and lv_movestopmoveup_idx > 0) then
	    	lv_routechangetransid := move_stop_moveup(lv_plantid, fp_newdrivingday, lv_newrouteid, fp_newroutenumber);
      else
        lv_routechangetransid := create_routechangetransaction(lv_transactionnumber, lv_changestartdate,
                                                               lv_customerid, lv_deliverypointid,
                                                               lv_plantid, fp_routenumber,
                                                               fp_drivingday, fp_depotcode,
                                                               lv_routeid, fp_stopnumber,
                                                               lv_routestopid,
                                                               fp_oldroutelastdrivingdate,
                                                               lv_deliveryschemeid,
                                                               fp_newdrivingday, fp_newroutenumber,
                                                               fp_newstopnumber, lv_newrouteid,
                                                               lv_newdeliveryschemeid,
                                                               lv_productgroupid, fp_sortSequence);
			end if;
    --replace in table the RCT Number with respective generated ID
      FP_ROUTECHANGETRANSID_TABLE(idx_rct) := lv_routechangetransid;
    end loop;

    --when all is ok
    commit;

    --write log
    lv_logmessage := 'Procedure Pack_Routetransaction.ADD_ROUTECHANGES ran succesfully for transactions: ';
    for idx_rct in FP_ROUTECHANGETRANSID_TABLE.first .. FP_ROUTECHANGETRANSID_TABLE.last loop
      lv_logmessage := lv_logmessage || FP_ROUTECHANGETRANSID_TABLE(idx_rct) || ',';
    end loop;
    write_log(lv_logmessage);

  exception
    when no_data_found then
      begin
        fp_errmsg := 'Addroutechange Error No Data Found ' || gv_message;
        write_log(fp_errmsg, 3);
        rollback;
      end;
    when ge_wrongvalue then
      begin
        fp_errmsg := 'Addroutechange Error Wrong value ' || gv_message;
        write_log(fp_errmsg, 3);
        rollback;
      end;
    when dup_val_on_index then
      begin
        fp_errmsg := 'Addroutechange Error Duplicate Value On Index ' || gv_message;
        write_log(fp_errmsg, 3);
        rollback;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        fp_errmsg := 'Addroutechange Error Others ' || gv_message;
        write_log(fp_errmsg, 3);
        fp_errmsg := fp_errmsg || ' ' || sqlerrm;
        rollback;
      end;
  end add_routechanges;

  procedure onlineroutechange(fp_changestartdate         in routechangetransaction.changestartdate%type,
                              fp_oldroutelastdrivingdate in date,
                              fp_customernumber          in customer.customernumber%type,
                              fp_deliverypointcode       in deliverypoint.code%type,
                              fp_plantcode               in plant.code%type,
                              fp_drivingday              in day.daynumber%type,
                              fp_routenumber             in route.routenumber%type,
                              fp_depotcode               in depot.code%type,
                              fp_stopnumber              in routestop.stopnumber%type,
                              fp_deliveryschemecode      in deliveryscheme.code%type,
                              fp_newdrivingday           in day.daynumber%type,
                              fp_newroutenumber          in route.routenumber%type,
                              fp_newstopnumber           in routestop.stopnumber%type,
                              fp_newdeliveryscheme       in deliveryscheme.code%type,
                              fp_productgroupcode        in productgroup.code%type,
                              fp_sortSequence            in routestop.sortsequence%type,
                              fp_errmsg                  out routechangetransaction.errormsg%type,
                              fp_onlineroutechange       out number,
                              fp_systemuserid            in systemuser.systemuser_id%type default 0)
  is
    LV_ROUTECHANGETRANSID_TABLE  RouteChangeTransactionIdTable;
    lv_errmsg                    routechangetransaction.errormsg%type;
    lv_routechangetransactionrec routechangetransaction%rowtype;

  begin
    --write log
    write_log('Start procedure Pack_Routetransaction.ONLINEROUTECHANGE');
    --initialize systemuser TD21292
    gv_defaultuserid := fp_systemuserid;
    --get System Setting MOVEDELIVEREDSTOP and MOVESTOPMOVEUP
    gv_ss_movedeliveredstop := getssmovedeliveredstop(fp_plantcode);
    gv_ss_movestopmoveup := get_systemsetting(fp_plantcode, 'MOVESTOPMOVEUP');
    gv_ss_directstopchange := get_systemsetting(fp_plantcode, 'DIRECTSTOPCHANGE');

    --add route change
    add_routechanges(fp_changestartdate, fp_oldroutelastdrivingdate, fp_customernumber,
                   fp_deliverypointcode, fp_plantcode, fp_drivingday, fp_routenumber, fp_depotcode,
                   fp_stopnumber, fp_deliveryschemecode, fp_newdrivingday, fp_newroutenumber,
                   fp_newstopnumber, fp_newdeliveryscheme, fp_productgroupcode, fp_sortSequence, lv_errmsg,
                     LV_ROUTECHANGETRANSID_TABLE);
    --check if it went ok
    if (lv_errmsg is not null) or (LV_ROUTECHANGETRANSID_TABLE.count = 0) then
      if (LV_ROUTECHANGETRANSID_TABLE.count = 0) then
        gv_message := 'No any Transaction Number identified to process ...';
        raise no_data_found;
      end if;
    --rollback;
      fp_errmsg            := lv_errmsg;
      fp_onlineroutechange := 0;
      update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id, fp_onlineroutechange, fp_errmsg);
      commit;

		else
      --process transactions
      for idx_rct in LV_ROUTECHANGETRANSID_TABLE.first .. LV_ROUTECHANGETRANSID_TABLE.last loop
        select *
        into   lv_routechangetransactionrec
        from   routechangetransaction rct
        where  rct.routechangetransaction_id = LV_ROUTECHANGETRANSID_TABLE(idx_rct);

        process_1_transaction(lv_routechangetransactionrec);

        --when all is ok
        fp_onlineroutechange := 1;
        update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id, fp_onlineroutechange, null);

        write_log('Procedure Pack_Routetransaction.ONLINEROUTECHANGE processed 1 row for ID = [ '
              ||lv_routechangetransactionrec.routechangetransaction_id||' ].');
      end loop;

      commit;
      write_log('Procedure Pack_Routetransaction.ONLINEROUTECHANGE finished succesfully');
		end if;

  exception
    when no_data_found then
      begin
        gv_message := 'Onlineroutechange Error Others ' || gv_message;
        write_log(gv_message, 3);
        fp_errmsg            := gv_message;
        fp_onlineroutechange := 2;
        rollback;
        update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id,
                                  fp_onlineroutechange, gv_message);
        commit;
      end;
    when ge_general then
      begin
        write_log('Onlineroutechange ' || gv_message, 3);
        fp_errmsg            := gv_message;
        fp_onlineroutechange := 2;
        rollback;
        update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id,
                                  fp_onlineroutechange, gv_message);
        commit;
      end;
    when ge_wrongvalue then
      begin
        gv_message := 'Onlineroutechange Error Wrong value ' || gv_message;
        write_log(gv_message, 3);
        fp_errmsg            := gv_message;
        fp_onlineroutechange := 2;
        rollback;
        update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id,
                                  fp_onlineroutechange, gv_message);
        commit;
      end;
    when dup_val_on_index then
      begin
        gv_message := 'Onlineroutechange Error Duplicate Value On Index ' || gv_message || ' ' ||
                      sqlerrm;
        write_log(gv_message, 3);
        fp_errmsg            := gv_message;
        fp_onlineroutechange := 2;
        rollback;
        update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id,
                                  fp_onlineroutechange, gv_message);
        commit;
      end;
    when others then
      begin
        gv_message := 'Onlineroutechange Error Others ' || sqlerrm || ' ' || gv_message;
        write_log(gv_message, 3);
        fp_errmsg            := gv_message;
        fp_onlineroutechange := 2;
        rollback;
        update_onlineroutechanges(lv_routechangetransactionrec.routechangetransaction_id,
                                  fp_onlineroutechange, gv_message);
        commit;
      end;
  end onlineroutechange;

  procedure cancelroutechange(fp_routechangetransactionid in routechangetransaction.routechangetransaction_id%type,
                              fp_status                   out routechangetransaction.status%type) is
    lv_routechangetransactionid routechangetransaction.routechangetransaction_id%type;
  begin
    --check if exists
    select rct.routechangetransaction_id
    into   lv_routechangetransactionid
    from   routechangetransaction rct
    where  rct.routechangetransaction_id = fp_routechangetransactionid
    and    rct.status <> 1;
    --if exists update
    fp_status := 4;
    update_onlineroutechanges(lv_routechangetransactionid, fp_status,
                              'Canceled routechangetransaction');
    commit;
    write_log('Procedure PACK_ROUTETRANSACTION.cancelroutechange ran succesfully, 1 row cancelled');
  exception
    when no_data_found then
      begin
        write_log('Procedure PACK_ROUTETRANSACTION.cancelroutechange Error RouteChangeTransactionID does not exist!',
                  3);
        fp_status := -1;
        rollback;
      end;
    when others then
      begin
        write_log('Procedure PACK_ROUTETRANSACTION.cancelroutechange Error others ' || sqlerrm, 3);
        fp_status := -1;
        rollback;
      end;
  end cancelroutechange;

begin
  --initialize
  --get system setting parameter for STOPNRUNIQUE
  gv_message := 'get STOPNRUNIQUE';
  select nvl(max(st.value), 0)
  into   gv_stopnrunique
  from   systemsetting st
  where  st.name = 'STOPNRUNIQUE';
  --get DIRECTSTOPCHANGE value
  gv_message := 'get DIRECTSTOPCHANGE';
  select nvl(max(st.value), 0)
  into   gv_ss_directstopchange
  from   systemsetting st
  where  st.name = 'DIRECTSTOPCHANGE';
  --get database code
  select code into gv_databasecode from databasesettings;
end pack_routetransaction;
/
create or replace package PACK_SCAN is

procedure CFbStoreOrCreate (
        FPnSCAN_ID                                in out SCAN.SCAN_ID%type,
        FPnBUSINESSUNIT_ID                        in out SCAN.BUSINESSUNIT_ID%type,
        FPdtSCANTIMESTAMP                         in out SCAN.SCANTIMESTAMP%type,
        FPsPRIMARYID                              in out SCAN.PRIMARYID%type,
        FPnUNIQUEITEM_LINK_ID                     in out SCAN.UNIQUEITEM_LINK_ID%type,
        FPnCUSTOMER_LINK_ID                       in out SCAN.CUSTOMER_LINK_ID%type,
        FPnWEAREREMPLOYMENT_LINK_ID               in out SCAN.WEAREREMPLOYMENT_LINK_ID%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out SCAN.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnPRODUCT_LINK_ID                        in out SCAN.PRODUCT_LINK_ID%type,
        FPnSIZEDEFINITION_LINK_ID                 in out SCAN.SIZEDEFINITION_LINK_ID%type,
        FPnSTAY_ID                                in out SCAN.STAY_ID%type,
        FPnSTATUS_ID                              in out SCAN.STATUS_ID%type,
        FPsSCANSTATION                            in out SCAN.SCANSTATION%type,
        FPdtISSUEDATE                             in out SCAN.ISSUEDATE%type,
        FPnROUTE_ID                               in out SCAN.ROUTE_ID%type,
        FPnREASONCODE_ID                          in out SCAN.REASONCODE_ID%type,
        FPsCUSTOMEROWNED                          in out SCAN.CUSTOMEROWNED%type,
        FPnYEAR                                   in out SCAN.YEAR%type,
        FPnWEEK                                   in out SCAN.WEEK%type,
        FPnDAYNO                                  in out SCAN.DAYNO%type,
        FPnQUALITYGRADE_ID                        in out SCAN.QUALITYGRADE_ID%type,
        FPnPREVSTAY_ID                            in out SCAN.PREVSTAY_ID%type,
        FPnTRANSACTIONTYPE_ID                     in out SCAN.TRANSACTIONTYPE_ID%type,
        FPsSECONDARYID                            in out SCAN.SECONDARYID%type,
        FPnDAYSLATE                               in out SCAN.DAYSLATE%type,
        FPnSYSTEMUSER_ID                          in out SCAN.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out SCAN.TIMESTAMP%type);
procedure CFbGetConversionInformations(
          FPnCUSTOMERNR                           in CUSTOMER.CUSTOMERNUMBER%type,
          FPnDEPARTMENTNR                         in DEPARTMENT.DEPARTMENTNUMBER%type,
          FPnWEARERNR                             in WEARER.WEARERNUMBER%type,
          FPsPRODUCTCODE                          in  PRODUCT.CODE%type,
          FPsSIZEDEFINITIONCODE                   in  SIZEDEFINITION.CODE%type,
          FPnCUSTOMER_ID                          out CUSTOMER.CUSTOMER_ID%type,
          FPnDISTRIBPOINT_ID                      out DISTRIBUTIONPOINT.DISTRIBUTIONPOINT_ID%type,
          FPnWEAREREMPLOYMENT_ID                  out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
          FPnPRODUCT_ID                           out PRODUCT.PRODUCT_ID%type,
          FPnSIZEDEFINITION_ID                    out SIZEDEFINITION.SIZEDEFINITION_ID%type,
          FPnError                                in out int);
end PACK_SCAN;

/
create or replace package body PACK_SCAN is

procedure CFbStoreOrCreate (
        FPnSCAN_ID                                in out SCAN.SCAN_ID%type,
        FPnBUSINESSUNIT_ID                        in out SCAN.BUSINESSUNIT_ID%type,
        FPdtSCANTIMESTAMP                         in out SCAN.SCANTIMESTAMP%type,
        FPsPRIMARYID                              in out SCAN.PRIMARYID%type,
        FPnUNIQUEITEM_LINK_ID                          in out SCAN.UNIQUEITEM_LINK_ID%type,
        FPnCUSTOMER_LINK_ID                       in out SCAN.CUSTOMER_LINK_ID%type,
        FPnWEAREREMPLOYMENT_LINK_ID               in out SCAN.WEAREREMPLOYMENT_LINK_ID%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out SCAN.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnPRODUCT_LINK_ID                        in out SCAN.PRODUCT_LINK_ID%type,
        FPnSIZEDEFINITION_LINK_ID                 in out SCAN.SIZEDEFINITION_LINK_ID%type,
        FPnSTAY_ID                                in out SCAN.STAY_ID%type,
        FPnSTATUS_ID                              in out SCAN.STATUS_ID%type,
        FPsSCANSTATION                            in out SCAN.SCANSTATION%type,
        FPdtISSUEDATE                             in out SCAN.ISSUEDATE%type,
        FPnROUTE_ID                               in out SCAN.ROUTE_ID%type,
        FPnREASONCODE_ID                          in out SCAN.REASONCODE_ID%type,
        FPsCUSTOMEROWNED                          in out SCAN.CUSTOMEROWNED%type,
        FPnYEAR                                   in out SCAN.YEAR%type,
        FPnWEEK                                   in out SCAN.WEEK%type,
        FPnDAYNO                                  in out SCAN.DAYNO%type,
        FPnQUALITYGRADE_ID                        in out SCAN.QUALITYGRADE_ID%type,
        FPnPREVSTAY_ID                            in out SCAN.PREVSTAY_ID%type,
        FPnTRANSACTIONTYPE_ID                     in out SCAN.TRANSACTIONTYPE_ID%type,
        FPsSECONDARYID                            in out SCAN.SECONDARYID%type,
        FPnDAYSLATE                               in out SCAN.DAYSLATE%type,
        FPnSYSTEMUSER_ID                          in out SCAN.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out SCAN.TIMESTAMP%type)
is
begin
  begin
   insert into SCAN(
        SCAN_ID,
        BUSINESSUNIT_ID,
        SCANTIMESTAMP,
        PRIMARYID,
        UNIQUEITEM_LINK_ID,
        CUSTOMER_LINK_ID,
        WEAREREMPLOYMENT_LINK_ID,
        DISTRIBUTIONPOINT_LINK_ID,
        PRODUCT_LINK_ID,
        SIZEDEFINITION_LINK_ID,
        STAY_ID,
        STATUS_ID,
        SCANSTATION,
        ISSUEDATE,
        ROUTE_ID,
        REASONCODE_ID,
        CUSTOMEROWNED,
        YEAR,
        WEEK,
        DAYNO,
        QUALITYGRADE_ID,
        PREVSTAY_ID,
        TRANSACTIONTYPE_ID,
        SECONDARYID,
        DAYSLATE,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        SEQ_SCAN.nextval,
        FPnBUSINESSUNIT_ID,
        FPdtSCANTIMESTAMP,
        FPsPRIMARYID,
        FPnUNIQUEITEM_LINK_ID,
        FPnCUSTOMER_LINK_ID,
        FPnWEAREREMPLOYMENT_LINK_ID,
        FPnDISTRIBUTIONPOINT_LINK_ID,
        FPnPRODUCT_LINK_ID,
        FPnSIZEDEFINITION_LINK_ID,
        FPnSTAY_ID,
        FPnSTATUS_ID,
        FPsSCANSTATION,
        FPdtISSUEDATE,
        FPnROUTE_ID,
        FPnREASONCODE_ID,
        FPsCUSTOMEROWNED,
        FPnYEAR,
        FPnWEEK,
        FPnDAYNO,
        FPnQUALITYGRADE_ID,
        FPnPREVSTAY_ID,
        FPnTRANSACTIONTYPE_ID,
        FPsSECONDARYID,
        FPnDAYSLATE,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
    select SEQ_SCAN.currval into FPnSCAN_ID from dual;
  exception
  	when dup_val_on_index then
	     update SCAN
       set
        BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID,
        SCANTIMESTAMP = FPdtSCANTIMESTAMP,
        PRIMARYID = FPsPRIMARYID,
        UNIQUEITEM_LINK_ID = FPnUNIQUEITEM_LINK_ID,
        CUSTOMER_LINK_ID = FPnCUSTOMER_LINK_ID,
        WEAREREMPLOYMENT_LINK_ID = FPnWEAREREMPLOYMENT_LINK_ID,
        DISTRIBUTIONPOINT_LINK_ID = FPnDISTRIBUTIONPOINT_LINK_ID,
        PRODUCT_LINK_ID = FPnPRODUCT_LINK_ID,
        SIZEDEFINITION_LINK_ID = FPnSIZEDEFINITION_LINK_ID,
        STAY_ID = FPnSTAY_ID,
        STATUS_ID = FPnSTATUS_ID,
        SCANSTATION = FPsSCANSTATION,
        ISSUEDATE = FPdtISSUEDATE,
        ROUTE_ID = FPnROUTE_ID,
        REASONCODE_ID = FPnREASONCODE_ID,
        CUSTOMEROWNED = FPsCUSTOMEROWNED,
        YEAR = FPnYEAR,
        WEEK = FPnWEEK,
        DAYNO = FPnDAYNO,
        QUALITYGRADE_ID = FPnQUALITYGRADE_ID,
        PREVSTAY_ID = FPnPREVSTAY_ID,
        TRANSACTIONTYPE_ID = FPnTRANSACTIONTYPE_ID,
        SECONDARYID = FPsSECONDARYID,
        DAYSLATE = FPnDAYSLATE,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
      where BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID and
            PRIMARYID = FPsPRIMARYID and
            SCANTIMESTAMP = FPdtSCANTIMESTAMP;
		-- get ID
		select SCAN_ID
			into FPnSCAN_ID
			from SCAN
			where BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID and
            PRIMARYID = FPsPRIMARYID and
            SCANTIMESTAMP = FPdtSCANTIMESTAMP;
  end;
end;
procedure CFbGetConversionInformations(
          FPnCUSTOMERNR                           in CUSTOMER.CUSTOMERNUMBER%type,
          FPnDEPARTMENTNR                         in DEPARTMENT.DEPARTMENTNUMBER%type,
          FPnWEARERNR                             in WEARER.WEARERNUMBER%type,
          FPsPRODUCTCODE                          in  PRODUCT.CODE%type,
          FPsSIZEDEFINITIONCODE                   in  SIZEDEFINITION.CODE%type,
          FPnCUSTOMER_ID                          out CUSTOMER.CUSTOMER_ID%type,
          FPnDISTRIBPOINT_ID                      out DISTRIBUTIONPOINT.DISTRIBUTIONPOINT_ID%type,
          FPnWEAREREMPLOYMENT_ID                  out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
          FPnPRODUCT_ID                           out PRODUCT.PRODUCT_ID%type,
          FPnSIZEDEFINITION_ID                    out SIZEDEFINITION.SIZEDEFINITION_ID%type,
          FPnError                                in out int)is
FPnWEARER_ID long;
begin
  FPnError := 1;
  select CUSTOMER_ID
  into FPnCUSTOMER_ID
  from CUSTOMER
  where CUSTOMERNUMBER = FPnCUSTOMERNR;

  FPnError := 2;
  select DP.DISTRIBUTIONPOINT_ID
  into FPnDISTRIBPOINT_ID
  from DEPARTMENT D,DISTRIBUTIONPOINT DP
  where D.CUSTOMER_ID = FPnCUSTOMER_ID AND D.DEPARTMENTNUMBER = FPnDEPARTMENTNR AND
        DP.DEPARTMENT_ID = D.DEPARTMENT_ID;

  FPnError := 3;
  select PRODUCT_ID
  into FPnPRODUCT_ID
  from PRODUCT
  where LEGACYPRODUCTCODE = FPsPRODUCTCODE and MODEL = 'Y';

  FPnError := 4;
  select SIZEDEFINITION_ID
  into FPnSIZEDEFINITION_ID
  from SIZEDEFINITION
  where CODE = FPsSIZEDEFINITIONCODE;

  FPnError := 5;
  select WEARER_ID
  into FPnWEARER_ID
  from WEARER
  where WEARERNUMBER = FPnWEARERNR AND CUSTOMER_ID = FPnCUSTOMER_ID;

  FPnError := 6;
  select we.weareremployment_id
  into FPnWEAREREMPLOYMENT_ID
	from weareremployment we,wearerinventory wi
  where we.wearer_id = FPnWEARER_ID and
  we.weareremployment_id = wi.weareremployment_id and
  wi.product_id = FPnPRODUCT_ID and wi.sizedefinition_id = FPnSIZEDEFINITION_ID;
exception
  when no_data_found then null;
  when others then raise;

end;

end PACK_SCAN;

/
create or replace PACKAGE PACK_SCANFLAG is

procedure CFbStoreOrCreate (
        FPnSCAN_ID                                in out SCANFLAG.SCAN_ID%type,
        FPnFLAG_ID                                in out SCANFLAG.FLAG_ID%type,
        FPsFLAGRESPONSE                           in out SCANFLAG.FLAGRESPONSE%type,
        FPnSYSTEMUSER_ID                          in out SCANFLAG.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out SCANFLAG.TIMESTAMP%type);

end PACK_SCANFLAG;

/
create or replace PACKAGE BODY PACK_SCANFLAG is

procedure CFbStoreOrCreate (
        FPnSCAN_ID                                in out SCANFLAG.SCAN_ID%type,
        FPnFLAG_ID                                in out SCANFLAG.FLAG_ID%type,
        FPsFLAGRESPONSE                           in out SCANFLAG.FLAGRESPONSE%type,
        FPnSYSTEMUSER_ID                          in out SCANFLAG.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out SCANFLAG.TIMESTAMP%type)
is
begin
  begin
     insert into SCANFLAG(
        SCAN_ID,
        FLAG_ID,
        FLAGRESPONSE,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        FPnSCAN_ID,
        FPnFLAG_ID,
        FPsFLAGRESPONSE,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
  exception
  	when dup_val_on_index then
	  update SCANFLAG
    set
        SCAN_ID = FPnSCAN_ID,
        FLAG_ID = FPnFLAG_ID,
        FLAGRESPONSE = FPsFLAGRESPONSE,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where SCAN_ID = FPnSCAN_ID and FLAG_ID = FPnFLAG_ID;
  end;
end;

end PACK_SCANFLAG;

/
create or replace package pack_scrutiny is
  -- Updated : 29-09-2020 DLA ABS-108518 Delivery variations processbusinessunit_id and internalprocessingbu_id are not filled when creating DV from Pack_multiread

PRAGMA SERIALLY_REUSABLE;
  -- Author  : MONICA.B
  -- Created : 7/15/2013 2:24:29 PM
  -- Purpose : Scrutiny process

  -- Public type declarations
  --type stop_ids_array is TABLE OF NUMBER INDEX BY BINARY_INTEGER;

  -- Public constant declarations
  --<ConstantName> constant <Datatype> := <Value>;

  -- Public variable declarations
  --<VariableName> <Datatype>;

  -- Public function and procedure declarations
PROCEDURE scrutinyProcess(plantId plant.plant_id%type,
                            stopIds numbers_array,
                            plantprocessId plantprocess.plantprocess_id%type,
                            dialogId dialogs.dialog_id%type,
                            abslogprocessjobId in out abslogprocessjob.abslogprocessjob_id%type,
                            languageId languages.language_id%type,
                            systemuserId systemuser.systemuser_id%type,
                            workstationId workstation.workstation_id%type);
end pack_scrutiny;
/
create or replace package body pack_scrutiny is
PRAGMA SERIALLY_REUSABLE;
  -- Private type declarations
  gv_userexception           exception;
  --type stop_ids_array is TABLE OF NUMBER INDEX BY BINARY_INTEGER;

  -- Private constant declarations
  RETURN_OK CONSTANT INTEGER := 0;
  RETURN_FAILED_UNKNOWN CONSTANT INTEGER := -1;

  PRIORITY_MESSAGE CONSTANT abslogprocessjobline.priority%TYPE := 1;
  --PRIORITY_WARNING CONSTANT abslogprocessjobline.priority%TYPE := 2;
  PRIORITY_ERROR CONSTANT abslogprocessjobline.priority%TYPE := 3;
  PRIORITY_DEBUG CONSTANT abslogprocessjobline.priority%TYPE := 5;

  -- Private variable declarations
  gv_processname              abslogprocessjobpart.processname%type;
  gv_systemuserid             systemuser.systemuser_id%type := 0;
  gv_workstationid            workstation.workstation_id%type := 0;
  gv_abslogprocessjobid       abslogprocessjob.abslogprocessjob_id%type;
  gv_abslogprocessjobpartid   abslogprocessjobpart.abslogprocessjobpart_id%type;
  gv_message                  abslog.message%type;
  gv_returnvalue              number := RETURN_OK;
  gv_plantid                  plant.plant_id%type;
  gv_approvedstops            number;
  gv_notapplicablestops       number;
  gv_notapprovedstops         number;
  gv_approvedroutecontrols    number;
  gv_notapprovedroutecontrols number;
  gv_totalroutecontrols       number;
  gv_checkResult              number;
  gv_StopNotApproved          boolean;

  -- Function and procedure implementations
  procedure write_log_line(fp_message        in abslogprocessjobline.message%type,
                            fp_routenumber    in route.routenumber%type default null,
                            fp_drivingdate    in routecontrol.drivingdate%type default null,
                            fp_stopnumber     in stop.stopnumber%type default null,
                            fp_customernumber in customer.customernumber%type default null) is
  lv_message varchar2(1000) := fp_message;
  begin
    if (fp_routenumber is not null) then
      lv_message := rpad(fp_routenumber, 10) || rpad(nvl(to_char(fp_drivingdate, 'dd-mm-yyyy'), ' '), 12)
                    || rpad(nvl(to_char(fp_stopnumber), ' '), 12) || rpad(nvl(to_char(fp_customernumber), ' '), 15) || fp_message;
    end if;

    IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);
    END IF;
  exception
    when others then
      begin
        dbms_output.put_line(fp_message);
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := RETURN_FAILED_UNKNOWN;
        raise gv_userexception;
      end;
  end write_log_line;

  procedure write_log_header is
  lv_message varchar2(1000);
  lv_workstation varchar2(45);
  lv_systemuser varchar2(20);
  begin
    if (nvl(gv_workstationid, 0) <> 0) then
       select (w.code || ' ' || w.description) into lv_workstation from workstation w where w.workstation_id = gv_workstationid;
    end if;
    if (nvl(gv_systemuserid, 0) <> 0) then
       select s.username into lv_systemuser from systemuser s where s.systemuser_id = gv_systemuserid;
    end if;

    IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
       lv_message := rpad('Process:', 13) || 'Scrutiny';
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Started:', 13) || to_char(sysdate, 'dd-mm-yyyy hh:mi:ss');
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Workstation:', 13) || lv_workstation;
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Systemuser:', 13) || lv_systemuser;
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Route', 10) || rpad('Driving Date', 12) || rpad('Stop', 12) || rpad('Customer', 15) || 'Message';
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('-', 150, '-');
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);
    END IF;
  exception
    when others then
      begin
        dbms_output.put_line('Scrutinity process - log header');
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := RETURN_FAILED_UNKNOWN;
        raise gv_userexception;
      end;
  end write_log_header;

  procedure write_log_footer is
  lv_message varchar2(1000);
  begin
    IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
       lv_message := rpad('-', 150, '-');
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Total Stops:', 14) || rpad(gv_approvedstops + gv_notapplicablestops + gv_notapprovedstops, 6) ||
       ' Approved: ' || rpad(gv_approvedstops, 6) || ' Not applicable: ' || rpad(gv_notapplicablestops, 6) ||
       ' Not approved: ' || rpad(gv_notapprovedstops, 6);
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Total Routes:', 14) || rpad(gv_totalroutecontrols, 6) || ' Approved: ' || rpad(gv_approvedroutecontrols, 6) ||
       rpad(' ', 23) || ' Not approved: ' || rpad(gv_notapprovedroutecontrols, 6);
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);

       lv_message := rpad('Finished:', 14) || to_char(sysdate, 'dd-mm-yyyy hh:mi:ss');
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, lv_message, gv_systemuserid);
    END IF;
  exception
    when others then
      begin
        dbms_output.put_line('Scrutinity process - log footer');
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := RETURN_FAILED_UNKNOWN;
        raise gv_userexception;
      end;
  end write_log_footer;

  procedure end_log is
  begin
    --end_log
    if gv_abslogprocessjobid is not null then
      abslogwrite.abslogprocessjob_update(gv_abslogprocessjobid, sysdate, gv_systemuserid);
      gv_abslogprocessjobid := NULL;
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(gv_message);
        dbms_output.put_line(sqlerrm);
      end;
  end end_log;

  procedure get_abslogprocessjobid(fp_plantprocessid in plantprocess.plantprocess_id%type,
                                   fp_plantid IN plant.plant_id%TYPE) is
  begin
    --write_log
    gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(fp_plantid, sysdate, null, null,
                                                                fp_plantprocessid, gv_systemuserid);
  end get_abslogprocessjobid;

  function get_systemsetting(fp_systemsettingname systemsetting.name%type,
                             fp_plant_id systemsetting.plant_id%TYPE) return NUMBER is
  lv_value NUMBER;
  begin
    --get_systemsetting
    gv_message := 'Error getting System Setting ' || fp_systemsettingname;
    select to_number( nvl(ss.value, ss.factorydefault) )
    into   lv_value
    from   systemsetting ss
    where  ss.plant_id = fp_plant_id
    and    ss.name = fp_systemsettingname;
    return lv_value;
  exception
    when others then
       raise_application_error( -20001, gv_message);
  end get_systemsetting;

  -- Check 1: Check if Customer is excluded from Scrutiny
  function check1(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    for x in (select s.status,
                     s.scrutinystatus,
                     c.scrutinyexcludecheckbags,
                     c.scrutinyexcludecheckdv,
                     r.routenumber,
                     rc.drivingdate,
                     s.stopnumber,
                     c.customernumber
                from stop s, customer c, routecontrol rc, route r
               where c.customer_id = s.customer_link_id
                 and s.routecontrol_id = rc.routecontrol_id
                 and rc.route_id = r.route_id
                 and s.stop_id = stopId) loop
      if (x.status = 1 or x.status = 2 or (x.scrutinyexcludecheckdv = 1)) then
        update stop s set s.scrutinystatus = 10 where s.stop_id = stopId;
        lv_result := 1;
        gv_notapplicablestops := gv_notapplicablestops + 1;
        gv_message := 'Stop is set to Not Applicable. Customer is excluded from scrutiny check DV.';
        write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);

        for y in (select dv.deliveryvariations_id
                from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId) loop
          update deliveryvariations dv set dv.scrutinystatus = 10 where dv.deliveryvariations_id = y.deliveryvariations_id;
        end loop;
      end if;
    end loop;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check1: ' ||sqlerrm;
  end check1;

  -- Check 2: Check if all unloaded Bags are sorted
  function check2(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    for x in (select distinct r.routenumber,
                              rc.drivingdate,
                              s.stopnumber,
                              c.customernumber
                from bagtag bt, stop s, customer c, routecontrol rc, route r
                             where bt.stop_id = s.stop_id
                 and bt.stay_id <> (select st.stay_id
                                      from stay st
                                     where st.staytype = 6
                                       and st.staynr = 70)
                 and s.routecontrol_id = rc.routecontrol_id
                 and rc.route_id = r.route_id
                 and s.customer_link_id = c.customer_id
                 and s.stop_id = stopId) loop
      update stop s set s.scrutinystatus = 20 where s.stop_id = stopId;
      update routecontrol rc set rc.scrutinystatus = 20 where rc.routecontrol_id = (select s.routecontrol_id from stop s where s.stop_id = stopId);
      lv_result := 1;
      gv_notapprovedstops := gv_notapprovedstops + 1;
      gv_StopNotApproved := true;
      gv_message := 'Stop is set to Not Approved (soil receiving), not all bags are soil counted.';
      write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
    end loop;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check2: ' || sqlerrm;
  end check2;

  -- Check 3: Nominal Stock is below a predefined quantity
  function check3(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  lv_minimumnominal number := 0;
  begin
    for x in (select plpd.product_id,
                     sum(rqa.quantity) rqa_qty,
                     nvl((select ca.processbusinessunit_id
                           from customeractivities ca, productgroup pg, product p
                          where ca.customer_id = c.customer_id
                            and ca.activity_id = pg.activity_id
                            and pg.productgroup_id = p.productgroup_id
                            and p.product_id = plpd.product_id
                            and rownum = 1),
                         c.defaultbusinessunit_id) bu,
                     r.routenumber,
                     rc.drivingdate,
                     s.stopnumber,
                     c.customernumber,
                     c.customer_id
                from rentalqtyadjustment        rqa,
                     productlistperdistribpoint plpd,
                     distributionpoint          dp,
                     department                 d,
                     stop                       s,
                     routecontrol               rc,
                     route                      r,
                     customer                   c
               where rqa.productlistperdistribpoint_id =
                     plpd.productlistperdistribpoint_id
                 and plpd.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and s.routecontrol_id = rc.routecontrol_id
                 and rc.route_id = r.route_id
                 and c.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and rqa.adjustmentdate <= rc.drivingdate
                 and rqa.origin <> 2
                 and s.stop_id = stopId
               group by plpd.product_id,
                        c.customer_id,
                        c.defaultbusinessunit_id,
                        r.routenumber,
                        rc.drivingdate,
                        s.stopnumber,
                        c.customernumber) loop
      begin
        select nvl(smn.minimumnominal, 0) into lv_minimumnominal from scrutinyminnominal smn where smn.businessunit_id = x.bu
             and smn.deliveriesperweek = (select count(1) from customerdeliveryday cdd where cdd.customer_id = x.customer_id);
      exception
        when no_data_found then null;
      end;

      if (lv_minimumnominal = 0) then
        select ('Minimum Nominal not defined for business unit ' || bu.code) into gv_message from businessunit bu where bu.businessunit_id = x.bu;
        write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
        exit;
      elsif (x.rqa_qty < lv_minimumnominal) then
        update deliveryvariations dv1 set dv1.scrutinystatus = 10
               where dv1.deliveryvariations_id in
               (select dv.deliveryvariations_id
                  from deliveryvariations dv, distributionpoint dp, department d, stop s
                 where dv.distributionpoint_id = dp.distributionpoint_id
                   and dp.department_id = d.department_id
                   and d.customer_id = s.customer_link_id
                   and (nvl(s.routestop_id, 0) = 0 or
                       (select nvl(rs.deliverypoint_id, 0)
                           from routestop rs
                          where rs.routestop_id = s.routestop_id) = 0 or
                       (select nvl(rs.deliverypoint_id, 0)
                           from routestop rs
                          where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                   and dv.deliverydate <= x.drivingdate
                   and dv.processed = 'N'
                   and dv.product_id = x.product_id
                   and dv.scrutinystatus = 11
                   and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
                   and d.customer_id = x.customer_id);

      end if;
    end loop;

    for x in (select sum(case
                         when dv.scrutinystatus <> 10 then 1
                         else 0
                       end) dvno,
                   r.routenumber,
                   rc.drivingdate,
                   s.stopnumber,
                   c.customernumber
              from deliveryvariations dv,
                   distributionpoint  dp,
                   department         d,
                   stop               s,
                   routecontrol       rc,
                   route              r,
                   customer           c
             where dv.distributionpoint_id = dp.distributionpoint_id
               and dp.department_id = d.department_id
               and d.customer_id = s.customer_link_id
               and (nvl(s.routestop_id, 0) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
               and dv.deliverydate <= rc.drivingdate
               and dv.processed = 'N'
               and s.routecontrol_id = rc.routecontrol_id
               and rc.route_id = r.route_id
               and c.customer_id = s.customer_link_id
               and s.stop_id = stopId
             group by r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
            ) loop
      if (x.dvno = 0) then -- if all products are not applicable - stop is approved
          update stop s set s.scrutinystatus = 30 where s.stop_id = stopId;
          lv_result := 1;
          gv_approvedstops := gv_approvedstops + 1;
          gv_message := 'Stop is set to Approved because of minimum order.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end if;
    end loop;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check3: ' || sqlerrm;
  end check3;

  -- Check 4: Negative Delivery Variation Lines
  function check4(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    gv_message := '';
    for x in (select dv.deliveryvariations_id, dv.deliverydate, rc.drivingdate, s.stopnumber
                from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc, reasoncode res
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 -- and dv.origin = 3
                 and dv.amount < 0
                 and dv.scrutinystatus = 11
                 and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId
                 and (nvl(dv.reasoncode_id, 0) = 0 or
                     (select res.excludescrutinycheck from reasoncode res where res.reasoncode_id = dv.reasoncode_id) <> 'Y')) loop
      update deliveryvariations dv set dv.scrutinystatus = 21 where dv.deliveryvariations_id = x.deliveryvariations_id;
         lv_result := 1;
    end loop;

    if (lv_result = 1) then
      for x in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                  from stop s, routecontrol rc, route r, customer c
                 where s.routecontrol_id = rc.routecontrol_id
                   and rc.route_id = r.route_id
                   and c.customer_id = s.customer_link_id
                   and s.stop_id = stopId) loop
            update stop s set s.scrutinystatus = 21 where s.stop_id = stopId;
            if not(gv_StopNotApproved) then
               gv_notapprovedstops := gv_notapprovedstops + 1;
               gv_StopNotApproved := true;
            end if;
            gv_message := 'Stop is set to Not Approved because of negative delivery variations.';
            write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end loop;
    end if;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check4: ' || sqlerrm;
  end check4;

  -- Check 5: Delivery Variation with Reason Code Exclude from Scrutiny
  function check5(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    for x in (select dv.deliveryvariations_id
                from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc, reasoncode res
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 and dv.scrutinystatus = 11
                 and dv.reasoncode_id = res.reasoncode_id
                 and res.excludescrutinycheck = 'Y'
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId) loop
      update deliveryvariations dv set dv.scrutinystatus = 10 where dv.deliveryvariations_id = x.deliveryvariations_id;
    end loop;

    for x in (select sum(case
                         when dv.scrutinystatus <> 10 then 1
                         else 0
                       end) dvno,
                   r.routenumber,
                   rc.drivingdate,
                   s.stopnumber,
                   c.customernumber
              from deliveryvariations dv,
                   distributionpoint  dp,
                   department         d,
                   stop               s,
                   routecontrol       rc,
                   route              r,
                   customer           c
             where dv.distributionpoint_id = dp.distributionpoint_id
               and dp.department_id = d.department_id
               and d.customer_id = s.customer_link_id
               and (nvl(s.routestop_id, 0) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
               and dv.deliverydate <= rc.drivingdate
               and dv.processed = 'N'
               and s.routecontrol_id = rc.routecontrol_id
               and rc.route_id = r.route_id
               and c.customer_id = s.customer_link_id
               and s.stop_id = stopId
             group by r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
            ) loop
      if (x.dvno = 0) then -- if all products are not applicable - stop is approved
          update stop s set s.scrutinystatus = 30 where s.stop_id = stopId;
          lv_result := 1;
          gv_approvedstops := gv_approvedstops + 1;
          gv_message := 'Stop is set to Approved because of Reason Code Exclude from Scrutiny.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end if;
    end loop;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check5: ' || sqlerrm;
  end check5;

  -- Check 6: Missing Products
  function check6(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  dvId number;
  dvAmount number;
  m_nominal number;
  existsDV number;
  businessunitid businessunit.businessunit_id%type;

  begin
    for x in (select sd.distributionpoint_id,
                   plpd.product_id,
                   plpd.sizedefinition_id,
                   plpd.finishingmethod_id,
                   rc.drivingdate,
                   s.stopnumber,
                   (select p.code from product p where p.product_id = plpd.product_id) prod,
                   (select sd.code from sizedefinition sd where sd.sizedefinition_id = plpd.sizedefinition_id) sz
              from standarddelivery           sd,
                   standarddeliveryline       sdl,
                   standarddeliveryamount     sda,
                   distributionpoint          dp,
                   department                 d,
                   stop                       s,
                   routecontrol               rc,
                   productlistperdistribpoint plpd,
                   productlistpercustomer     plpc
             where sd.standarddelivery_id = sdl.standarddelivery_id
               and sdl.standarddeliveryline_id = sda.standarddeliveryline_id
               and sd.distributionpoint_id = dp.distributionpoint_id
               and dp.department_id = d.department_id
               and d.customer_id = s.customer_link_id
               and (nvl(s.routestop_id, 0) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
               and sdl.dateactive <= rc.drivingdate
               and sdl.dateinactive > rc.drivingdate
               and sda.day_id = GETABSDAYNUMBER(rc.drivingdate)
               and sdl.productlistperdistribpoint_id =
                   plpd.productlistperdistribpoint_id
               and s.routecontrol_id = rc.routecontrol_id
               and s.stop_id = stopId
               and plpc.customer_id = s.customer_link_id
               and plpc.product_id = plpd.product_id
               and plpc.finishingmethod_id = plpd.finishingmethod_id
               and ((plpc.sizedefinition_id = plpd.sizedefinition_id) or
                   (plpc.sizedefinition_id = (select sz.sizedefinition_id from sizedefinition sz where sz.code = '*')))
               and plpc.soilcountmethod <> 0) loop
      begin
        gv_message := '';
        m_nominal := 0;
          begin
            select sum(rqa.quantity) into m_nominal
            from rentalqtyadjustment rqa, productlistperdistribpoint plpd
            where rqa.productlistperdistribpoint_id = plpd.productlistperdistribpoint_id
             and plpd.distributionpoint_id = x.distributionpoint_id
             and plpd.product_id = x.product_id
             and plpd.sizedefinition_id = x.sizedefinition_id
             and plpd.finishingmethod_id = x.finishingmethod_id
             and rqa.adjustmentdate <= x.drivingdate
             and rqa.origin <> 2;
          exception
           when no_data_found then null;
          end;

       if (m_nominal <> 0) then
           existsDV := 0;
           for y in
              (select dv.deliveryvariations_id dvId, dv.amount dvAmount, dv.scrutinystatus, dv.deliverydate, (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) isDryClean
                from deliveryvariations dv
               where dv.distributionpoint_id = x.distributionpoint_id
                 and dv.product_id = x.product_id
                 and dv.sizedefinition_id = x.sizedefinition_id
                 and dv.finishingmethod_id = x.finishingmethod_id
                 and dv.deliverydate = x.drivingdate
                 and dv.origin = 1
                 and dv.amount >= 0) loop
             existsDV := 1;
             if (y.dvAmount = 0 and y.scrutinystatus <> 10 and y.isdryclean <> 1) then -- if DV is not applicable or is a dry clean - do nothing
               update deliveryvariations dv set dv.scrutinystatus = 21 where dv.deliveryvariations_id = y.dvId;
               gv_message := 'Delivery variation set to Not Approved because of missing product (' || x.prod || '/' || x.sz || ') for stop: ' || x.stopnumber || ', on date: ' || to_char(y.deliverydate, 'dd Mon yyyy');
               write_log_line(gv_message);
                 lv_result := 1;
             end if;
           end loop;

          if (existsDV != 1) then
            select ca.processbusinessunit_id into businessunitid
            from customeractivities ca join department dt on ca.customer_id = dt.customer_id
                 join distributionpoint dp on dt.department_id = dp.department_id
                 join productgroup pg on ca.activity_id = pg.activity_id
                 join product p on p.productgroup_id = pg.productgroup_id
                 join businessunit bu on ca.processbusinessunit_id = bu.businessunit_id
            where dp.distributionpoint_id = x.distributionpoint_id
            and p.product_id = x.product_id
            and bu.plant_id = gv_plantid;
            insert into deliveryvariations(deliveryvariations_id, distributionpoint_id, product_id, sizedefinition_id, finishingmethod_id,
                                            deliverydate, origin, soilcountsubtype, amount, reference, updaterentqty, fixedamount,
                                            processed, scrutinystatus, systemuser_id, timestamp, processbusinessunit_id, internalprocessingbu_id)
                        values(seq_deliveryvariations.nextval, x.distributionpoint_id, x.product_id, x.sizedefinition_id,
                               x.finishingmethod_id, x.drivingdate, 1, 1, 0, 'Scrutiny', 'N', 'N', 'N', 21, gv_systemuserid, sysdate, businessunitid, businessunitid);
            gv_message := 'Delivery variation created because of missing product (' || x.prod || '/' || x.sz || ') for stop: ' || x.stopnumber || ', on date: ' || to_char(x.drivingdate, 'dd Mon yyyy');
            write_log_line(gv_message);
            lv_result := 1;
          end if;
      end if;
     end;
    end loop;

    if (lv_result = 1) then
      for x in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                  from stop s, routecontrol rc, route r, customer c
                 where s.routecontrol_id = rc.routecontrol_id
                   and rc.route_id = r.route_id
                   and c.customer_id = s.customer_link_id
                   and s.stop_id = stopId) loop
          update stop s set s.scrutinystatus = 21 where s.stop_id = stopId;
          if not(gv_StopNotApproved) then
             gv_notapprovedstops := gv_notapprovedstops + 1;
             gv_StopNotApproved := true;
          end if;
          gv_message := 'Stop is set to Not Approved because of missing products.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end loop;
    end if;

    return lv_result;
  exception
    when others then
      gv_message := 'Error in check6: ' || sqlerrm;
  end check6;

  -- Check 7-8: Average and Deviation and Nominal
  function check7_8(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  ss_weekavgcalcper number;
  ss_soildeviationsoilpercpos number;
  ss_soildeviationsoilpercneg number;
  m_delivery numbers_array;
  lv_delNo number := 0;
  m_average number := 0;
  m_quantity number := 0;
  lv_totalDel number := 0;
  m_nominal number := 0;
  begin
    ss_weekavgcalcper := get_systemsetting('WEEKAVGCALCPER', gv_plantid);
    ss_soildeviationsoilpercpos := get_systemsetting('SOILDEVIATIONSOILPERCPOS', gv_plantid);
    ss_soildeviationsoilpercneg := get_systemsetting('SOILDEVIATIONSOILPERCNEG', gv_plantid);
    for x in (select dv.distributionpoint_id,
                     dv.product_id,
                     dv.sizedefinition_id,
                     dv.finishingmethod_id,
                     rc.drivingdate,
                     s.stopnumber,
                     nvl(sum(dv.amount), 0) amount
                from deliveryvariations dv,
                     distributionpoint  dp,
                     department         d,
                     stop               s,
                     routecontrol       rc
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 and dv.scrutinystatus = 11
                 and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
                 and dv.origin = 1
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId
               group by dv.distributionpoint_id,
                        dv.product_id,
                        dv.sizedefinition_id,
                        dv.finishingmethod_id,
                        rc.drivingdate,
                        s.stopnumber) loop
      m_quantity := x.amount;

      -- calculate m_delivery / m_average
      select /*+index(PNL XAK2PACKINGNOTELINE) */ sum(pnl.deliveredamount) bulk collect into m_delivery
        from packingnote pn, packingnoteline pnl, routecontrol rc, route r
       where pn.packingnote_id = pnl.packingnote_id
         and pn.distributionpoint_id = x.distributionpoint_id
         and pnl.product_id = x.product_id
         and pnl.sizedefinition_id = x.sizedefinition_id
         and pnl.finishingmethod_id = x.finishingmethod_id
         and pn.routecontrol_id = rc.routecontrol_id
         and rc.drivingdate < x.drivingdate
         and pn.route_id = r.route_id
         and r.drivingday_id = GETABSDAYNUMBER(x.drivingdate)
         and PN.DELIVERYDATE between (getdateforweekyear(GETABSDAYNUMBER(x.drivingdate), getisoweek(sysdate), year(sysdate)) - 7 * ss_weekavgcalcper)
                                      and (getdateforweekyear(GETABSDAYNUMBER(x.drivingdate), getisoweek(sysdate), year(sysdate)))
       group by pn.deliverydate
       order by pn.deliverydate desc;

       lv_delNo := 0;
       lv_totalDel := 0;
       for y in 1..m_delivery.count loop
         lv_delNo := lv_delNo + 1;
         lv_totalDel := lv_totalDel + m_delivery(y);
       end loop;

       if (lv_delNo != 0) then
          m_average := round(lv_totalDel/lv_delNo);
       else
          m_average := 0;
       end if;

       -- calculate m_nominal
       select nvl(sum(rqa.quantity), 0) into m_nominal
          from rentalqtyadjustment rqa, productlistperdistribpoint plpd
        where rqa.productlistperdistribpoint_id = plpd.productlistperdistribpoint_id
           and plpd.distributionpoint_id = x.distributionpoint_id
           and plpd.product_id = x.product_id
           and plpd.sizedefinition_id = x.sizedefinition_id
           and plpd.finishingmethod_id = x.finishingmethod_id
           and rqa.adjustmentdate <= x.drivingdate
           and rqa.origin <> 2;

       gv_message := '';

       if (m_average = 0
        or ((m_average > m_quantity) and (round(((m_average - m_quantity) / m_average)*100) > ss_soildeviationsoilpercpos))
        or ((m_average <= m_quantity) and (round(((m_quantity - m_average) / m_average)*100) > ss_soildeviationsoilpercneg))
        or (m_quantity > m_nominal)) then -- update DV
         for y in (select dv.deliveryvariations_id, dv.deliverydate
                    from deliveryvariations dv,
                         distributionpoint  dp,
                         department         d,
                         stop               s,
                         routecontrol       rc
                   where dv.distributionpoint_id = dp.distributionpoint_id
                     and dp.department_id = d.department_id
                     and d.customer_id = s.customer_link_id
                     and (nvl(s.routestop_id, 0) = 0 or
                         (select nvl(rs.deliverypoint_id, 0)
                             from routestop rs
                            where rs.routestop_id = s.routestop_id) = 0 or
                         (select nvl(rs.deliverypoint_id, 0)
                             from routestop rs
                            where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                     and dv.deliverydate <= rc.drivingdate
                     and dv.processed = 'N'
                     and dv.scrutinystatus = 11
                     and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
                     and dv.origin = 1
                     and s.routecontrol_id = rc.routecontrol_id
                     and s.stop_id = stopId) loop
           update deliveryvariations dv set dv.scrutinystatus = 21 where dv.deliveryvariations_id = y.deliveryvariations_id;
              lv_result := 1;
         end loop;
       end if;
    end loop;

    if (lv_result = 1) then
      for x in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                  from stop s, routecontrol rc, route r, customer c
                 where s.routecontrol_id = rc.routecontrol_id
                   and rc.route_id = r.route_id
                   and c.customer_id = s.customer_link_id
                   and s.stop_id = stopId) loop
          update stop s set s.scrutinystatus = 21 where s.stop_id = stopId;
          if not(gv_StopNotApproved) then
             gv_notapprovedstops := gv_notapprovedstops + 1;
             gv_StopNotApproved := true;
          end if;
          gv_message := 'Stop is set to Not Approved because of deviation from average.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end loop;
    end if;
    return lv_result;

  exception
    when others then
      gv_message := 'Error in check7_8: ' || sqlerrm;
  end check7_8;

  -- Check 9: Dry Cleaning
  function check9(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    gv_message := '';
    for x in (select dv.deliveryvariations_id, dv.deliverydate, rc.drivingdate, s.stopnumber
                from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc, finishingmethod fm
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 and dv.scrutinystatus = 11
                 and dv.finishingmethod_id = fm.finishingmethod_id
                 and fm.washtype = 1
                 and dv.reference is null
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId) loop
      update deliveryvariations dv set dv.scrutinystatus = 21 where dv.deliveryvariations_id = x.deliveryvariations_id;
         lv_result := 1;
    end loop;

    if (lv_result = 1) then
      for x in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                  from stop s, routecontrol rc, route r, customer c
                 where s.routecontrol_id = rc.routecontrol_id
                   and rc.route_id = r.route_id
                   and c.customer_id = s.customer_link_id
                   and s.stop_id = stopId) loop
          update stop s set s.scrutinystatus = 21 where s.stop_id = stopId;
          if not(gv_StopNotApproved) then
             gv_notapprovedstops := gv_notapprovedstops + 1;
             gv_StopNotApproved := true;
          end if;
          gv_message := 'Stop is set to Not Approved because of dry clean without reference.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end loop;
    end if;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check9: ' || sqlerrm;
  end check9;

  -- Check 10: Heavy Soil
  function check10(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  m_total number := 0;
  m_heavysoil number := 0;
  ss_scrutinyheavysoil number := 0;
  begin
    ss_scrutinyheavysoil := get_systemsetting('SCRUTINYHEAVYSOIL', gv_plantid);
    select total, heavysoil into m_total, m_heavysoil from
    (select nvl(sum(dv.amount), 0) total,
           nvl(sum(case
                     when (dv.origin = 1 and dv.soilcountsubtype = 4) then dv.amount
                     else 0
                   end),
               0) heavysoil
      from deliveryvariations dv,
           distributionpoint  dp,
           department         d,
           stop               s,
           routecontrol       rc
     where dv.distributionpoint_id = dp.distributionpoint_id
       and dp.department_id = d.department_id
       and d.customer_id = s.customer_link_id
       and (nvl(s.routestop_id, 0) = 0 or
           (select nvl(rs.deliverypoint_id, 0)
               from routestop rs
              where rs.routestop_id = s.routestop_id) = 0 or
           (select nvl(rs.deliverypoint_id, 0)
               from routestop rs
              where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
       and dv.deliverydate <= rc.drivingdate
       and dv.processed = 'N'
       and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
       and s.routecontrol_id = rc.routecontrol_id
       and s.stop_id = stopId);

    if (m_total <> 0) then
      gv_message := '';
      if ((m_heavysoil / m_total * 100) > ss_scrutinyheavysoil) then
        for x in (select dv.deliveryvariations_id, dv.deliverydate, rc.drivingdate, s.stopnumber
                    from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc
                   where dv.distributionpoint_id = dp.distributionpoint_id
                     and dp.department_id = d.department_id
                     and d.customer_id = s.customer_link_id
                     and (nvl(s.routestop_id, 0) = 0 or
                         (select nvl(rs.deliverypoint_id, 0)
                             from routestop rs
                            where rs.routestop_id = s.routestop_id) = 0 or
                         (select nvl(rs.deliverypoint_id, 0)
                             from routestop rs
                            where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                     and dv.deliverydate <= rc.drivingdate
                     and dv.processed = 'N'
                     and dv.origin = 1
                     and dv.scrutinystatus <> 10
                     and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
                     and dv.soilcountsubtype = 4
                     and s.routecontrol_id = rc.routecontrol_id
                     and s.stop_id = stopId) loop
          update deliveryvariations dv set dv.scrutinystatus = 21 where dv.deliveryvariations_id = x.deliveryvariations_id;
             lv_result := 1;
        end loop;
      end if;
    end if;

    if (lv_result = 1) then
      for x in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                  from stop s, routecontrol rc, route r, customer c
                 where s.routecontrol_id = rc.routecontrol_id
                   and rc.route_id = r.route_id
                   and c.customer_id = s.customer_link_id
                   and s.stop_id = stopId) loop
          update stop s set s.scrutinystatus = 21 where s.stop_id = stopId;
          if not(gv_StopNotApproved) then
             gv_notapprovedstops := gv_notapprovedstops + 1;
             gv_StopNotApproved := true;
          end if;
          gv_message := 'Stop is set to Not Approved because heavy soil exceeds maximum percentage.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end loop;
    end if;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check10: ' || sqlerrm;
  end check10;

  -- Check 11: Clean Return
  function check11(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    gv_message := '';
    for x in (select dv.deliveryvariations_id, dv.deliverydate, rc.drivingdate, s.stopnumber
                from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 and dv.origin = 1
                 and dv.scrutinystatus <> 10
                 and (select fm.washtype from finishingmethod fm where fm.finishingmethod_id = dv.finishingmethod_id) != 1 -- not dry clean
                 and dv.soilcountsubtype = 5
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId) loop
      update deliveryvariations dv set dv.scrutinystatus = 21 where dv.deliveryvariations_id = x.deliveryvariations_id;
         lv_result := 1;
    end loop;

    if (lv_result = 1) then
      for x in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                  from stop s, routecontrol rc, route r, customer c
                 where s.routecontrol_id = rc.routecontrol_id
                   and rc.route_id = r.route_id
                   and c.customer_id = s.customer_link_id
                   and s.stop_id = stopId) loop
            update stop s set s.scrutinystatus = 21 where s.stop_id = stopId;
            if not(gv_StopNotApproved) then
               gv_notapprovedstops := gv_notapprovedstops + 1;
               gv_StopNotApproved := true;
            end if;
            gv_message := 'Stop is set to Not Approved because stop has clean return.';
            write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end loop;
    end if;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check11: ' || sqlerrm;
  end check11;

  -- Check 12: 'Both COG and LOG, same wash price' products
  function check12(stopId stop.stop_id%type) return number is
  lv_result number := 0;
  begin
    for x in (select dv.deliveryvariations_id
                from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc, productlistpercustomer plpc
               where dv.distributionpoint_id = dp.distributionpoint_id
                 and dp.department_id = d.department_id
                 and d.customer_id = s.customer_link_id
                 and (nvl(s.routestop_id, 0) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = 0 or
                     (select nvl(rs.deliverypoint_id, 0)
                         from routestop rs
                        where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                 and dv.deliverydate <= rc.drivingdate
                 and dv.processed = 'N'
                 and dv.scrutinystatus = 11
                 and s.routecontrol_id = rc.routecontrol_id
                 and s.stop_id = stopId
                 and dv.product_id = plpc.product_id
                 and dv.sizedefinition_id = plpc.sizedefinition_id
                 and dv.finishingmethod_id = plpc.finishingmethod_id
                 and d.customer_id = plpc.customer_id
                 and dv.deliverydate between plpc.dateactive and plpc.dateinactive
                 and plpc.billingmethod = 4
                 and plpc.chargewashesonlyforcog = 0) loop
      update deliveryvariations dv set dv.scrutinystatus = 10 where dv.deliveryvariations_id = x.deliveryvariations_id;
    end loop;

    for x in (select sum(case
                         when dv.scrutinystatus <> 10 then 1
                         else 0
                       end) dvno,
                   r.routenumber,
                   rc.drivingdate,
                   s.stopnumber,
                   c.customernumber
              from deliveryvariations dv,
                   distributionpoint  dp,
                   department         d,
                   stop               s,
                   routecontrol       rc,
                   route              r,
                   customer           c
             where dv.distributionpoint_id = dp.distributionpoint_id
               and dp.department_id = d.department_id
               and d.customer_id = s.customer_link_id
               and (nvl(s.routestop_id, 0) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = 0 or
                   (select nvl(rs.deliverypoint_id, 0)
                       from routestop rs
                      where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
               and dv.deliverydate <= rc.drivingdate
               and dv.processed = 'N'
               and s.routecontrol_id = rc.routecontrol_id
               and rc.route_id = r.route_id
               and c.customer_id = s.customer_link_id
               and s.stop_id = stopId
             group by r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
            ) loop
      if (x.dvno = 0) then -- if all products are not applicable - stop is approved
          update stop s set s.scrutinystatus = 30 where s.stop_id = stopId;
          lv_result := 1;
          gv_approvedstops := gv_approvedstops + 1;
          gv_message := 'Stop is set to Approved because all products are ''Both COG and LOG, same wash price''.';
          write_log_line(gv_message, x.routenumber, x.drivingdate, x.stopnumber, x.customernumber);
      end if;
    end loop;
    return lv_result;
  exception
    when others then
      gv_message := 'Error in check12: ' || sqlerrm;
  end check12;

  PROCEDURE scrutinyProcess(plantId            plant.plant_id%type,
                            stopIds            numbers_array,
                            plantprocessId     plantprocess.plantprocess_id%type,
                            dialogId           dialogs.dialog_id%type,
                            abslogprocessjobId in out abslogprocessjob.abslogprocessjob_id%type,
                            languageId         languages.language_id%type,
                            systemuserId       systemuser.systemuser_id%type,
                            workstationId      workstation.workstation_id%type) is

  type rcIdsList is table of routecontrol.routecontrol_id%type;
  lv_rcIds rcIdsList;

--  gv_checkResult number := 0;
  lv_stops numbers_array := stopIds;
  lv_scrutinyExcludeCheckDv number := 0;
  lv_scrutinyExcludeCheckBags number := 0;
  lv_checksList numbers_array := numbers_array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  lv_pnGenerated number;
  locator varchar2(300) := '';
  begin
    --START
    gv_abslogprocessjobpartid := null;
    gv_abslogprocessjobid := abslogprocessjobId;
    gv_processname := 'pack_scrutiny.scrutinyProcess';
    gv_message := gv_processname;
    gv_plantid := plantId;
    if (systemuserId is not null) then
       gv_systemuserid := systemuserId;
    end if;
    gv_workstationid := workstationId;
    gv_approvedstops := 0;
    gv_notapplicablestops := 0;
    gv_notapprovedstops := 0;
    --check parameter not null
/*    if fp_plantprocessid is null then
      begin
        gv_message     := 'parameter fp_plantprocessid cannot be left empty!';
        gv_returnvalue := RETURN_FAILED_UNKNOWN;
        raise gv_userexception;
      end;
    end if;*/

    --get abslog process job id
    if (gv_abslogprocessjobid is null) then
       gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(plantId,
                                                                   sysdate,
                                                                   workstationId,
                                                                   dialogId,
                                                                   plantprocessId,
                                                                   nvl(systemuserId, gv_systemuserid));
    end if;
    abslogprocessjobId := gv_abslogprocessjobid;

    --write_log part
    if gv_abslogprocessjobpartid is null and gv_abslogprocessjobid is not null then
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gv_abslogprocessjobid,
                                                                          gv_processname,
                                                                          nvl(systemuserId, gv_systemuserid));
    end if;

    -- initialize check list
    begin
      select sc.check1, sc.check2, sc.check3, sc.check4, sc.check5, sc.check6, sc.check7, sc.check8, sc.check9, sc.check10
               into lv_checksList(1),
                   lv_checksList(2),
                   lv_checksList(3),
                   lv_checksList(4),
                   lv_checksList(5),
                   lv_checksList(6),
                   lv_checksList(7),
                   lv_checksList(8),
                   lv_checksList(9),
                   lv_checksList(10) from scrutinycheck sc where sc.plant_id = gv_plantid;
    exception
      when others then
           lv_checksList := numbers_array(0, 1, 1, 1, 1, 1, 1, 1, 1, 1);  -- all checks will be performed
    end;

    -- process stops if plant was set to be excluded from scrutiny check
    if (lv_checksList(1) = 1) then
        gv_message := 'All plant customers are excluded from scrutiny check.';
        write_log_line(gv_message);
        return;
    end if;

    -- initialize stops array if null
    if (lv_stops is null) then
      select s.stop_id bulk collect into lv_stops
        from routecontrol rc, stop s
       where rc.routecontrol_id = s.routecontrol_id
         and rc.plant_id = plantId
         and trunc(rc.drivingdate) >= trunc(sysdate)
         and trunc(rc.drivingdate) <= trunc(sysdate) + 1
         and rc.scrutinystatus <> 30
         for update;
    end if;

    -- report header:
    write_log_header;

    if (lv_stops.count > 0) then
    for x in lv_stops.First..lv_stops.Last loop
      -- string of stops id's
    --  lv_stopsIds := lv_stopsIds || ', ' || lv_stops(x);
      locator := 'stop_id for a certain check do not exists' || ' -Stop :' || to_char(lv_stops(x))   ;

      begin
        -- skip approved stops for which PN was generated
        select count(1) into lv_pnGenerated from packingnote pn, stop s where pn.stop_id = s.stop_id and s.stop_id = lv_stops(x) and s.scrutinystatus = 30;
        if (lv_pnGenerated > 0) then
          continue;
        end if;

        gv_StopNotApproved := false;

        -- read customer's exclusion flags
        select c.scrutinyexcludecheckbags, c.scrutinyexcludecheckdv
          into lv_scrutinyExcludeCheckBags, lv_scrutinyExcludeCheckDv
          from stop s, customer c, routecontrol rc, route r
         where c.customer_id = s.customer_link_id
           and s.routecontrol_id = rc.routecontrol_id
           and rc.route_id = r.route_id
           and s.stop_id = lv_stops(x);

   /*     -- Check 1: Check if Customer is excluded from Scrutiny
        gv_checkResult := check1(lv_stops(x));
        if (gv_checkResult = 1 and lv_scrutinyExcludeCheckBags = 1) then
          continue;
        end if;*/

        -- Check 2: Check if all unloaded Bags are sorted
        if (lv_checksList(2) = 1) then
          if (lv_scrutinyExcludeCheckBags = 0) then
            gv_checkResult := check2(lv_stops(x));
            if (gv_checkResult = 1) then
              continue;
            end if;
          end if;
        end if;

        -- Check 1: Check if Customer is excluded from Scrutiny
        gv_checkResult := check1(lv_stops(x));
        if (gv_checkResult = 1) then
          continue;
        end if;

        -- set all stop's DV (except approved ones) to 'not checked'
        if (lv_scrutinyExcludeCheckDv = 0) then
          for y in (select dv.deliveryvariations_id
                      from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc
                     where dv.distributionpoint_id = dp.distributionpoint_id
                       and dp.department_id = d.department_id
                       and d.customer_id = s.customer_link_id
                       and (nvl(s.routestop_id, 0) = 0 or
                           (select nvl(rs.deliverypoint_id, 0)
                               from routestop rs
                              where rs.routestop_id = s.routestop_id) = 0 or
                           (select nvl(rs.deliverypoint_id, 0)
                               from routestop rs
                              where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                       and dv.deliverydate <= rc.drivingdate
                       and dv.processed = 'N'
                       and dv.scrutinystatus <> 30
                       and s.routecontrol_id = rc.routecontrol_id
                       and s.stop_id = lv_stops(x)) loop
            update deliveryvariations dv set dv.scrutinystatus = 11 where dv.deliveryvariations_id = y.deliveryvariations_id;
          end loop;
        end if;

        -- Check 12: 'Both COG and LOG, same wash price' products
        if (lv_scrutinyExcludeCheckDv = 0) then
          gv_checkResult := check12(lv_stops(x));
          if (gv_checkResult = 1) then
            continue;
          end if;
        end if;

        -- Check 3: Nominal Stock is below a predefined quantity
        if (lv_checksList(3) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := check3(lv_stops(x));
            if (gv_checkResult = 1) then
              continue;
            end if;
          end if;
        end if;

        -- Check 5: Delivery Variation with Reason Code Exclude from Scrutiny
        if (lv_checksList(5) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := check5(lv_stops(x));
            if (gv_checkResult = 1) then
              continue;
            end if;
          end if;
        end if;

        -- Check 4: Negative Delivery Variation Lines
        if (lv_checksList(4) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := greatest(gv_checkResult, check4(lv_stops(x)));
          end if;
        end if;

        -- Check 6: Missing Products
        if (lv_checksList(6) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := greatest(gv_checkResult, check6(lv_stops(x)));
          end if;
        end if;

        -- Check 7-8: Average and Deviation and Nominal
        if (lv_checksList(7) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := greatest(gv_checkResult, check7_8(lv_stops(x)));
          end if;
        end if;

        -- Check 9: Dry Cleaning
        if (lv_checksList(8) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := greatest(gv_checkResult, check9(lv_stops(x)));
          end if;
        end if;

        -- Check 10: Heavy Soil
        if (lv_checksList(9) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := greatest(gv_checkResult, check10(lv_stops(x)));
          end if;
        end if;

        -- Check 11: Clean Return
        if (lv_checksList(10) = 1) then
          if (lv_scrutinyExcludeCheckDv = 0) then
            gv_checkResult := greatest(gv_checkResult, check11(lv_stops(x)));
          end if;
        end if;

        -- Stop Completion
        if (lv_scrutinyExcludeCheckDv = 0) then
          for y in (select dv.deliveryvariations_id
                      from deliveryvariations dv, distributionpoint dp, department d, stop s, routecontrol rc
                     where dv.distributionpoint_id = dp.distributionpoint_id
                       and dp.department_id = d.department_id
                       and d.customer_id = s.customer_link_id
                       and (nvl(s.routestop_id, 0) = 0 or
                           (select nvl(rs.deliverypoint_id, 0)
                               from routestop rs
                              where rs.routestop_id = s.routestop_id) = 0 or
                           (select nvl(rs.deliverypoint_id, 0)
                               from routestop rs
                              where rs.routestop_id = s.routestop_id) = dp.deliverypoint_id)
                       and dv.deliverydate <= rc.drivingdate
                       and dv.processed = 'N'
                       and dv.scrutinystatus = 11
                       and s.routecontrol_id = rc.routecontrol_id
                       and s.stop_id = lv_stops(x)) loop
            update deliveryvariations dv set dv.scrutinystatus = 30 where dv.deliveryvariations_id = y.deliveryvariations_id;
          end loop;
        end if;

        -- if one of the checks failed, skip the stop update (already updated)
        if (gv_checkResult = 1) then
          continue;
        end if;

        for y in (select r.routenumber, rc.drivingdate, s.stopnumber, c.customernumber
                    from stop s, routecontrol rc, route r, customer c
                   where s.routecontrol_id = rc.routecontrol_id
                     and rc.route_id = r.route_id
                     and c.customer_id = s.customer_link_id
                     --and gv_checkResult = 0 -- if stop passed all checks this time
                     and s.stop_id = lv_stops(x)) loop
            update stop s set s.scrutinystatus = 30 where s.stop_id = lv_stops(x);
            gv_message := 'Stop is set to Approved.';
            gv_approvedstops := gv_approvedstops + 1;
          write_log_line(gv_message, y.routenumber, y.drivingdate, y.stopnumber, y.customernumber);
        end loop;
      exception when NO_DATA_FOUND then
         IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
         abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_ERROR, locator || ' ' || to_char(nvl(systemuserId, gv_systemuserid)));
         END IF;
        continue;
      end;
    end loop;
    end if;

    -- setting Route Control after processing
    if (lv_stops is not null and lv_stops.count > 0) then

      -- all checked routecontrols
      locator := ' all checked routecontrols fails'  ;
      select count(distinct rc.routecontrol_id) into gv_totalroutecontrols from routecontrol rc, stop s where rc.routecontrol_id = s.routecontrol_id and s.stop_id in (select * from table(lv_stops));

      -- all approved route controls
      locator := '  all approved route controls fails'  ;
      select distinct rc.routecontrol_id bulk collect into lv_rcIds
                from routecontrol rc, stop s1
               where not exists (select 1
                        from stop s
                       where s.routecontrol_id = rc.routecontrol_id
                         and s.scrutinystatus <> 10
                         and s.scrutinystatus <> 30
                         and s.status not in (1, 4))
                 and rc.routecontrol_id = s1.routecontrol_id
                 and s1.stop_id in (select * from table(lv_stops));

      gv_approvedroutecontrols := 0;

      if (lv_rcIds.FIRST is not null) then
        for x in lv_rcIds.FIRST..lv_rcIds.LAST loop
          locator := 'lv_rcIds.FIRST..lv_rcIds.LAST' ||  lv_rcIds(x) ;
          update routecontrol rc set rc.scrutinystatus = 30, rc.timestamp = sysdate, rc.systemuser_id = nvl(systemuserId, gv_systemuserid)
                 where rc.routecontrol_id = lv_rcIds(x);
          gv_approvedroutecontrols := gv_approvedroutecontrols + 1;
        end loop;
      end if;

      -- all not approved route controls
      locator := ' all not approved route controls fails ';
      select distinct rc.routecontrol_id bulk collect into lv_rcIds
                from routecontrol rc, stop s1
               where exists (select 1
                        from stop s
                       where s.routecontrol_id = rc.routecontrol_id
                         and (s.scrutinystatus = 20
                         or s.scrutinystatus = 21)
                         and s.status not in (1, 4))
                 and rc.routecontrol_id = s1.routecontrol_id
                 and s1.stop_id in (select * from table(lv_stops));

      gv_notapprovedroutecontrols := 0;

      if (lv_rcIds.FIRST is not null) then
        for x in lv_rcIds.FIRST..lv_rcIds.LAST loop
          locator := 'lv_rcIds.FIRST..lv_rcIds.LAST second ' ||  lv_rcIds(x) ;
          update routecontrol rc set rc.scrutinystatus = 20, rc.timestamp = sysdate, rc.systemuser_id = nvl(systemuserId, gv_systemuserid)
                 where rc.routecontrol_id = lv_rcIds(x);
          gv_notapprovedroutecontrols := gv_notapprovedroutecontrols + 1;
        end loop;
      end if;
    end if;

    commit;
    -- report footer:
    write_log_footer;

  exception
    when others then
      IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
         abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_ERROR, locator || ' - ' || sqlerrm, nvl(systemuserId, gv_systemuserid));
      END IF;
      raise;
  end scrutinyProcess;

  begin
  -- Initialization
  begin
    select sy.systemuser_id into gv_systemuserid from systemuser sy where sy.username = 'SYSADM';
  exception
    when no_data_found then
    begin
    select sy.systemuser_id into gv_systemuserid from systemuser sy where sy.username = 'ABSADM';
    exception
      when no_data_found then
        begin
          select min(sy.systemuser_id) into gv_systemuserid from systemuser sy;
        end;
    end;
  end;
exception
  when others then
    begin
      dbms_output.put_line('Error during abslogwrite initialization: ' || sqlerrm);
      raise;
    end;
end pack_scrutiny;
/
create or replace package pack_shipmentlist is
  --pack_shipmentlist version 0.37  31-07-2014

  /*
  This procedure will create the content for the customs file.
  The custom file will be created by the application part that calls this procedure.
  Directory used by the application is CUSTOMSFILEPATH system setting.
  Default separator should be ;  but can be changed using the parameter
  */
  procedure createcustomsfile(fp_shipmentlistid in shipmentlist.shipmentlist_id%type,
                              fp_filecontent    out nocopy clob,
                              fp_separator      varchar2 default ';');

  --receiveshipmentlist for non EU countries
  procedure receiveshipmentlist(fp_shipmentlistid in shipmentlist.shipmentlist_id%type,
                                fp_systemuserid   in systemuser.systemuser_id%type default 0);
end pack_shipmentlist;
/
create or replace package body pack_shipmentlist is
  ----------------------------------------------------------------------------
  --internal variables:
  ge_user___exception exception;
  gv_message      abslog.message%type;
  gv_systemuserid systemuser.systemuser_id%type := 0;
  gv_plantid      plant.plant_id%type;
  ----------------------------------------------------------------------------
  --internal functions:
  procedure write_log(fp_message  in abslog.message%type,
                      fp_priority in abslog.priority%type default 3) is
  begin
    --write_log
    abslogwrite.abslog_write(5, 'pack_shipmentlist', gv_plantid, fp_priority, fp_message,
                             gv_systemuserid);
  end write_log;

  procedure get_shipmentlist(fp_shipmentlistid   in shipmentlist.shipmentlist_id%type,
                             fp_rec_shipmentlist out nocopy shipmentlist%rowtype) is
  begin
    --get_shipmentlist
    gv_message := 'get_shipmentlist for fp_shipmentlistid ' ||
                  nvl(to_char(fp_shipmentlistid), 'NULL');
    select sl.*
    into   fp_rec_shipmentlist
    from   shipmentlist sl
    where  sl.shipmentlist_id = fp_shipmentlistid;
    --check supplyingstockroom is not null
    if fp_rec_shipmentlist.supplyingstockroom_id is null then
      begin
        gv_message := 'The supplyingstockroom_id cannot be left blank for fp_shipmentlistid ' ||
                      to_char(fp_shipmentlistid);
        raise ge_user___exception;
      end;
    end if;
  end get_shipmentlist;

  procedure get_stockroom(fp_stockroomid   in stockroom.stockroom_id%type,
                          fp_rec_stockroom out nocopy stockroom%rowtype) is
  begin
    --get_stockroom
    gv_message := 'get_stockroom for fp_stockroomid ' || nvl(to_char(fp_stockroomid), 'NULL');
    select * into fp_rec_stockroom from stockroom st where st.stockroom_id = fp_stockroomid;
    --get plant id for logging
    gv_message := 'get plant id for businessunit_id ' || to_char(fp_rec_stockroom.managedbybu_id);
    select bu.plant_id
    into   gv_plantid
    from   businessunit bu
    where  bu.businessunit_id = fp_rec_stockroom.managedbybu_id;
  end get_stockroom;

  procedure update_stockquantity(fp_stockreservationpergradeid in stockquantity.stockreservationpergrade_id%type,
                                 fp_stockroomlocationid        in stockquantity.stockroomlocation_id%type,
                                 fp_qtyunique                  in stockquantity.qtyunique%type,
                                 fp_qtyuniquewithmodifications in stockquantity.qtyuniquewithmodifications%type,
                                 fp_qtynonunique               in stockquantity.qtynonunique%type) is
  begin
    --update_stockquantity
    update stockquantity q
    set    q.qtyunique = case
                           when q.qtyunique + fp_qtyunique > 0 then
                            q.qtyunique + fp_qtyunique
                           else
                            0
                         end,
           q.qtyuniquewithmodifications = case
                                            when q.qtyuniquewithmodifications +
                                                 fp_qtyuniquewithmodifications > 0 then
                                             q.qtyuniquewithmodifications +
                                             fp_qtyuniquewithmodifications
                                            else
                                             0
                                          end,
           q.qtynonunique = case
                              when q.qtynonunique + fp_qtynonunique > 0 then
                               q.qtynonunique + fp_qtynonunique
                              else
                               0
                            end, q.systemuser_id = gv_systemuserid, q.timestamp = sysdate
    where  q.stockreservationpergrade_id = fp_stockreservationpergradeid
    and    q.stockroomlocation_id = fp_stockroomlocationid;
    --nothing updated... does not yet exist, then insert it
    if sql%rowcount = 0 then
      begin
        insert into stockquantity
          (stockreservationpergrade_id, stockroomlocation_id, qtyunique, qtyuniquewithmodifications,
           systemuser_id, timestamp, qtynonunique)
        values
          (fp_stockreservationpergradeid, fp_stockroomlocationid,
           case when fp_qtyunique > 0 then fp_qtyunique else 0 end,
           case when fp_qtyuniquewithmodifications > 0 then fp_qtyuniquewithmodifications else 0 end,
           gv_systemuserid, sysdate, case when fp_qtynonunique > 0 then fp_qtynonunique else 0 end);
      end;
    end if;
  end update_stockquantity;
  ----------------------------------------------------------------------------
  --external procedures
  procedure createcustomsfile(fp_shipmentlistid in shipmentlist.shipmentlist_id%type,
                              fp_filecontent    out nocopy clob,
                              fp_separator      varchar2 default ';') is
    /*
    This procedure will create the content for the customs file.
    The custom file will be created by the application part that calls this procedure.
    Directory used by the application is CUSTOMSFILEPATH system setting.
    Default separator should be ;  but can be changed using the parameter
    */
    lv_rec_shipmentlist shipmentlist%rowtype;
    lv_rec_stockroom    stockroom%rowtype;
    lv_shipped_qty      number;
    lv_processed_qty    number;

    procedure write_line(fp_export_string in varchar2) is
    begin
      --write_line
      fp_filecontent := fp_filecontent || (chr(13) || chr(10)) || fp_export_string;
    end write_line;
  begin
    --createCustomsFile
    gv_message := 'createcustomsfile';
    --get_shipmentlist
    get_shipmentlist(fp_shipmentlistid, lv_rec_shipmentlist);
    --get stockroom
    get_stockroom(lv_rec_shipmentlist.supplyingstockroom_id, lv_rec_stockroom);
    --find shipmentlistlines
    gv_message := 'find shipmentlistline(s) for fp_shipmentlistid ' || to_char(fp_shipmentlistid);
    for x in (select spll.transportunitnumber, spll.workorderline_id, spll.quantityshipped,
                     wol.purchaseorderline_id, spll.shipmentlistline_id
              from   shipmentlistline spll
              join   workorderline wol
              on     wol.workorderline_id = spll.workorderline_id
              where  spll.shipmentlist_id = fp_shipmentlistid) loop
      begin
        --x.purchaseorderline_id is null is not allowed
        if x.purchaseorderline_id is null then
          begin
            gv_message := 'workorderline id ' || to_char(x.workorderline_id) ||
                          ' is not linked to a purchaseorderline! For fp_shipmentlistid ' ||
                          to_char(fp_shipmentlistid);
            raise ge_user___exception;
          end;
        end if;
        --find dispatchadvicelines
        gv_message       := 'find dispatchadviceline(s) for purchaseorderline_id ' ||
                            to_char(x.purchaseorderline_id) || ' for fp_shipmentlistid ' ||
                            to_char(fp_shipmentlistid);
        lv_processed_qty := 0;
        for y in (select dal.dispatchadviceline_id, p.code productcode, s.code sizecode,
                         dal.commoditycode, dal.countryoforigin, dal.actualquantitydelivered,
                         dal.shippedquantity,
                         (dal.actualquantitydelivered - dal.shippedquantity) leftover_quantity,
                         (select ps.theoreticalweight
                           from   productsize ps
                           where  ps.product_id = dal.laundryproduct_id
                           and    ps.sizedefinition_id = dal.laundrysize_id) theoreticalweight,
                         pol.purchaseprice,
                         (select cu.code from currency cu where cu.currency_id = sp.currency_id) sp_currencycode,
                         (select cpl.preferred
                           from   customspreferencelookup cpl
                           where  cpl.commoditycode = dal.commoditycode
                           and    cpl.countryoforigin = dal.countryoforigin) preferred
                  from   dispatchadviceline dal
                  join   dispatchadviceheader dah
                  on     dah.dispatchadviceheader_id = dal.dispatchadviceheader_id
                  join   product p
                  on     p.product_id = dal.laundryproduct_id
                  join   sizedefinition s
                  on     s.sizedefinition_id = dal.laundrysize_id
                  join   purchaseorderline pol
                  on     pol.purchaseorderline_id = dal.purchaseorderline_id
                  join   supplier sp
                  on     sp.supplier_id = dah.supplier_id
                  where  dal.purchaseorderline_id = x.purchaseorderline_id
                  order  by dah.deliverydate, dal.linesequentialnumber asc) loop
          begin
            --calc the lv_shipped_qty
            if x.quantityshipped <= y.leftover_quantity then
              lv_shipped_qty := x.quantityshipped;
            else
              lv_shipped_qty := y.leftover_quantity;
            end if;
            lv_processed_qty := lv_processed_qty + lv_shipped_qty;
            --update dispatchadviceline dal
            gv_message := 'update dispatchadviceline id ' || to_char(y.dispatchadviceline_id) ||
                          ' with ' || to_char(lv_shipped_qty);
            update dispatchadviceline dal
            set    dal.shippedquantity = dal.shippedquantity + lv_shipped_qty
            where  dal.dispatchadviceline_id = y.dispatchadviceline_id;
            --write customs file
            gv_message := 'write customs file line';
            write_line(y.productcode || fp_separator || y.productcode || fp_separator ||
                       y.sizecode || fp_separator || y.commoditycode || fp_separator ||
                       y.countryoforigin || fp_separator || y.preferred || fp_separator ||
                       lv_shipped_qty || fp_separator || (y.theoreticalweight * lv_shipped_qty) ||
                       fp_separator || y.purchaseprice || fp_separator || y.sp_currencycode ||
                       fp_separator);
            --check if we are ready
            if lv_processed_qty = x.quantityshipped then
              exit;
            end if;
          end;
        end loop; --y  dispatchadviceline
        if lv_processed_qty <> x.quantityshipped then
          begin
            --quantities have to be equal!
            gv_message := 'Cannot determine dispatchadviceline quantities; for workorderline id ' ||
                          to_char(x.workorderline_id) || ' and fp_shipmentlistid ' ||
                          to_char(fp_shipmentlistid) || ' qty processed is less then ' ||
                          to_char(lv_processed_qty) || ' shipmentlistline.quantityshipped? For ' ||
                          to_char(x.quantityshipped) || ' shipmentlistline_id ' ||
                          to_char(x.shipmentlistline_id);
            raise ge_user___exception;
          end;
        end if;
      end;
    end loop; --x  shipmentlistline
    --finalize
    gv_message := 'finalize, close files/commit';
    commit;
  exception
    when ge_user___exception then
      begin
        rollback;
        write_log(gv_message);
      end;
    when no_data_found then
      begin
        rollback;
        write_log(gv_message || ' no data found!');
      end;
    when others then
      begin
        rollback;
        write_log(gv_message || ' ' || sqlerrm);
      end;
  end createcustomsfile;

  --receiveshipmentlist for non EU countries
  procedure receiveshipmentlist(fp_shipmentlistid in shipmentlist.shipmentlist_id%type,
                                fp_systemuserid   in systemuser.systemuser_id%type default 0) is
    lv_rec_shipmentlist            shipmentlist%rowtype;
    lv_rec_from_stockroom          stockroom%rowtype;
    lv_rec_to_stockroom            stockroom%rowtype;
    lv_from_stockreservatpgradeid  stockreservationpergrade.stockreservationpergrade_id%type;
    lv_to___stockreservatpgradeid  stockreservationpergrade.stockreservationpergrade_id%type;
    lv_to_stockdefinitionperitemid stockdefinitionperitem.stockdefinitionperitem_id%type;
    lv_unique_modification_cnt     number;
  begin
    --receiveshipmentlist
    gv_message      := 'receiveshipmentlist fp_systemuserid';
    gv_systemuserid := coalesce(fp_systemuserid, gv_systemuserid);
    --get_shipmentlist
    get_shipmentlist(fp_shipmentlistid, lv_rec_shipmentlist);
    if lv_rec_shipmentlist.receiveonlocalstock = 1 then
      begin
        gv_message := 'shipmentlist.receiveonlocalstock = 1  is not allowed for ' ||
                      nvl(to_char(fp_shipmentlistid), 'NULL');
        raise ge_user___exception;
      end;
    end if;
    --get FROM stockroom
    get_stockroom(lv_rec_shipmentlist.supplyingstockroom_id, lv_rec_from_stockroom);
    --check lv_rec_to_stockroom.receiveshipmentlocation_id is not null
    if lv_rec_from_stockroom.transitlocation_id is null then
      begin
        gv_message := 'stockroom.transitlocation_id is null is not allowed for stockroom ' ||
                      nvl(lv_rec_from_stockroom.code, 'NULL');
        raise ge_user___exception;
      end;
    end if;
    --get TO stockroom
    gv_message := 'select TO stockroom for businessunit id ' ||
                  nvl(to_char(lv_rec_shipmentlist.shiptobusinessunit_id), 'NULL');
    select sr.*
    into   lv_rec_to_stockroom
    from   stockroomsservicingbu srsb
    join   stockroom sr
    on     sr.stockroom_id = srsb.stockroom_id
    where  srsb.businessunit_id = lv_rec_shipmentlist.shiptobusinessunit_id
    and    srsb.priority = (select min(srsbx.priority)
                            from   stockroomsservicingbu srsbx
                            where  srsbx.businessunit_id = srsb.businessunit_id);
    --check lv_rec_to_stockroom.receiveshipmentlocation_id is not null
    if lv_rec_to_stockroom.receiveshipmentlocation_id is null then
      begin
        gv_message := 'stockroom.receiveshipmentlocation_id is null is not allowed for stockroom ' ||
                      nvl(lv_rec_to_stockroom.code, 'NULL');
        raise ge_user___exception;
      end;
    end if;
    --start moving the issue history that belongs to the shipmentlist_id
    for y in (select ih.stockroomlocation_id, ih.product_link_id, ih.sizedefinition_link_id,
                     ih.issuegrade_id, ih.originalgrade_id, ih.customerowned,
                     case ih.customerrelated /*Only customer stock when customer related!*/
                        when 'Y' then
                         ih.customer_link_id
                        else
                         null
                      end customer_id, ih.uniqueitem_link_id, ih.quantity, ih.reasoncode_id
              from   shipmentlist shp
              join   shipmentlistline shpl
              on     shpl.shipmentlist_id = shp.shipmentlist_id
              join   issuehistory ih
              on     ih.shipmentlistline_id = shpl.shipmentlistline_id
              where  shp.shipmentlist_id = fp_shipmentlistid
              and    ih.quantity > 0) loop
      begin
        ---------------------------------------------------------------------------------------
        ---START FROM---
        --get FROM stockreservationpergade
        gv_message := 'get (FROM) stockreservationpergade for stockroom id ' ||
                      lv_rec_from_stockroom.stockroom_id || ' product id ' || y.product_link_id ||
                      ' size id ' || y.sizedefinition_link_id || ' original grade id ' ||
                      y.originalgrade_id || ' customer owned ' || y.customerowned ||
                      ' customer id ' || nvl(to_char(y.customer_id), 'NULL');
        select sr.stockreservationpergrade_id
        into   lv_from_stockreservatpgradeid
        from   stockreservationpergrade sr
        join   stockdefinitionperitem sti
        on     sti.stockdefinitionperitem_id = sr.stockdefinitionperitem_id
        where  sti.product_id = y.product_link_id
        and    sti.sizedefinition_id = y.sizedefinition_link_id
        and    sti.stockroom_id = lv_rec_from_stockroom.stockroom_id
        and    sr.qualitygrade_id = y.originalgrade_id --FROM GRADE
        and    ((sti.customer_id = y.customer_id) or
              (sti.customer_id is null and y.customer_id is null))
        and    sti.customerowned = y.customerowned;
        --update FROM stockquantity
        if y.uniqueitem_link_id is null then
          begin
            --update FROM stockquantity
            gv_message := 'update (FROM) stockquantity nonunique with ' || to_char(y.quantity) ||
                          ' for stockroom id ' || lv_rec_from_stockroom.stockroom_id ||
                          ' product id ' || y.product_link_id || ' size id ' ||
                          y.sizedefinition_link_id || ' original grade id ' || y.originalgrade_id ||
                          ' customer owned ' || y.customerowned || ' customer id ' ||
                          nvl(to_char(y.customer_id), 'NULL');
            update_stockquantity(lv_from_stockreservatpgradeid,
                                 lv_rec_from_stockroom.transitlocation_id, 0, 0, (y.quantity * -1));
          end;
        else
          begin
            --check for modifications
            gv_message := 'check for modifications for uniqueitem_id ' ||
                          to_char(y.uniqueitem_link_id);
            select (select count(1)
                     from   uniqueitemmodification unm
                     where  unm.uniqueitem_id = u.uniqueitem_id) unique_modification_cnt
            into   lv_unique_modification_cnt
            from   uniqueitem u
            where  u.uniqueitem_id = y.uniqueitem_link_id;
            if nvl(lv_unique_modification_cnt, 0) > 0 then
              begin
                --update from stock quantity qtyuniquewithmodifications
                gv_message := 'update (FROM) stockquantity qtyuniquewithmodifications with ' ||
                              to_char(y.quantity) || ' for stockroom id ' ||
                              lv_rec_from_stockroom.stockroom_id || ' product id ' ||
                              y.product_link_id || ' size id ' || y.sizedefinition_link_id ||
                              ' original grade id ' || y.originalgrade_id || ' customer owned ' ||
                              y.customerowned || ' customer id ' ||
                              nvl(to_char(y.customer_id), 'NULL');
                update_stockquantity(lv_from_stockreservatpgradeid,
                                     lv_rec_from_stockroom.transitlocation_id, 0, -1, 0);
              end;
            else
              begin
                --update from stock quantity qtyunique
                gv_message := 'update (FROM) stockquantity qtyunique with ' || to_char(y.quantity) ||
                              ' for stockroom id ' || lv_rec_from_stockroom.stockroom_id ||
                              ' product id ' || y.product_link_id || ' size id ' ||
                              y.sizedefinition_link_id || ' original grade id ' ||
                              y.originalgrade_id || ' customer owned ' || y.customerowned ||
                              ' customer id ' || nvl(to_char(y.customer_id), 'NULL');
                update_stockquantity(lv_from_stockreservatpgradeid,
                                     lv_rec_from_stockroom.transitlocation_id, -1, 0, 0);
              end;
            end if;
          end;
        end if;
        --end update FROM stockquantity
        --create from stocktransaction 417
        gv_message := 'create FROM stocktransaction 417 for stockreservation per grade id ' ||
                      to_char(lv_from_stockreservatpgradeid);
        insert into stocktransaction
          (stocktransaction_id, stockreservationpergrade_id, transactiondate, reasoncode_id,
           transactiontype_id, uniquestock, quantity, systemuser_id, timestamp, exported, delayed,
           transactiontimestamp, fromstockroomlocation_id, tostockroomlocation_id, remark,
           documenttype, documentnumber, documentnumberprefix, stockvaluationmethod,
           calculationprice, uniqueitem_link_id)
        values
          (seq_stocktransaction.nextval, lv_from_stockreservatpgradeid, sysdate, y.reasoncode_id,
           417, case when y.uniqueitem_link_id is not null then 'Y' else 'N' end, -y.quantity,
           gv_systemuserid, sysdate, 'N', 'N', sysdate, lv_rec_from_stockroom.transitlocation_id,
           lv_rec_to_stockroom.receiveshipmentlocation_id, 'Receive Shipmentlist 417', 0
           /*documenttype stocktransation*/, lv_rec_shipmentlist.shipmentlistnumber, null, 0, 0,
           y.uniqueitem_link_id);
        ---END FROM---
        ---------------------------------------------------------------------------------------
        ---START TO---
        begin
          --get TO stockreservationpergade
          gv_message := 'get (TO) stockreservationpergade for stockroom id ' ||
                        lv_rec_from_stockroom.stockroom_id || ' product id ' || y.product_link_id ||
                        ' size id ' || y.sizedefinition_link_id || ' issue grade id ' ||
                        y.issuegrade_id || ' customer owned ' || y.customerowned || ' customer id ' ||
                        nvl(to_char(y.customer_id), 'NULL');
          select sr.stockreservationpergrade_id
          into   lv_to___stockreservatpgradeid
          from   stockreservationpergrade sr
          join   stockdefinitionperitem sti
          on     sti.stockdefinitionperitem_id = sr.stockdefinitionperitem_id
          where  sti.product_id = y.product_link_id
          and    sti.sizedefinition_id = y.sizedefinition_link_id
          and    sti.stockroom_id = lv_rec_to_stockroom.stockroom_id
          and    sr.qualitygrade_id = y.issuegrade_id --TO GRADE
          and    ((sti.customer_id = y.customer_id) or
                (sti.customer_id is null and y.customer_id is null))
          and    sti.customerowned = y.customerowned;
          --update TO stockquantity, continue when is found lv_to___stockreservatpgradeid
          if y.uniqueitem_link_id is null then
            begin
              --update TO stockquantity
              gv_message := 'update (TO) stockquantity nonunique with ' || to_char(y.quantity) ||
                            ' for stockroom id ' || lv_rec_from_stockroom.stockroom_id ||
                            ' product id ' || y.product_link_id || ' size id ' ||
                            y.sizedefinition_link_id || ' issue grade id ' || y.issuegrade_id ||
                            ' customer owned ' || y.customerowned || ' customer id ' ||
                            nvl(to_char(y.customer_id), 'NULL');
              update_stockquantity(lv_to___stockreservatpgradeid,
                                   lv_rec_to_stockroom.receiveshipmentlocation_id, 0, 0, y.quantity);
            end;
          else
            begin
              --lv_unique_modification_cnt is already known
              if nvl(lv_unique_modification_cnt, 0) > 0 then
                begin
                  --update TO stock quantity qtyuniquewithmodifications
                  gv_message := 'update (TO) stockquantity qtyuniquewithmodifications with ' ||
                                to_char(y.quantity) || ' for stockroom id ' ||
                                lv_rec_from_stockroom.stockroom_id || ' product id ' ||
                                y.product_link_id || ' size id ' || y.sizedefinition_link_id ||
                                ' issue grade id ' || y.issuegrade_id || ' customer owned ' ||
                                y.customerowned || ' customer id ' ||
                                nvl(to_char(y.customer_id), 'NULL');
                  update_stockquantity(lv_to___stockreservatpgradeid,
                                       lv_rec_to_stockroom.receiveshipmentlocation_id, 0, 1, 0);
                end;
              else
                begin
                  --update TO stock quantity qtyunique
                  gv_message := 'update (TO) stockquantity qtyunique with ' || to_char(y.quantity) ||
                                ' for stockroom id ' || lv_rec_from_stockroom.stockroom_id ||
                                ' product id ' || y.product_link_id || ' size id ' ||
                                y.sizedefinition_link_id || ' issue grade id ' || y.issuegrade_id ||
                                ' customer owned ' || y.customerowned || ' customer id ' ||
                                nvl(to_char(y.customer_id), 'NULL');
                  update_stockquantity(lv_to___stockreservatpgradeid,
                                       lv_rec_to_stockroom.receiveshipmentlocation_id, 1, 0, 0);
                end;
              end if;
            end;
          end if;
          --end update TO stockquantity
        exception
          when no_data_found then
            begin
              --continue when lv_to___stockreservatpgradeid is not found, create it
              --get TO stockdefinitionperitem (NO DATA)
              begin
                select sti.stockdefinitionperitem_id
                into   lv_to_stockdefinitionperitemid
                from   stockdefinitionperitem sti
                where  sti.stockroom_id = lv_rec_to_stockroom.stockroom_id
                and    sti.product_id = y.product_link_id
                and    sti.sizedefinition_id = y.sizedefinition_link_id
                and    ((sti.customer_id = y.customer_id) or
                      (sti.customer_id is null and y.customer_id is null))
                and    sti.customerowned = y.customerowned;
              exception
                when no_data_found then
                  begin
                    gv_message := 'create (TO) stockdefinitionperitem for stockroom id ' ||
                                  lv_rec_from_stockroom.stockroom_id || ' product id ' ||
                                  y.product_link_id || ' size id ' || y.sizedefinition_link_id ||
                                  ' issue grade id ' || y.issuegrade_id || ' customer owned ' ||
                                  y.customerowned || ' customer id ' ||
                                  nvl(to_char(y.customer_id), 'NULL');
                    --get TO next id for stockdefinitionperitem (NO DATA)
                    select seq_stockdefinitionperitem.nextval
                    into   lv_to_stockdefinitionperitemid
                    from   dual;
                    --insert into stockdefinitionperitem (NO DATA)
                    insert into stockdefinitionperitem
                      (stockdefinitionperitem_id, stockroom_id, product_id, sizedefinition_id,
                       customer_id, customerowned, minqtynew, minqtyused, maxqtynew, maxqtyused,
                       systemuser_id, timestamp, defaultsupplier_id)
                      select lv_to_stockdefinitionperitemid, lv_rec_to_stockroom.stockroom_id,
                             p.product_id, y.sizedefinition_link_id, y.customer_id, y.customerowned,
                             0, 0, 999, 999, gv_systemuserid, sysdate, p.supplier_id
                      from   product p
                      where  p.product_id = y.product_link_id;
                  end;
              end; --TO stockdefinitionperitem (NO DATA)
              --insert TO stockreservationpergade (NO DATA)
              gv_message := 'create (TO) stockreservationpergade for stockroom id ' ||
                            lv_rec_from_stockroom.stockroom_id || ' product id ' ||
                            y.product_link_id || ' size id ' || y.sizedefinition_link_id ||
                            ' issue grade id ' || y.issuegrade_id || ' customer owned ' ||
                            y.customerowned || ' customer id ' ||
                            nvl(to_char(y.customer_id), 'NULL');
              insert into stockreservationpergrade
                (stockreservationpergrade_id, stockdefinitionperitem_id, qualitygrade_id,
                 qtyuniquereserved, qtynonuniquereserved, qtyuniquewiithmodifreserved, qtynonunique,
                 qtyuniqueordered, qtynonuniqueordered, systemuser_id, timestamp,
                 qtyuniqueordereddirectissue, qtynonuniqueordereddirectissue)
              values
                (seq_stockreservationpergrade.nextval, lv_to_stockdefinitionperitemid,
                 y.issuegrade_id, 0, 0, 0, 0, 0, 0, gv_systemuserid, sysdate, 0, 0)
              returning stockreservationpergrade_id into lv_to___stockreservatpgradeid;
              --create stockquantity
              gv_message := 'create (TO) stockquantity for stockroom id ' ||
                            lv_rec_from_stockroom.stockroom_id || ' product id ' ||
                            y.product_link_id || ' size id ' || y.sizedefinition_link_id ||
                            ' issue grade id ' || y.issuegrade_id || ' customer owned ' ||
                            y.customerowned || ' customer id ' ||
                            nvl(to_char(y.customer_id), 'NULL');
              insert into stockquantity
                (stockreservationpergrade_id, stockroomlocation_id, qtyunique,
                 qtyuniquewithmodifications, systemuser_id, timestamp, qtycounted, datecounted,
                 qtynonunique)
              values
                (lv_to___stockreservatpgradeid, lv_rec_to_stockroom.receiveshipmentlocation_id,
                 case when
                  y.uniqueitem_link_id is not null and nvl(lv_unique_modification_cnt, 0) = 0 then
                  y.quantity else 0 end,
                 case when
                  y.uniqueitem_link_id is not null and nvl(lv_unique_modification_cnt, 0) > 0 then
                  y.quantity else 0 end, gv_systemuserid, sysdate, 0, null,
                 case when y.uniqueitem_link_id is null then y.quantity else 0 end);
            end; --END TO stockreservationpergrade (NO DATA)
        end;
        --create TO stocktransaction 418
        gv_message := 'create TO stocktransaction 418 for stockreservation per grade id ' ||
                      to_char(lv_to___stockreservatpgradeid);
        insert into stocktransaction
          (stocktransaction_id, stockreservationpergrade_id, transactiondate, reasoncode_id,
           transactiontype_id, uniquestock, quantity, systemuser_id, timestamp, exported, delayed,
           transactiontimestamp, fromstockroomlocation_id, tostockroomlocation_id, remark,
           documenttype, documentnumber, documentnumberprefix, stockvaluationmethod,
           calculationprice, uniqueitem_link_id)
        values
          (seq_stocktransaction.nextval, lv_to___stockreservatpgradeid, sysdate, y.reasoncode_id,
           418, case when y.uniqueitem_link_id is not null then 'Y' else 'N' end, y.quantity,
           gv_systemuserid, sysdate, 'N', 'N', sysdate, lv_rec_from_stockroom.transitlocation_id,
           lv_rec_to_stockroom.receiveshipmentlocation_id, 'Receive Shipmentlist 418', 0
           /*documenttype stocktransation*/, lv_rec_shipmentlist.shipmentlistnumber, null, 0, 0,
           y.uniqueitem_link_id);
        ---END TO---
        ---------------------------------------------------------------------------------------
        if y.uniqueitem_link_id is not null then
          begin
            --update uniqueitemfixedinfo
            gv_message := 'update uniqueitemfixedinfo for uniqueitem id ' ||
                          to_char(y.uniqueitem_link_id);
            update uniqueitemfixedinfo uf
            set    uf.stockroomlocation_id = lv_rec_to_stockroom.receiveshipmentlocation_id,
                   uf.timestamp = sysdate, uf.systemuser_id = gv_systemuserid
            where  uf.uniqueitem_id = y.uniqueitem_link_id;
          end;
        end if;
        ---------------------------------------------------------------------------------------
      end;
    end loop; --y
    --update shipmentlist receiveonlocalstock to 1
    gv_message := 'update shipmentlist receiveonlocalstock to 1 for shipment id ' ||
                  nvl(to_char(fp_shipmentlistid), 'NULL');
    update shipmentlist l
    set    l.receiveonlocalstock = 1, l.timestamp = sysdate, l.systemuser_id = gv_systemuserid
    where  l.shipmentlist_id = fp_shipmentlistid;
    ---------------------------------------------------------------------------------------
    commit;
  exception
    when ge_user___exception then
      begin
        rollback;
        write_log(gv_message);
      end;
    when no_data_found then
      begin
        rollback;
        write_log(gv_message || ' no data found!');
      end;
    when others then
      begin
        rollback;
        write_log(gv_message || ' ' || sqlerrm);
      end;
  end receiveshipmentlist;

end pack_shipmentlist;
/
create or replace package pack_sort is
  -- Author  : TATIANA
  -- Created : 6/21/2004 5:49:46 PM
  -- Purpose :
  -- Public type declarations
  -- Version 3.4
  -- Update 19-01-2017 ABS-42607 Make it possible to feed a UHF buffer
  -- Update 02-03-2017 ABS-45388 Sorting System UHF ID code filter compatible
  -- Update 07-04-2017 ABS-39934 Changes in getgarmentdata (for pool and route)
  -- Update 05-07-2018 ABS-64648 order by for flags by HVL
  -- Update 11-06-2020 ABS-103336 Fill deliveryscan.planneddeliverydate
  -- Update 02-07-2020 ABS-102309 reduce length sort string based on system settings
  -- Update 16-09-2020 ABS-102775 fake inscan garments at outscan
  -- Updated : 29-09-2020 DLA ABS-108518 Delivery variations processbusinessunit_id and internalprocessingbu_id are not filled when creating DV from Pack_multiread
  -- Updated : 15-12-2020 ABS-108106 Add option to create UHFBundles to the Inwatec Interface
  -- Updated : 02-06-2021 ABS-119757 provide route and stop information for pool items when a delivery point has been set on the routestop
  -- Updated : 03-06-2021 ABS-116289 Wrong delivery determination by GETGARMENTDATAWITHORDER
  -- Updated : 28-09-2021 ABS-125089 Correct mis-commit from ABS-116289
  -- Updated : 08-10-2021 ABS-125149 Unexpected sideeffect of DELIVERYDETERMINATION = 1
  -- Updated : 15-11-2021 ABS-127284 JSG Scanola interface timestamps
  -- Updated : 31-01-2022 ABS-127128 SENDTRACKINFOWITHORDER did not create GDTransactiontype 24
  -- Updated : 03-02-2022 ABS-128694 Fake inscan on multiple BU's where only 1 BU has a simulate workstation
  -- Updated : 11-03-2022 ABS-119962 Fake inscan should never have a Saturday or Sunday date
  -- Updated : 24-08-2022 ABS-119848 Closed customers added in RSC
  -- Updated : 01-02-2022 ABS-113854 Interface with DBM picking robot for loading containers, need script 2,3 and 4 from, 9.07.01
  -- Updated : 21-03-2023 ABS-148657 Outscan Multi Read on DN doesn't show already delivered quantities
  -- Updated : 03-05-2023 ABS-139116 problem uploading routes on Route Status Control
  -- Updated : 11-07-2023 ABS-152024 Send Track Info - extension
  -- Updated : 09-10-2023 ABS-156386 Add support season_change sortfield
  -- Updated : 11-10-2023 ABS-154407 Add Finishing Code to the Sorting Definitions for sorting systems
  -- Updated : 22-11-2023 ABS-156155 Backup views and procedures, remove parts of ABS-113854
  -- Updated : 09-02-2024 ABS-157099 Add RouteStatusControl ExtraInfo for virtual routes
  -- Updated : 09-04-2024 ABS-162835 Web portal standard deliveries not shown correctly

  type deliveryweeks is table of number index by binary_integer;
  type visitdates is table of number index by varchar2(8);
  type flags is table of number index by varchar2(22);
  i                              integer;
  gv_specialsizeid               sizedefinition.sizedefinition_id%type; --size star
  AUTOMATICFLAG_DECREASE_MAX_INV integer := 7;
  --SO 20015256 logging in database instead of to files
  procedure write_logging(fp_message    in abslog.message%type,
                          fp_loglevel   in number,
                          fp_logname    in varchar2,
                          fp_plantid    in plant.plant_id%type default null,
                          fp_priority   in number default 1,
                          fp_detailinfo in number default 0); ---0=no detail 1=detail
  ---
  procedure getadditionalabelinfo(fp_idcode                      in uniqueitem.primaryid%type,
                                  fp_unitcode                    in businessunit.code%type,
                                  fp_deliverypointcode           in deliverypoint.code%type,
                                  fp_departmentdescription       out department.description%type,
                                  fp_consumptionpointnumber      out distributionpoint.distributionpointnumber%type,
                                  fp_consumptionpointdescription out distributionpoint.description%type,
                                  fp_deliverypointdescription    out deliverypoint.description%type,
                                  fp_deliverypointstreet1        out address.street%type,
                                  fp_deliverypointstreet2        out address.street2%type,
                                  fp_deliverypointzipcode        out address.zipcode%type,
                                  fp_deliverypointcity           out address.city%type,
                                  fp_transportarticledescription out transportarticle_desc.description%type);
  function getdeliveryweeksforyear(year      in integer,
                                   frequency in integer,
                                   offset    in integer) return deliveryweeks;
  procedure getnextdeliveryweek(deliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                dayno            in day.day_id%type,
                                currentdate      in date,
                                nextdeliveryweek out integer,
                                nextdeliveryyear out integer);
  function getvisitdate(deliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                        dayno            in day.day_id%type,
                        currentdate      in date) return date;
  function getnextdeliverydate(currentdate in date,
                               customerid  in customer.customer_id%type,
                               typeofmerch in product.typeofmerchandise%type)
    return date;
  function getroutestopforcustomer(plantid_garment in plant.plant_id%type,
                                   visitdate       in date,
                                   customerid      in customer.customer_id%type,
                                   deliverypointid in integer) return integer;
  procedure getlastinroute(customerid      in customer.customer_id%type,
                           datex           in date,
                           deliverypointid in deliverypoint.deliverypoint_id%type,
                           typeofmerch     in product.typeofmerchandise%type,
                           lastinroute     out route.route_id%type,
                           routestopx      out routestop.routestop_id%type,
                           lastindate      out date,
                           garmentplantid  in route.plant_id%type default null);
  procedure fillplannedoutroute(plantid_garment     in plant.plant_id%type,
                                currentdate         in date,
                                typeofmerch         in product.typeofmerchandise%type,
                                deliverymethod      in integer,
                                deedeliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                plpcid              in productlistpercustomer.productlistpercustomer_id%type,
                                customerid          in customer.customer_id%type,
                                deliverypointid     in deliverypoint.deliverypoint_id%type,
                                lastinroute         in route.route_id%type,
                                lastindate          in date,
                                routestopin         in routestop.routestop_id%type,
                                routestopid         out routestop.routestop_id%type,
                                routeid             out route.route_id%type,
                                plannedoutdate      out date,
                                scanbyroute         in varchar2);
  procedure getflags(uniqueitemid        in uniqueitem.uniqueitem_id%type,
                     plantid_param       in plant.plant_id%type,
                     wearerflagid        in flag.flag_id%type,
                     wearerflagstartdate in date,
                     empflagid           in flag.flag_id%type,
                     empflagstartdate    in date,
                     languageid          in languages.language_id%type,
                     flagsusage          in integer,
                     flagcode1           out nocopy sortaddressperflag.sortaddress%type,
                     flagcode2           out nocopy sortaddressperflag.sortaddress%type,
                     flagcode3           out nocopy sortaddressperflag.sortaddress%type,
                     flagcode4           out nocopy sortaddressperflag.sortaddress%type,
                     flagdescription1    out nocopy flag_desc.description%type,
                     flagdescription2    out nocopy flag_desc.description%type,
                     flagdescription3    out nocopy flag_desc.description%type,
                     flagdescription4    out nocopy flag_desc.description%type,
                     flagsinfo           out nocopy varchar2, --300
                     destinationstring   out nocopy varchar2,
                     fp_kann_yes_no      in varchar2 default 'N', --Default N, options Y,N
                     fp_flag_freetext1   out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext2   out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext3   out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext4   out nocopy uniqueitemflag.freetextitem%type);
  procedure getflags(uniqueitemid           in uniqueitem.uniqueitem_id%type,
                     plantid_param          in plant.plant_id%type,
                     wearerflagid           in flag.flag_id%type,
                     wearerflagstartdate    in date,
                     empflagid              in flag.flag_id%type,
                     empflagstartdate       in date,
                     languageid             in languages.language_id%type,
                     flagsusage             in integer,
                     flagcode1              out nocopy sortaddressperflag.sortaddress%type,
                     flagcode2              out nocopy sortaddressperflag.sortaddress%type,
                     flagcode3              out nocopy sortaddressperflag.sortaddress%type,
                     flagcode4              out nocopy sortaddressperflag.sortaddress%type,
                     flagdescription1       out nocopy flag_desc.description%type,
                     flagdescription2       out nocopy flag_desc.description%type,
                     flagdescription3       out nocopy flag_desc.description%type,
                     flagdescription4       out nocopy flag_desc.description%type,
                     flagsinfo              out nocopy varchar2, --300
                     destinationstring      out nocopy varchar2, --3
                     fp_kann_yes_no         in varchar2 default 'N', --Default N, options Y,N
                     fp_flag_freetext1      out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext2      out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext3      out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext4      out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext1         out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext2         out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext3         out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext4         out nocopy uniqueitemflag.freetextitem%type,
                     ui_status_assigned     in varchar2 default 'N',
                     freetext2descriptionyn in varchar2 default 'Y',
                     metricon               in varchar2 default 'N');
  procedure determinegarmentid(sortingsystem     in varchar2,
                               idcode            in uniqueitem.primaryid%type,
                               plantcode         in plant.code%type,
                               uniqueitemid      out nocopy uniqueitem.uniqueitem_id%type,
                               pool              out nocopy uniqueitem.poolitem%type,
                               unitcode          out nocopy businessunit.code%type,
                               businessunitid    out nocopy businessunit.businessunit_id%type,
                               plantid_garment   out nocopy plant.plant_id%type,
                               returnedplantcode out nocopy plant.code%type,
                               status            out nocopy integer,
                               idprimary         out uniqueitem.primaryid%type,
                               plantid_param     out nocopy plant.plant_id%type,
                               secondaryid       out secondaryuniqueitem.secondaryid%type);
  procedure determinegarmentid2(sortingsystem     in varchar2,
                                idcode            in uniqueitem.primaryid%type,
                                plantcode         in plant.code%type,
                                uniqueitemid      out nocopy uniqueitem.uniqueitem_id%type,
                                pool              out nocopy uniqueitem.poolitem%type,
                                unitcode          out nocopy businessunit.code%type,
                                businessunitid    out nocopy businessunit.businessunit_id%type,
                                plantid_garment   out nocopy plant.plant_id%type,
                                returnedplantcode out nocopy plant.code%type,
                                status            out nocopy integer,
                                idprimary         out uniqueitem.primaryid%type,
                                plantid_param     out nocopy plant.plant_id%type,
                                secondaryid       out secondaryuniqueitem.secondaryid%type,
                                relatedcustomerid out nocopy uniqueitem.relatedcustomer_id%type,
                                productid         out nocopy product.product_id%type,
                                sizeid            out nocopy sizedefinition.sizedefinition_id%type,
                                batchnumber       out nocopy uniqueitem.batchnumber%type,
                                prevstayid        out nocopy uniqueitem.prevstay_id%type,
                                plastinscandate   out nocopy uniqueitem.lastinscandate%type);
  procedure getsystemsettings(plantid_param   in plant.plant_id%type,
                              debuglevel      out nocopy integer,
                              utldir          out nocopy varchar2,
                              allowrepairscan out nocopy integer,
                              getgarment      in number default 0);
  procedure getgarmentlocation(lockerid             in locker.locker_id%type,
                               garmentdispenserid   in garmentdispenser.garmentdispenser_id%type,
                               deliverypointid      in out deliverypoint.deliverypoint_id%type,
                               banklocker           out nocopy varchar2,
                               garmentdispensercode out nocopy garmentdispenser.code%type,
                               deliverypointcode    out nocopy deliverypoint.code%type);
  procedure getgarmentdatainfo(sortingsystem           in varchar2,
                               plantid_garment         in plant.plant_id%type,
                               uniqueitemid            in uniqueitem.uniqueitem_id%type,
                               languageid              in out languages.language_id%type,
                               finishingcodeid         out nocopy finishingcode.finishingcode_id%type,
                               serviceteamid           out nocopy serviceteam.serviceteam_id%type,
                               vchargerepairs          out nocopy customer.chargerepairs%type,
                               vcustomerowned          out nocopy uniqueitem.customerowned%type,
                               colorid                 out nocopy color.color_id%type,
                               wearerflagid            out nocopy flag.flag_id%type,
                               wearerflagstartdate     out nocopy date,
                               empflagid               out nocopy flag.flag_id%type,
                               empflagstartdate        out nocopy date,
                               finishingmethodid       out nocopy finishingmethod.finishingmethod_id%type,
                               productid               out nocopy product.product_id%type,
                               productcode             out nocopy product.code%type,
                               productdescription      out nocopy product_desc.description%type,
                               sizecode                out nocopy sizedefinition.code%type,
                               customernumber          out nocopy customer.customernumber%type,
                               customerid              out nocopy customer.customer_id%type,
                               customername            out nocopy customer.name%type,
                               wearernumber            out nocopy wearer.wearernumber%type,
                               wearername              out nocopy wearer.searchname%type,
                               banklocker              out nocopy varchar2,
                               departmentnumber        out nocopy department.departmentnumber%type,
                               customeremployeenumber  out nocopy wearer.customeremployeenumber%type,
                               gender                  out nocopy wearer.sex%type,
                               garmentdispensercode    out nocopy garmentdispenser.code%type,
                               deliverypointcode       out nocopy deliverypoint.code%type,
                               infotext                out nocopy wearer.remark%type,
                               routenumber             out nocopy route.routenumber%type,
                               routeday                out nocopy day.daynumber%type,
                               stopnumber              out nocopy routestop.stopnumber%type,
                               packingsequence         out nocopy product.packingsequence%type,
                               stayid                  out nocopy stay.stay_id%type,
                               routeid                 out nocopy route.route_id%type,
                               imageid                 out nocopy product.image_id%type,
                               routestopid             out nocopy routestop.routestop_id%type,
                               planneddate             out nocopy date,
                               statusout               out nocopy integer,
                               valternatesortingstring out nocopy customer.alternatesorting%type,
                               debuglevel              in integer,
                               findpackingnote         in out varchar2,
                               pnnotenumber            out packingnote.notenumber%type,
                               routedate               in out date,
                               fp_washestotal          out nocopy uniqueitem.washestotal%type,
                               fp_routecodeonlabel     out nocopy route.codeonlabel%type,
                               fp_plant_idparam        in plant.plant_id%type default null,
                               fp_sortcustomerid       out nocopy customer.sortcustomer_id%type,
                               fp_languagecode         in languages.code%type default null);
  function convertstringdesc(receivedstring varchar2) return varchar2;
  function buildsortstring(productcode          in product.code%type,
                           sizecode             in sizedefinition.code%type,
                           customernumber       in customer.customernumber%type,
                           customerid           in customer.customer_id%type,
                           wearernumber         in wearer.wearernumber%type,
                           wearername           in wearer.searchname%type,
                           banklocker           in varchar2,
                           departmentnumber     in department.departmentnumber%type,
                           customeremployee#    in wearer.customeremployeenumber%type,
                           gender               in wearer.sex%type,
                           garmentdispensercode in garmentdispenser.code%type,
                           deliverypointcode    in deliverypoint.code%type,
                           stopnumber           in routestop.stopnumber%type,
                           plantid_param        in plant.plant_id%type,
                           customerownedyn      in varchar2,
                           ordernumber          in packingnote.notenumber%type,
                           productsortgroupseq  in productsortgroupperplant.sequencenumber%type,
                           lockersortgroup#     in lockersortgroup.lockersortgroupnumber%type,
                           distributionpoint#   in distributionpoint.distributionpointnumber%type,
                           fp_sortcustomerid    in customer.sortcustomer_id%type,
                           fp_seasoncode        in season.code%type,
                           fp_finsortstring     in sortaddressperfinishingcode.sortaddress%type default null,
                           fp_stackchange       in sortingdefinition.stackchange%type default 'N')
    return varchar2;
  function buildstackchangeinfo(productcode          in product.code%type,
                                sizecode             in sizedefinition.code%type,
                                customernumber       in customer.customernumber%type,
                                customerid           in customer.customer_id%type,
                                wearernumber         in wearer.wearernumber%type,
                                wearername           in wearer.searchname%type,
                                banklocker           in varchar2,
                                departmentnumber     in department.departmentnumber%type,
                                customeremployee#    in wearer.customeremployeenumber%type,
                                gender               in wearer.sex%type,
                                garmentdispensercode in garmentdispenser.code%type,
                                deliverypointcode    in deliverypoint.code%type,
                                stopnumber           in routestop.stopnumber%type,
                                plantid_param        in plant.plant_id%type,
                                customerownedyn      in varchar2,
                                ordernumber          in packingnote.notenumber%type,
                                productsortgroupseq  in productsortgroupperplant.sequencenumber%type,
                                lockersortgroup#     in lockersortgroup.lockersortgroupnumber%type,
                                distributionpoint#   in distributionpoint.distributionpointnumber%type,
                                fp_sortcustomerid    in customer.sortcustomer_id%type,
                                fp_seasoncode        in season.code%type,
                                fp_finsortstring     in sortaddressperfinishingcode.sortaddress%type default null)
    return varchar2;
  function getsortstring(plantid_param in plant.plant_id%type,
                         customerid    in customer.customer_id%type,
                         routestopid   in routestop.routestop_id%type,
                         uniqueitemid  in uniqueitem.uniqueitem_id%type)
    return varchar2;
  procedure getdeliverydaysmask(customerid      in customer.customer_id%type,
                                deliverydaymask out nocopy varchar2);
  procedure getdepot(routeid in route.route_id%type,
                     depot   out nocopy depot.code%type);
  function updateflags(flagsstring    in varchar2,
                       uniqueitemid   in uniqueitem.uniqueitem_id%type,
                       fplastscandate in date,
                       systemuserid   in systemuser.systemuser_id%type,
                       debuglevel     in integer) return integer;
  procedure getsendtrackinfo(pool                 in uniqueitem.poolitem%type,
                             uniqueitemid         in uniqueitem.uniqueitem_id%type,
                             stayid               out nocopy stay.stay_id%type,
                             statusid             out nocopy status.status_id%type,
                             productid            out nocopy product.product_id%type,
                             sizeid               out nocopy sizedefinition.sizedefinition_id%type,
                             weareremploymentid   out nocopy weareremployment.weareremployment_id%type,
                             customerid           out nocopy customer.customer_id%type,
                             vissuedate           out nocopy date,
                             finishingmethodid    out nocopy finishingmethod.finishingmethod_id%type,
                             distributionpointid  out nocopy distributionpoint.distributionpoint_id%type,
                             lastdistribpointid   out nocopy distributionpoint_link.distributionpoint_link_id%type,
                             vwashestotal         out nocopy integer,
                             vcustomerowned       out nocopy varchar2,
                             qualitygradeid       out nocopy qualitygrade.qualitygrade_id%type,
                             vfirstissuedate      out nocopy date,
                             vnumberofissues      out nocopy integer,
                             vlastonstockdate     out nocopy date,
                             vdaysinstockprevious out nocopy integer,
                             vstatuschangedate    out nocopy date,
                             vstartrentfrom       out nocopy integer,
                             vdaysincircprevissue out nocopy integer,
                             vwashesthisissue     out nocopy integer,
                             unrelatedloanid      out nocopy unrelatedloan.unrelatedloan_id%type,
                             vlastinscandate      out nocopy date,
                             deliverypointid      out nocopy deliverypoint.deliverypoint_id%type,
                             lockerid             out nocopy locker.locker_id%type,
                             garmentdispenserid   out nocopy garmentdispenser.garmentdispenser_id%type,
                             accept               in out varchar2);
  procedure writelogfile(sortsystem           in varchar2,
                         debuglevel           in integer,
                         plantcode            in plant.code%type,
                         idcode               in uniqueitem.primaryid%type,
                         unitcode             in businessunit.code%type,
                         status               in varchar2,
                         finishselection      in varchar2,
                         checkpointselection  in varchar2,
                         repairselection      in varchar2,
                         destination          in varchar2,
                         fold                 in varchar2,
                         stackchangeinfo      in varchar2,
                         routenumber          in integer,
                         stopnumber           in integer,
                         routeday             in day.daynumber%type,
                         depot                in varchar2,
                         sortstring           in varchar2,
                         alternatesortstring  in varchar2,
                         customernumber       in customer.customernumber%type,
                         customername         in customer.name%type,
                         wearernumber         in wearer.wearernumber%type,
                         wearername           in wearer.searchname%type,
                         department           in department.departmentnumber%type,
                         customeremployee#    in wearer.customeremployeenumber%type,
                         gender               in wearer.sex%type,
                         banklocker           in varchar2,
                         garmentdispensercode in garmentdispenser.code%type,
                         deliverypointcode    in deliverypoint.code%type,
                         productcode          in product.code%type,
                         productdescription   in product_desc.description%type,
                         sizecode             in sizedefinition.code%type,
                         productpicturecode   in image.code%type,
                         deliverydaymask      in varchar2,
                         secondaryid          in secondaryuniqueitem.secondaryid%type,
                         flagcode1            in sortaddressperflag.sortaddress%type,
                         flagcode2            in sortaddressperflag.sortaddress%type,
                         flagcode3            in sortaddressperflag.sortaddress%type,
                         flagcode4            in sortaddressperflag.sortaddress%type,
                         flagdescription1     in flag_desc.description%type,
                         flagdescription2     in flag_desc.description%type,
                         flagdescription3     in flag_desc.description%type,
                         flagdescription4     in flag_desc.description%type,
                         infotext             in wearer.remark%type,
                         requiredrepairs      in varchar2,
                         flags                in varchar2,
                         staycode             in varchar2,
                         sortbatchnumber      in integer,
                         spare2               in varchar2);
  function iscustomervisitdate(customerid  customer.customer_id%type,
                               planneddate date) return boolean;
  function iscustomervisitdateint(customerid  customer.customer_id%type,
                                  planneddate date) return integer;
  function isdepartmentdeliverydayint(depid  department.department_id%type,
                                      delday day.day_id%type) return integer;
  procedure processcheckpointscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                                  idcode          in uniqueitem.primaryid%type,
                                  pool            in integer,
                                  secondaryid     in secondaryuniqueitem.secondaryid%type,
                                  businessunitid  in businessunit.businessunit_id%type,
                                  uniqueitemid    in uniqueitem.uniqueitem_id%type,
                                  workstationcode in workstation.code%type,
                                  datep           in number,
                                  timep           in varchar2,
                                  systemuserid    in systemuser.systemuser_id%type,
                                  debuglevel      in integer,
                                  accept          out varchar2,
                                  scanbyroute     in varchar2,
                                  plantid_garment in plant.plant_id%type,
                                  flagcode1       in sortaddressperflag.sortaddress%type default null,
                                  flagcode2       in sortaddressperflag.sortaddress%type default null,
                                  flagcode3       in sortaddressperflag.sortaddress%type default null,
                                  flagcode4       in sortaddressperflag.sortaddress%type default null,
                                  fpbatchnumber   in scan.batchnumber%type default null);
  procedure processinscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                          idcode          in uniqueitem.primaryid%type,
                          pool            in integer,
                          secondaryid     in secondaryuniqueitem.secondaryid%type,
                          plantid_garment in plant.plant_id%type,
                          plantid_param   in plant.plant_id%type,
                          businessunitid  in businessunit.businessunit_id%type,
                          uniqueitemid    in uniqueitem.uniqueitem_id%type,
                          workstationcode in workstation.code%type,
                          datep           in number,
                          timep           in varchar2,
                          countwashesat   in varchar2,
                          scanbyroute     in varchar2,
                          systemuserid    in systemuser.systemuser_id%type,
                          debuglevel      in integer,
                          accept          out varchar2,
                          scaninterval    out varchar2,
                          pickuproutedate in date,
                          fpsretransferyn in varchar2 default 'N',
                          flagcode1       in sortaddressperflag.sortaddress%type default null,
                          flagcode2       in sortaddressperflag.sortaddress%type default null,
                          flagcode3       in sortaddressperflag.sortaddress%type default null,
                          flagcode4       in sortaddressperflag.sortaddress%type default null,
                          fpbatchnumber   in scan.batchnumber%type default null);
  procedure processoutscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                           idcode          in uniqueitem.primaryid%type,
                           secondaryid     in secondaryuniqueitem.secondaryid%type,
                           plantid_garment in plant.plant_id%type,
                           plantid_param   in plant.plant_id%type,
                           businessunitid  in businessunit.businessunit_id%type,
                           uniqueitemid    in uniqueitem.uniqueitem_id%type,
                           workstationid   in workstation.workstation_id%type,
                           workstationcode in workstation.code%type,
                           datep           in number,
                           timep           in varchar2,
                           countwashesat   in varchar2,
                           scanbyroute     in varchar2,
                           systemuserid    in systemuser.systemuser_id%type,
                           debuglevel      in integer,
                           accept          out varchar2,
                           scaninterval    out varchar2,
                           packingnoteid   in integer,
                           statusout       out integer,
                           flagcode1       in sortaddressperflag.sortaddress%type default null,
                           flagcode2       in sortaddressperflag.sortaddress%type default null,
                           flagcode3       in sortaddressperflag.sortaddress%type default null,
                           flagcode4       in sortaddressperflag.sortaddress%type default null,
                           m_deliveryscan  in varchar2 default 'Y',
                           fpbatchnumber   in scan.batchnumber%type default null);
  procedure processrepairscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                              idcode          in uniqueitem.primaryid%type,
                              pool            in integer,
                              secondaryid     in secondaryuniqueitem.secondaryid%type,
                              businessunitid  in businessunit.businessunit_id%type,
                              uniqueitemid    in uniqueitem.uniqueitem_id%type,
                              workstationcode in workstation.code%type,
                              datep           in number,
                              timep           in varchar2,
                              repairsdone     in varchar2,
                              systemuserid    in systemuser.systemuser_id%type,
                              debuglevel      in integer,
                              accept          out varchar2,
                              flagcode1       in sortaddressperflag.sortaddress%type default null,
                              flagcode2       in sortaddressperflag.sortaddress%type default null,
                              flagcode3       in sortaddressperflag.sortaddress%type default null,
                              flagcode4       in sortaddressperflag.sortaddress%type default null);
  procedure processrewash(transactiontp   in sortingimportdefinition.transactiontype%type,
                          idcode          in uniqueitem.primaryid%type,
                          pool            in integer,
                          secondaryid     in secondaryuniqueitem.secondaryid%type,
                          plantid_garment in plant.plant_id%type,
                          plantid_param   in plant.plant_id%type,
                          businessunitid  in businessunit.businessunit_id%type,
                          uniqueitemid    in uniqueitem.uniqueitem_id%type,
                          workstationcode in workstation.code%type,
                          datep           in number,
                          timep           in varchar2,
                          scanbyroute     in varchar2,
                          systemuserid    in systemuser.systemuser_id%type,
                          debuglevel      in integer,
                          accept          out varchar2,
                          flagcode1       in sortaddressperflag.sortaddress%type default null,
                          flagcode2       in sortaddressperflag.sortaddress%type default null,
                          flagcode3       in sortaddressperflag.sortaddress%type default null,
                          flagcode4       in sortaddressperflag.sortaddress%type default null);
  procedure processsortscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                            idcode          in uniqueitem.primaryid%type,
                            pool            in integer,
                            secondaryid     in secondaryuniqueitem.secondaryid%type,
                            businessunitid  in businessunit.businessunit_id%type,
                            uniqueitemid    in uniqueitem.uniqueitem_id%type,
                            workstationcode in workstation.code%type,
                            datep           in number,
                            timep           in varchar2,
                            systemuserid    in systemuser.systemuser_id%type,
                            debuglevel      in integer,
                            accept          out varchar2,
                            flagcode1       in sortaddressperflag.sortaddress%type default null,
                            flagcode2       in sortaddressperflag.sortaddress%type default null,
                            flagcode3       in sortaddressperflag.sortaddress%type default null,
                            flagcode4       in sortaddressperflag.sortaddress%type default null,
                            fpbatchnumber   in scan.batchnumber%type default null);
  function iscustomeractive(customerid   customer.customer_id%type,
                            specificdate date) return boolean;
  function getstopstatus(customerid   customer.customer_id%type,
                         specificdate date) return number;
  procedure importsoilscan(fpnplantid      plant.plant_id%type,
                           fpsreadfilename varchar2);
  function getsortstringsupport(plantid      in plant.plant_id%type,
                                customerid   in customer.customer_id%type,
                                routestopid  in routestop.routestop_id%type,
                                uniqueitemid in uniqueitem.uniqueitem_id%type)
    return varchar2;

  function iscustomer_nonbusinessday(customerid  customer.customer_id%type,
                                     planneddate date) return boolean;
  procedure getnextdeliverydatewithstop(currentdate     in date,
                                        plantid         in plant.plant_id%type,
                                        customerid      in customer.customer_id%type,
                                        typeofmerch     in product.typeofmerchandise%type,
                                        deliverypointid in deliverypoint.deliverypoint_id%type,
                                        retvisitdate    out date,
                                        retroute        out route.route_id%type);
  procedure addmaxrepairflag(uniqueitemid        in uniqueitem.uniqueitem_id%type,
                             systemuserid        in systemuser.systemuser_id%type,
                             debuglevel          in integer,
                             businessunitid      in businessunit.businessunit_id%type,
                             pool                in integer,
                             vlastscandate       in date,
                             repairstotal        in integer,
                             productid           in product.product_id%type,
                             sizeid              in sizedefinition.sizedefinition_id%type,
                             finishingmethodid   in finishingmethod.finishingmethod_id%type,
                             distributionpointid in distributionpoint.distributionpoint_id%type);
  procedure processfakeinscanforgarments(
                              plantid_garment    in plant.plant_id%type,
                              businessunitid     in businessunit.businessunit_id%type,
                              idcode             in uniqueitem.primaryid%type,
                              uniqueitemid       in uniqueitem.uniqueitem_id%type,
                              secondaryid        in secondaryuniqueitem.secondaryid%type,
                              scanbyroute        in varchar2,
                              systemuserid       in systemuser.systemuser_id%type);
  procedure processonsiteinvetoryscan(transactiontp       in sortingimportdefinition.transactiontype%type,
                                      idcode              in uniqueitem.primaryid%type,
                                      businessunitid      in businessunit.businessunit_id%type,
                                      plantid             in plant.plant_id%type default null,
                                      uniqueitemid        in uniqueitem.uniqueitem_id%type,
                                      workstationcode     in workstation.code%type,
                                      gv_lastscandatetime in varchar2,
                                      systemuserid        in systemuser.systemuser_id%type,
                                      debuglevel          in integer,
                                      accept              out varchar2);
end pack_sort;
/
create or replace package body pack_sort is
  --order 20012023, additional getgarmentdata metricon fields
  gv_sortroutestop varchar2(1);
  --SO 20015256 logging in database instead of to files
  procedure write_logging(fp_message    in abslog.message%type,
                          fp_loglevel   in number,
                          fp_logname    in varchar2,
                          fp_plantid    in plant.plant_id%type default null,
                          fp_priority   in number default 1,
                          fp_detailinfo in number default 0) is ---0=no detail 1=detail
  begin
    --write_logging
    if fp_priority > 1 then
      begin
        abslogwrite.abslog_write(5,
                                 fp_logname,
                                 fp_plantid,
                                 fp_priority,
                                 fp_message);
      end;
    else
      case fp_loglevel
        when 0 then
          null; --no logging other then errors
        when 1 then
          if fp_detailinfo = 1 then
            --Log level 1 and detailinfo=1 write detail info
            abslogwrite.abslog_write(5,
                                     fp_logname,
                                     fp_plantid,
                                     fp_priority,
                                     fp_message);
          end if;
        when 2 then
          --write all logs
          abslogwrite.abslog_write(5,
                                   fp_logname,
                                   fp_plantid,
                                   fp_priority,
                                   fp_message);
        else
          null;
      end case;
    end if;
  end write_logging;

  ---
  function verify_routeid(plantid plant.plant_id%type, routeid route.route_id%type, additional varchar2) return number is
    routeplant plant.plant_id%type;
  begin
    select r.plant_id into routeplant from route r where r.route_id = routeid;
    if (routeplant != plantid) then
      write_logging('Route id = ' || routeid || ' from plant id = ' || routeplant ||
                    ' doesn''t belong to garment plant id ' || plantid || additional || chr(10) ||
                    DBMS_UTILITY.format_call_stack,
                    5,
                    'PACK_SORT.VERIFYROUTE',
                    plantid,
                    3,
                    1);
      return routeplant;
    end if;
    return 0;
  exception
    when no_data_found then
      return 0;
  end verify_routeid;

  function iscustomervisitdateint(customerid  customer.customer_id%type,
                                  planneddate date) return integer is
    xyear integer;
    xweek integer;
    xday  integer;
    i     integer;
  begin
    i     := 0;
    xday  := getabsdaynumber(planneddate);
    xweek := getisoweek(planneddate);
    xyear := getyearofweek(planneddate);
    for dcursor in (select d.deliveryscheme_id,
                           x.frequency,
                           x.offsetweek,
                           c.day_id
                      from customerdeliveryday    c,
                           customerdeliveryscheme d,
                           deliveryscheme         x
                     where c.customer_id = customerid
                       and c.customer_id = d.customer_id
                       and c.day_id = d.day_id
                       and d.deliveryscheme_id = x.deliveryscheme_id
                       and c.day_id = xday) loop
      begin
        if isweekdeliveryweek(xyear,
                              xweek,
                              dcursor.frequency,
                              dcursor.offsetweek) then
          i := 1;
          exit;
        end if;
      end;
    end loop;
    if i = 1 then
      return 1;
    else
      return 0;
    end if;
  end iscustomervisitdateint;
  function isdepartmentdeliverydayint(depid  department.department_id%type,
                                      delday day.day_id%type) return integer is
    depdelday deliveryday.day_id%type;
  begin
    begin
      select dd.day_id
        into depdelday
        from deliveryday dd
       where dd.department_id = depid
         and dd.day_id = delday;
    exception
      when no_data_found then
        return 1;
    end;
    if depdelday = delday then
      return 0;
    end if;
  end isdepartmentdeliverydayint;
  procedure getadditionalabelinfo(fp_idcode                      in uniqueitem.primaryid%type,
                                  fp_unitcode                    in businessunit.code%type,
                                  fp_deliverypointcode           in deliverypoint.code%type,
                                  fp_departmentdescription       out department.description%type,
                                  fp_consumptionpointnumber      out distributionpoint.distributionpointnumber%type,
                                  fp_consumptionpointdescription out distributionpoint.description%type,
                                  fp_deliverypointdescription    out deliverypoint.description%type,
                                  fp_deliverypointstreet1        out address.street%type,
                                  fp_deliverypointstreet2        out address.street2%type,
                                  fp_deliverypointzipcode        out address.zipcode%type,
                                  fp_deliverypointcity           out address.city%type,
                                  fp_transportarticledescription out transportarticle_desc.description%type) is
    lv_poolitem            uniqueitem.poolitem%type;
    lv_customerid          customer.customer_id%type;
    lv_distributionpointid distributionpoint.distributionpoint_id%type;
    lv_plantid             plant.plant_id%type;
    lv_languageid          languages.language_id%type;
    lv_sortcustomerid      customer.customer_id%type;
    lv_externalockerid     locker.locker_id%type;

    procedure make_null is
    begin
      --make all output variables null
      fp_departmentdescription       := null;
      fp_consumptionpointnumber      := null;
      fp_consumptionpointdescription := null;
      fp_deliverypointdescription    := null;
      fp_deliverypointstreet1        := null;
      fp_deliverypointstreet2        := null;
      fp_deliverypointzipcode        := null;
      fp_deliverypointcity           := null;
      fp_transportarticledescription := null;
    end make_null;
  begin
    make_null;
    --get garment id
    select u.poolitem,
           t.description,
           dp.distributionpointnumber,
           dp.description,
           t.customer_id,
           bu.plant_id,
           dp.distributionpoint_id,
           pt.language_id,
           c.sortcustomer_id,
           we.externallocker_id
      into lv_poolitem,
           fp_departmentdescription,
           fp_consumptionpointnumber,
           fp_consumptionpointdescription,
           lv_customerid,
           lv_plantid,
           lv_distributionpointid,
           lv_languageid,
           lv_sortcustomerid,
           lv_externalockerid
      from uniqueitem        u,
           uniqueitemnonpool un,
           businessunit      bu,
           weareremployment  we,
           department        t,
           distributionpoint dp,
           plant             pt,
           customer          c
     where u.primaryid = fp_idcode
       and u.businessunit_id = bu.businessunit_id
       and bu.code = fp_unitcode
       and u.uniqueitem_id = un.uniqueitem_id
       and bu.plant_id = pt.plant_id
       and un.weareremployment_id = we.weareremployment_id
       and we.distributionpoint_id = dp.distributionpoint_id
       and dp.department_id = t.department_id
       and c.customer_id = t.customer_id;
    --do nothing for pool=1
    if lv_poolitem <> 1 then
      begin
        begin
          -- Order 20013679 take delivery point info from sort customer
          if lv_externalockerid is not null and
             lv_sortcustomerid is not null then
            lv_customerid := lv_sortcustomerid;
          end if;
          --get deliverypoint
          select dpo.description,
                 ad.street,
                 ad.street2,
                 ad.zipcode,
                 ad.city
            into fp_deliverypointdescription,
                 fp_deliverypointstreet1,
                 fp_deliverypointstreet2,
                 fp_deliverypointzipcode,
                 fp_deliverypointcity
            from deliverypoint dpo, address ad
           where dpo.customer_id = lv_customerid
             and dpo.code = trim(fp_deliverypointcode)
             and dpo.deliveryaddress_id = ad.address_id;
        exception
          when no_data_found then
            begin
              fp_deliverypointdescription := null;
              fp_deliverypointstreet1     := null;
              fp_deliverypointstreet2     := null;
              fp_deliverypointzipcode     := null;
              fp_deliverypointcity        := null;
            end;
        end;
        begin
          --get transportarticledescription
          select td.description
            into fp_transportarticledescription
            from standarddelivery std, transportarticle_desc td
           where std.distributionpoint_id = lv_distributionpointid
             and std.sequencenumber = 1
             and std.transportarticle_id = td.transportarticle_id
             and td.language_id = lv_languageid;
        exception
          when no_data_found then
            begin
              fp_transportarticledescription := null;
            end;
        end;
      end; --lv_poolitem <> 1
    else
      make_null; --nothing to be returned
    end if;
  exception
    when no_data_found then
      make_null; --nothing to be returned
  end getadditionalabelinfo;
  --begin 502877
  function create_uniqueitemflag(fp_logname         in abslog.logsource%type,
                                 fp_debuglevel      in integer,
                                 fp_systemuserid    in systemuser.systemuser_id%type,
                                 fp_uniqueitemid    in uniqueitem.uniqueitem_id%type,
                                 fp_flagid          in flag.flag_id%type,
                                 fp_startdate       in uniqueitemflag.startdate%type default sysdate,
                                 fp_scanid          in scan.scan_id%type default null,
                                 fp_freetextitem    in uniqueitemflag.freetextitem%type default null,
                                 fp_treatmenttypeid in uniqueitemflag.treatmenttype_id%type default null,
                                 fp_plantid_param   in plant.plant_id%type default null)
    return boolean is
    lvcounter    number;
    flaginserted boolean;
  begin
    flaginserted := false;

    -- if flag id is null, then return
    if (fp_flagid is null) then
      return false;
    end if;

    --check if flag did not already exist yes or no
    select count(u.flag_id)
      into lvcounter
      from uniqueitemflag u
     where u.uniqueitem_id = fp_uniqueitemid
       and u.flag_id = fp_flagid;
    --only add flag when it did not yet exist, then counter=0
    if lvcounter = 0 then
      --insert into uniqueitemflag
      insert into uniqueitemflag
        (uniqueitem_id,
         flag_id,
         startdate,
         freetextitem,
         systemuser_id,
         timestamp,
         treatmenttype_id)
      values
        (fp_uniqueitemid,
         fp_flagid,
         trunc(fp_startdate),
         fp_freetextitem,
         fp_systemuserid,
         sysdate,
         fp_treatmenttypeid);
      flaginserted := true;
      --add scanflag when scanid is known
      if fp_scanid is not null then
        insert into scanflag
          (scan_id, flag_id, flagresponse, systemuser_id, timestamp)
        values
          (fp_scanid, fp_flagid, 'N', fp_systemuserid, sysdate);
      end if;
      --add debud information when needed
      if fp_debuglevel > 0 then
        pack_sort.write_logging('PACK_SORT.CREATE_UNIQUEITEMFLAG Insert uniqueitemflag for uniqueitemid ' ||
                                fp_uniqueitemid || ' flagid ' || fp_flagid ||
                                ' insert scanflag ' ||
                                nvl(to_char(fp_scanid), 'NULL'),
                                fp_debuglevel,
                                fp_logname,
                                fp_plantid_param,
                                1,
                                1);
      end if;
    end if; --lvcounter
    return flaginserted;
  exception
    when dup_val_on_index then
      return flaginserted;
      --does not matter when flag already exist
    when others then
      pack_sort.write_logging('PACK_SORT.CREATE_UNIQUEITEMFLAG !> create flagid ' ||
                              fp_flagid || ' for uniqueitemid ' ||
                              fp_uniqueitemid || ' ' || sqlerrm,
                              fp_debuglevel,
                              fp_logname,
                              fp_plantid_param,
                              3,
                              1);
      return flaginserted;
  end create_uniqueitemflag;

  function process_plpctreatmntcheckschm(fp_plpcid                     in productlistpercustomer.productlistpercustomer_id%type,
                                         fp_checkpercentage            in treatmentcheckschemedetail.checkpercentage%type,
                                         fp_treatmentchkschemedetailid in plpctreatmentcheckscheme.treatmentcheckschemedetail_id%type,
                                         fp_systemuserid               in systemuser.systemuser_id%type)
    return plpctreatmentcheckscheme.factor%type is
    lv_plpc_treat_factor plpctreatmentcheckscheme.factor%type;
  begin
    --get factor
    select pt.factor + (fp_checkpercentage / 100)
      into lv_plpc_treat_factor
      from plpctreatmentcheckscheme pt
     where pt.treatmentcheckschemedetail_id = fp_treatmentchkschemedetailid
       and pt.productlistpercustomer_id = fp_plpcid;
    --check if update is needed
    if lv_plpc_treat_factor > 1 then
      update plpctreatmentcheckscheme pt
         set pt.factor        = lv_plpc_treat_factor - 1,
             pt.systemuser_id = fp_systemuserid,
             pt.timestamp     = sysdate
       where pt.treatmentcheckschemedetail_id =
             fp_treatmentchkschemedetailid
         and pt.productlistpercustomer_id = fp_plpcid;
    else
      update plpctreatmentcheckscheme pt
         set pt.factor        = lv_plpc_treat_factor,
             pt.systemuser_id = fp_systemuserid,
             pt.timestamp     = sysdate
       where pt.treatmentcheckschemedetail_id =
             fp_treatmentchkschemedetailid
         and pt.productlistpercustomer_id = fp_plpcid;
    end if;
    return lv_plpc_treat_factor;
  exception
    when no_data_found then
      begin
        lv_plpc_treat_factor := (fp_checkpercentage / 100);
        insert into plpctreatmentcheckscheme
          (treatmentcheckschemedetail_id,
           productlistpercustomer_id,
           factor,
           systemuser_id,
           timestamp)
        values
          (fp_treatmentchkschemedetailid,
           fp_plpcid,
           lv_plpc_treat_factor,
           fp_systemuserid,
           sysdate);
        return lv_plpc_treat_factor;
      end;
  end process_plpctreatmntcheckschm;
  procedure add_treatmentcheck_flags(fp_debuglevel             in integer,
                                     fp_systemuserid           in systemuser.systemuser_id%type,
                                     fp_uniqueitemid           in uniqueitem.uniqueitem_id%type,
                                     fp_startdate              in uniqueitemflag.startdate%type default sysdate,
                                     fp_scanid                 in scan.scan_id%type default null,
                                     fp_freetextitem           in uniqueitemflag.freetextitem%type default null,
                                     fp_treatmentcheckschemeid in out productlistpercustomer.treatmentcheckscheme_id%type,
                                     fp_nrofwashes             in number,
                                     fp_plantid_param          in plant.plant_id%type,
                                     fp_productid              in product.product_id%type,
                                     fp_plpcid                 in productlistpercustomer.productlistpercustomer_id%type) is
    lv_plpc_treat_factor plpctreatmentcheckscheme.factor%type;
    flaginserted         boolean;
  begin
    --if fp_treatmentcheckid is null try to get it on another level
    if fp_treatmentcheckschemeid is null then
      begin
        begin
          select ps.treatmentcheckscheme_id
            into fp_treatmentcheckschemeid
            from plantproductsettings ps
           where ps.plant_id = fp_plantid_param
             and ps.product_id = fp_productid;
        exception
          when no_data_found then
            fp_treatmentcheckschemeid := null;
        end;
        if fp_treatmentcheckschemeid is null then
          begin
            select p.treatmentcheckscheme_id
              into fp_treatmentcheckschemeid
              from product p
             where p.product_id = fp_productid;
          end;
        end if;
      end;
    end if; --fp_treatmentcheckid is null
    --fp_treatmentcheckid is not null then check for flags
    if fp_treatmentcheckschemeid is not null then
      begin
        --0 = Fixed  1 = Repeated
        for x in (select tsd.flag_id,
                         tsd.checkpercentage,
                         tsd.treatmentcheckschemedetail_id,
                         tsd.treatmenttype_id
                    from treatmentcheckschemedetail tsd
                   where tsd.treatmentcheckscheme_id =
                         fp_treatmentcheckschemeid
                     and ((tsd.schemetype = 0 and tsd.washes = fp_nrofwashes) or
                         (tsd.schemetype = 1 and
                         fp_nrofwashes between tsd.fromwashes and
                         tsd.towashes and
                         (mod((fp_nrofwashes - tsd.fromwashes),
                                tsd.repeatwashes) = 0)))) loop
          begin
            if x.checkpercentage = 100 then
              lv_plpc_treat_factor := 1;
            else
              begin
                --get current factor
                lv_plpc_treat_factor := process_plpctreatmntcheckschm(fp_plpcid,
                                                                      x.checkpercentage,
                                                                      fp_treatmentcheckschemeid,
                                                                      fp_systemuserid);
              end;
            end if;
            if lv_plpc_treat_factor >= 1 then
              flaginserted := create_uniqueitemflag('PACK_SORT.ADD_TREATMENTCHECK_FLAGS',
                                                    fp_debuglevel,
                                                    fp_systemuserid,
                                                    fp_uniqueitemid,
                                                    x.flag_id,
                                                    fp_startdate,
                                                    fp_scanid,
                                                    fp_freetextitem,
                                                    x.treatmenttype_id,
                                                    fp_plantid_param);
            end if;
          end;
        end loop; --x
      end;
    end if;
  end add_treatmentcheck_flags;
  --end 502877
  procedure findplpcinfo(fp_customerid             in customer.customer_id%type,
                         fp_productid              in product.product_id%type,
                         fp_sizedefinitionid       in sizedefinition.sizedefinition_id%type,
                         fp_finishingmethodid      in finishingmethod.finishingmethod_id%type,
                         fp_deliverymethod         out integer,
                         fp_deedeliveryschemeid    out deliveryscheme.deliveryscheme_id%type,
                         fp_plpcid                 out productlistpercustomer.productlistpercustomer_id%type,
                         fp_maxwashes              out integer,
                         fp_plpcfinishingcode      out productlistpercustomer.finishingcode_id%type,
                         fp_plpcustomcode          out productlistpercustomer.customcode%type,
                         fp_plpcustomdescription   out productlistpercustomer.customdescription%type,
                         fp_chargewashesonlyforcog out varchar2,
                         fp_pbillingmethod         out productlistpercustomer.billingmethod%type,
                         fp_treatmentschemeid      out productlistpercustomer.treatmentcheckscheme_id%type) is
    lv_chargewashesonlyforcog productlistpercustomer.chargewashesonlyforcog%type;
  begin
    begin
      --find plpc for right size
      select p.productlistpercustomer_id,
             p.maxwashes,
             p.delayedevenexchange,
             p.deedeliveryscheme_id,
             p.finishingcode_id,
             p.customcode,
             p.customdescription,
             p.chargewashesonlyforcog,
             p.billingmethod,
             p.treatmentcheckscheme_id
        into fp_plpcid,
             fp_maxwashes,
             fp_deliverymethod,
             fp_deedeliveryschemeid,
             fp_plpcfinishingcode,
             fp_plpcustomcode,
             fp_plpcustomdescription,
             lv_chargewashesonlyforcog,
             fp_pbillingmethod,
             fp_treatmentschemeid
        from productlistpercustomer p
       where p.customer_id = fp_customerid
         and p.product_id = fp_productid
         and p.sizedefinition_id = fp_sizedefinitionid
         and p.finishingmethod_id = fp_finishingmethodid
         and sysdate between p.dateactive and p.dateinactive;
    exception
      when no_data_found then
        begin
          --when not found find for size *
          select p.productlistpercustomer_id,
                 p.maxwashes,
                 p.delayedevenexchange,
                 p.deedeliveryscheme_id,
                 p.finishingcode_id,
                 p.customcode,
                 p.customdescription,
                 p.chargewashesonlyforcog,
                 p.billingmethod,
                 p.treatmentcheckscheme_id
            into fp_plpcid,
                 fp_maxwashes,
                 fp_deliverymethod,
                 fp_deedeliveryschemeid,
                 fp_plpcfinishingcode,
                 fp_plpcustomcode,
                 fp_plpcustomdescription,
                 lv_chargewashesonlyforcog,
                 fp_pbillingmethod,
                 fp_treatmentschemeid
            from productlistpercustomer p
           where p.customer_id = fp_customerid
             and p.product_id = fp_productid
             and p.sizedefinition_id = gv_specialsizeid -->size star
             and p.finishingmethod_id = fp_finishingmethodid
             and sysdate between p.dateactive and p.dateinactive;
        exception
          when no_data_found then
            fp_deliverymethod := 1;
        end;
    end;
    --todo24970 do not change fp_deliverymethod when 0 to 1
    --order501280
    if fp_deliverymethod = 7 and fp_deedeliveryschemeid is null then
      fp_deliverymethod := 1;
    end if;
    --501875
    if lv_chargewashesonlyforcog in (1, 3) then
      fp_chargewashesonlyforcog := 'Y';
    else
      fp_chargewashesonlyforcog := 'N';
    end if;
  end findplpcinfo;
  function getdeliveryweeksforyear(year      in integer,
                                   frequency in integer,
                                   offset    in integer) return deliveryweeks is
    delweeks       deliveryweeks;
    countdelweeks  integer;
    firstweek      integer;
    w              integer;
    wb             integer;
    currentdelweek integer;
    i              integer;
  begin
    firstweek      := getfirstdeliveryweekforyear(year, frequency, offset);
    w              := getweeksinyear(year);
    currentdelweek := firstweek;
    wb             := firstweek - frequency;
    i              := 1;
    while (wb > 0) loop
      begin
        delweeks(i) := wb;
        i := i + 1;
        wb := wb - frequency;
      end;
    end loop;
    countdelweeks := i;
    delweeks(countdelweeks) := currentdelweek;
    while (currentdelweek <= w) loop
      begin
        currentdelweek := currentdelweek + frequency;
        if (currentdelweek <= w) then
          begin
            countdelweeks := countdelweeks + 1;
            delweeks(countdelweeks) := currentdelweek;
          end;
        end if;
      end;
    end loop;
    return(delweeks);
  end getdeliveryweeksforyear;
  procedure getnextdeliveryweek(deliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                dayno            in day.day_id%type,
                                currentdate      in date,
                                nextdeliveryweek out integer,
                                nextdeliveryyear out integer) is
    --Result       date;
    currentweek  integer;
    currentyear  integer;
    currentday   integer;
    weeksinyear  integer;
    compareweek  integer;
    compareyear  integer;
    nextdelweekv integer;
    frequency    integer;
    offsetweek   integer;
    v            deliveryweeks;
    countv       integer;
  begin
    currentweek := getisoweek(currentdate);
    currentday  := getabsdaynumber(currentdate);
    currentyear := getyearofweek(currentdate);
    weeksinyear := getweeksinyear(currentyear);
    --  //determine comparation week and year depanding on the current date and selected visit day
    if currentday > dayno then
      compareweek := currentweek + 1;
    else
      compareweek := currentweek;
    end if;
    if (compareweek > weeksinyear) then
      begin
        compareweek := 1;
        compareyear := currentyear + 1;
      end;
    else
      compareyear := currentyear;
    end if;
    select d.frequency, d.offsetweek
      into frequency, offsetweek
      from deliveryscheme d
     where d.deliveryscheme_id = deliveryschemeid;
    --  get delivery weeks for compare year and selected delivery scheme
    v      := pack_sort.getdeliveryweeksforyear(compareyear,
                                                frequency,
                                                offsetweek);
    countv := v.count;
    --  if no delivery weeks found for current year get delivery weeks for next year
    if countv = 0 then
      begin
        compareyear := compareyear + 1;
        compareweek := 1;
        v           := pack_sort.getdeliveryweeksforyear(compareyear,
                                                         frequency,
                                                         offsetweek);
      end;
    end if;
    -- //determine next delivery week
    for i in v.first .. v.last loop
      if v(i) = compareweek then
        begin
          nextdelweekv := compareweek;
          exit;
        end;
      else
        nextdelweekv := 0;
      end if;
    end loop;
    if nextdelweekv = 0 then
      while (compareweek < weeksinyear) loop
        begin
          compareweek := compareweek + 1;
          for i in v.first .. v.last loop
            if v(i) = compareweek then
              begin
                nextdelweekv := compareweek;
                exit;
              end;
            else
              nextdelweekv := 0;
            end if;
          end loop;
          if nextdelweekv > 0 then
            exit;
          end if;
        end;
      end loop;
    end if;
    -- //if there is no next delivery week this year then det delivery week from next year
    if nextdelweekv = 0 then
      begin
        compareyear := compareyear + 1;
        compareweek := 1;
        v           := pack_sort.getdeliveryweeksforyear(compareyear,
                                                         frequency,
                                                         offsetweek);
        for i in v.first .. v.last loop
          if v(i) = compareweek then
            begin
              nextdelweekv := compareweek;
              exit;
            end;
          end if;
        end loop;
      end;
    end if;
    --  //if there is a next delivery week this year or next year then add it in the hash map
    if (nextdelweekv > 0) then
      nextdeliveryweek := nextdelweekv;
      nextdeliveryyear := compareyear;
    else
      nextdeliveryweek := 0;
      nextdeliveryyear := 0;
    end if;
  end getnextdeliveryweek;
  function getvisitdate(deliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                        dayno            in day.day_id%type,
                        currentdate      in date) return date is
    result           date;
    nextdeliveryweek integer;
    nextdeliveryyear integer;
  begin
    pack_sort.getnextdeliveryweek(deliveryschemeid,
                                  dayno,
                                  currentdate,
                                  nextdeliveryweek,
                                  nextdeliveryyear);
    if (nextdeliveryweek > 0) then
      result := getdateforweekyear(dayno,
                                   nextdeliveryweek,
                                   nextdeliveryyear);
    else
      return null;
    end if;
    return(result);
  end getvisitdate;
  function getnextdeliverydate(currentdate in date,
                               customerid  in customer.customer_id%type,
                               typeofmerch in product.typeofmerchandise%type)
    return date is
    result    date;
    visitdate date;
    dates     visitdates;
    i         integer;
  begin
    i := 1;
    for vcursor in (select c.day_id, d.deliveryscheme_id, x.frequency
                      from customerdeliveryday    c,
                           customerdeliveryscheme d,
                           deliveryscheme         x
                     where c.customer_id = customerid
                       and c.customer_id = d.customer_id
                       and c.day_id = d.day_id
                       and c.typeofmerchadise = typeofmerch
                       and c.deliverytype in ('B', 'D')
                       and d.deliveryscheme_id = x.deliveryscheme_id
                       and d.active = 'Y') loop
      begin
        visitdate := pack_sort.getvisitdate(vcursor.deliveryscheme_id,
                                            vcursor.day_id,
                                            currentdate);
        if visitdate is not null and visitdate >= currentdate then
          begin
            dates(to_char(visitdate, 'YYYYMMDD')) := i;
            i := i + 1;
          end;
        end if;
      end;
    end loop;
    result := to_date(dates.first, 'YYYYMMDD');
    return(result);
  end getnextdeliverydate;
  function getroutestopforcustomer(plantid_garment in plant.plant_id%type,
                                   visitdate       in date,
                                   customerid      in customer.customer_id%type,
                                   deliverypointid in integer) return integer is
    result   integer; --routestops;
    year     integer;
    week     integer;
    routeday integer;
    i        integer;
    aux      integer;
  begin
    select count(d.routestop_id)
      into aux
      from deliveryschemesperstop d
     where d.customer_id = customerid;
    if aux > 0 then
      year     := getyearofweek(visitdate);
      week     := getisoweek(visitdate);
      routeday := getabsdaynumber(visitdate);
      aux      := deliverypointid;
      i        := 0;
      result   := null;
      while i = 0 loop
        begin
          for vcursor in (select d.deliveryscheme_id,
                                 d.frequency,
                                 d.offsetweek
                            from customerdeliveryscheme c, deliveryscheme d
                           where c.customer_id = customerid
                             and c.day_id = routeday
                             and c.deliveryscheme_id = d.deliveryscheme_id
                             and c.active = 'Y'
                           order by d.frequency asc) loop
            if isweekdeliveryweek(year,
                                  week,
                                  vcursor.frequency,
                                  vcursor.offsetweek) then
              begin
                if aux is not null then
                  begin
                    select min(rs.routestop_id)
                      into result
                      from route r, routestop rs
                     where r.route_id = rs.route_id
                       and r.plant_id = plantid_garment
                       and r.drivingday_id = routeday
                          -- and    rs.dateactive <= trunc(sysdate) -- order 502746
                       and trunc(sysdate) < trunc(rs.dateinactive)
                       and trunc(visitdate) < trunc(rs.dateinactive)
                       and exists
                     (select d.routestop_id
                              from deliveryschemesperstop d
                             where d.customer_id = customerid
                               and d.deliveryscheme_id =
                                   vcursor.deliveryscheme_id
                               and d.day_id = routeday
                               and d.routestop_id = rs.routestop_id)
                       and rs.deliverypoint_id = aux;
                    if result is not null then
                      i := i + 1;
                    end if;
                  exception
                    when no_data_found then
                      result := 0;
                  end;
                else
                  begin
                    select min(rs.routestop_id)
                      into result
                      from route r, routestop rs
                     where r.route_id = rs.route_id
                       and r.plant_id = plantid_garment
                       and r.drivingday_id = routeday
                       and trunc(sysdate) < trunc(rs.dateinactive)
                       and trunc(visitdate) < trunc(rs.dateinactive)
                       and exists
                     (select d.routestop_id
                              from deliveryschemesperstop d
                             where d.customer_id = customerid
                               and d.deliveryscheme_id =
                                   vcursor.deliveryscheme_id
                               and d.day_id = routeday
                               and d.routestop_id = rs.routestop_id)
                       and    rs.deliverypoint_id is null;
                    if result is not null then
                      i := i + 1;
                    end if;
                  exception
                    when no_data_found then
                      result := 0;
                  end;
                end if;
                if result is not null then
                  exit;
                end if;
              end;
            end if;
          end loop;
          if i = 0 then
            if deliverypointid is not null and aux is not null then
              aux := null;
            else
              i := i + 1;
            end if;
          end if;
        end;
      end loop;
    end if;
    return(result);
  exception
    when others then
      null;
  end getroutestopforcustomer;
  procedure getlastinroute_debug(customerid      in customer.customer_id%type,
                           datex           in date,
                           deliverypointid in deliverypoint.deliverypoint_id%type,
                           typeofmerch     in product.typeofmerchandise%type,
                           plantid         in plant.plant_id%type,
                           lastinroute     out route.route_id%type,
                           routestopx      out routestop.routestop_id%type,
                           lastindate      out date) is
  ret number;
  begin
    getlastinroute(customerid, datex, deliverypointid, typeofmerch, lastinroute, routestopx, lastindate, plantid);
    ret := verify_routeid(plantid, lastinroute, ' (for customerid = ' || customerid || ')');
  end getlastinroute_debug;

  procedure getlastinroute(customerid      in customer.customer_id%type,
                           datex           in date,
                           deliverypointid in deliverypoint.deliverypoint_id%type,
                           typeofmerch     in product.typeofmerchandise%type,
                           lastinroute     out route.route_id%type,
                           routestopx      out routestop.routestop_id%type,
                           lastindate      out date,
                           garmentplantid  in route.plant_id%type default null) is
    startyear        integer;
    year             integer;
    dayx             integer;
    week             integer;
    cnt              integer;
    vdeliverypointid deliverypoint.deliverypoint_id%type;
  begin
    select count(d.routestop_id)
      into cnt
      from deliveryschemesperstop d
     where d.customer_id = customerid;
    if cnt > 0 then
      vdeliverypointid := deliverypointid;
      startyear        := getyearofweek(datex);
      dayx             := getabsdaynumber(datex);
      week             := getisoweek(datex);
      lastindate       := datex;
      while dayx <> 0 loop
        begin
          for vcursor in (select ds.routestop_id,
                                 c.day_id,
                                 ds.deliveryscheme_id,
                                 x.frequency,
                                 x.offsetweek offset,
                                 r.plant_id routeplantid
                            from customerdeliveryday    c,
                                 routestop              rs,
                                 deliveryschemesperstop ds,
                                 deliveryscheme         x,
                                 route                  r
                           where ds.customer_id = customerid
                             and ds.customer_id = c.customer_id
                             and c.typeofmerchadise = typeofmerch
                             and ds.routestop_id = rs.routestop_id
                             and ---
                                 (rs.deliverypoint_id = vdeliverypointid or
                                 rs.deliverypoint_id is null)
                             and ---
                                 c.day_id = dayx
                             and rs.route_id = r.route_id
                             and ds.day_id = c.day_id
                             and ds.deliveryscheme_id = x.deliveryscheme_id
                             and trunc(RS.Dateactive) <= lastindate
                             and trunc(RS.Dateinactive) > lastindate) loop
            begin
              if isweekdeliveryweek(year,
                                    week,
                                    vcursor.frequency,
                                    vcursor.offset) then
                begin
                  routestopx := vcursor.routestop_id;
                  dayx       := 0;
                  if ((garmentplantid is null) or (garmentplantid = vcursor.routeplantid)) then
                     exit;
                  end if;
                end;
              end if;
            end;
          end loop;
          if routestopx is null then
            begin
              lastindate := lastindate - 1;
              dayx       := getabsdaynumber(lastindate);
              week       := getisoweek(lastindate);
              year       := getyearofweek(lastindate);
              if year < (startyear - 2) then
                dayx       := 0;
                lastindate := datex;
              end if;
            end;
          end if;
        end;
      end loop;
      select route_id
        into lastinroute
        from routestop
       where routestop_id = routestopx;
    end if;
  exception
    when others then
      null;
  end getlastinroute;
  procedure fillplannedoutroute(plantid_garment     in plant.plant_id%type,
                                currentdate         in date,
                                typeofmerch         in product.typeofmerchandise%type,
                                deliverymethod      in integer,
                                deedeliveryschemeid in deliveryscheme.deliveryscheme_id%type,
                                plpcid              in productlistpercustomer.productlistpercustomer_id%type,
                                customerid          in customer.customer_id%type,
                                deliverypointid     in deliverypoint.deliverypoint_id%type,
                                lastinroute         in route.route_id%type,
                                lastindate          in date,
                                routestopin         in routestop.routestop_id%type,
                                routestopid         out routestop.routestop_id%type,
                                routeid             out route.route_id%type,
                                plannedoutdate      out date,
                                scanbyroute         in varchar2) is
    dates             visitdates;
    returnrouteid     route.route_id%type;
    movedroutestopid  routestop.routestop_id%type;
    routedayp         integer;
    i                 integer;
    ii                integer;
    j                 integer;
    startdate         date;
    vdeliverypointid  deliverypoint.deliverypoint_id%type;
    deliverydays_us   varchar2(1);
    currentweek       integer;
    currentday        integer;
    nextdeliveryweek  integer;
    nextdeliveryyear  integer;
    dayid             integer;
    routestopactive   routestop.routestop_id%type;
    lv_deliverymethod integer;
  begin
    if deliverymethod = 8 then
      startdate := currentdate;
    else
      startdate := currentdate + 1; --todo4313
    end if;
    i                := 0;
    j                := 0;
    vdeliverypointid := deliverypointid;
    if typeofmerch = 2 then
      ii := 15;
    else
      ii := 30;
    end if;
    --todo24970 replace 0 with 1, use new variable to do this
    if deliverymethod in (1, 2, 3, 4, 5, 6, 7) then
      lv_deliverymethod := deliverymethod;
    else
      lv_deliverymethod := 1;
    end if;
    case lv_deliverymethod
      when 1 then
        --determine the first route when the customer is visited starting from today
        begin
          while j < 2 loop
            while i < ii loop
              plannedoutdate := pack_sort.getnextdeliverydate(startdate,
                                                              customerid,
                                                              typeofmerch);
              if plannedoutdate is null then
                plannedoutdate := lastindate + 7;
              end if;
              --todo3394
              if scanbyroute <> 'Y' then
                exit;
              end if;
              routestopid := pack_sort.getroutestopforcustomer(plantid_garment,
                                                               plannedoutdate,
                                                               customerid,
                                                               vdeliverypointid);
              if routestopid is null --and plannedoutdate is not null
               then
                i         := i + 1;
                startdate := plannedoutdate + 1;
              else
                i := ii;
              end if;
            end loop;
            if routestopid is null then
              vdeliverypointid := null;
              i                := 1;
              j                := j + 1;
            else
              j := 2;
            end if;
          end loop;
          select route_id
            into routeid
            from routestop s
           where s.routestop_id = routestopid;
        exception
          when no_data_found then
            begin
              routeid     := lastinroute;
              routestopid := routestopin;
            end;
        end;
      when 2 then
        begin
          --use the same route as the route of the item was brought in
          routeid        := lastinroute;
          plannedoutdate := lastindate + 7;
          routestopid    := routestopin;
          begin
            select s.routestop_id
              into routestopactive
              from routestop s
             where trunc(s.dateinactive) > trunc(plannedoutdate)
               and s.routestop_id = routestopid;
          exception
            when no_data_found then
              routestopactive := null;
          end;
          if (routestopactive is null) then
            begin
              select s.movedroutestop_id
                into movedroutestopid
                from routestop s
               where trunc(s.dateinactive) > trunc(plannedoutdate)
                 and s.routestop_id = routestopid;
            exception
              when no_data_found then
                movedroutestopid := null;
            end;
            if (movedroutestopid is null) then
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            1,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            routestopin,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            else
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            deliverymethod,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            movedroutestopid,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            end if;
          end if;
        end;
      when 3 then
        --same as 2
        begin
          dbms_output.put_line('plpc FOUND 3');
          routeid        := lastinroute;
          plannedoutdate := lastindate + 7;
          routestopid    := routestopin;
          begin
            select s.routestop_id
              into routestopactive
              from routestop s
             where trunc(s.dateinactive) > trunc(plannedoutdate)
               and s.routestop_id = routestopid;
          exception
            when no_data_found then
              routestopactive := null;
          end;
          if (routestopactive is null) then
            begin
              select s.movedroutestop_id
                into movedroutestopid
                from routestop s
               where trunc(s.dateinactive) > trunc(plannedoutdate)
                 and s.routestop_id = routestopid;
            exception
              when no_data_found then
                movedroutestopid := null;
            end;
            if (movedroutestopid is null) then
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            1,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            routestopin,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            else
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            deliverymethod,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            movedroutestopid,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            end if;
          end if;
        end;
      when 4 then
        begin
          begin
            select s.returnroute_id
              into returnrouteid
              from routestop s, route returnroute
             where returnroute.route_id = s.returnroute_id
               and returnroute.plant_id = plantid_garment
               and s.customer_id = customerid
               and s.route_id = lastinroute
               and s.routestop_id = routestopin;
          exception
            when no_data_found then
              returnrouteid := null;
          end;
          if routestopin is not null then

            if vdeliverypointid is not null then
              begin
                select min(routestop_id)
                  into routestopid
                  from routestop
                 where routestop.route_id = returnrouteid
                   and routestop.customer_id = customerid
                   and trunc(routestop.dateinactive) > trunc(startdate)
                   and routestop.deliverypoint_id = vdeliverypointid;
              exception
                when no_data_found then
                  routestopid := null;
              end;
            end if;
            if routestopid is null then
              select min(routestop_id)
                into routestopid
                from routestop
               where routestop.route_id = returnrouteid
                 and trunc(routestop.dateinactive) > trunc(startdate)
                 and routestop.customer_id = customerid
               order by stopnumber;
            end if;
          end if;
          if returnrouteid is null then
            begin
              routeid        := lastinroute;
              plannedoutdate := lastindate + 7;
              routestopid    := routestopin;
              begin
                select s.routestop_id
                  into routestopactive
                  from routestop s
                 where trunc(s.dateinactive) > trunc(plannedoutdate)
                   and s.routestop_id = routestopid;
              exception
                when no_data_found then
                  routestopactive := null;
              end;
              if (routestopactive is null) then
                begin
                  select s.movedroutestop_id
                    into movedroutestopid
                    from routestop s
                   where trunc(s.dateinactive) > trunc(plannedoutdate)
                     and s.routestop_id = routestopid;
                exception
                  when no_data_found then
                    movedroutestopid := null;
                end;
                if (movedroutestopid is null) then
                  pack_sort.fillplannedoutroute(plantid_garment,
                                                plannedoutdate,
                                                typeofmerch,
                                                1,
                                                deedeliveryschemeid,
                                                plpcid,
                                                customerid,
                                                deliverypointid,
                                                lastinroute,
                                                lastindate,
                                                routestopin,
                                                routestopid,
                                                routeid,
                                                plannedoutdate,
                                                scanbyroute);
                else
                  pack_sort.fillplannedoutroute(plantid_garment,
                                                plannedoutdate,
                                                typeofmerch,
                                                deliverymethod,
                                                deedeliveryschemeid,
                                                plpcid,
                                                customerid,
                                                deliverypointid,
                                                lastinroute,
                                                lastindate,
                                                movedroutestopid,
                                                routestopid,
                                                routeid,
                                                plannedoutdate,
                                                scanbyroute);
                end if;
              end if;
            end;
          else
            begin
              select r.drivingday_id
                into routedayp
                from route r
               where r.route_id = returnrouteid;
              i := 1;
              for vcursor in (select s.day_id,
                                     s.deliveryscheme_id,
                                     s.routestop_id
                                from deliveryschemesperstop s
                               where s.customer_id = customerid
                                 and s.day_id = routedayp
                                 and s.routestop_id = routestopid) loop
                begin
                  plannedoutdate := pack_sort.getvisitdate(vcursor.deliveryscheme_id,
                                                           routedayp,
                                                           startdate);
                  if plannedoutdate is not null then
                    begin
                      select s.routestop_id
                        into routestopactive
                        from routestop s
                       where trunc(s.dateinactive) > trunc(plannedoutdate)
                         and s.routestop_id = routestopid;
                    exception
                      when no_data_found then
                        routestopactive := null;
                    end;
                    if (routestopactive is not null) then
                      dates(to_char(plannedoutdate, 'YYYYMMDD')) := i;
                      i := i + 1;
                    end if;
                  end if;
                end;
              end loop;
              plannedoutdate := to_date(dates.first, 'YYYYMMDD');
              routeid        := returnrouteid;
            end;
          end if;
        end;
      when 5 then
        --same as 2 - but 14 days -order501096
        begin
          dbms_output.put_line('plpc FOUND 3');
          routeid        := lastinroute;
          plannedoutdate := lastindate + 14;
          routestopid    := routestopin;
          begin
            select s.routestop_id
              into routestopactive
              from routestop s
             where trunc(s.dateinactive) > trunc(plannedoutdate)
               and s.routestop_id = routestopid;
          exception
            when no_data_found then
              routestopactive := null;
          end;
          if (routestopactive is null) then
            begin
              select s.movedroutestop_id
                into movedroutestopid
                from routestop s
               where trunc(s.dateinactive) > trunc(plannedoutdate)
                 and s.routestop_id = routestopid;
            exception
              when no_data_found then
                movedroutestopid := null;
            end;
            if (movedroutestopid is null) then
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            1,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            routestopin,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            else
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            deliverymethod,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            movedroutestopid,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            end if;
          end if;
        end;
      when 6 then
        --same as 2 -but 28 days -order501096
        begin
          dbms_output.put_line('plpc FOUND 3');
          routeid        := lastinroute;
          plannedoutdate := lastindate + 28;
          routestopid    := routestopin;
          begin
            select s.routestop_id
              into routestopactive
              from routestop s
             where trunc(s.dateinactive) > trunc(plannedoutdate)
               and s.routestop_id = routestopid;
          exception
            when no_data_found then
              routestopactive := null;
          end;
          if (routestopactive is null) then
            begin
              select s.movedroutestop_id
                into movedroutestopid
                from routestop s
               where trunc(s.dateinactive) > trunc(plannedoutdate)
                 and s.routestop_id = routestopid;
            exception
              when no_data_found then
                movedroutestopid := null;
            end;
            if (movedroutestopid is null) then
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            1,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            routestopin,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            else
              pack_sort.fillplannedoutroute(plantid_garment,
                                            plannedoutdate,
                                            typeofmerch,
                                            deliverymethod,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            movedroutestopid,
                                            routestopid,
                                            routeid,
                                            plannedoutdate,
                                            scanbyroute);
            end if;
          end if;
        end;
      when 7 then
        --according with deliveryscheme - order501280
        begin
          begin
            select s.value
              into deliverydays_us
              from systemsetting s
             where s.plant_id = plantid_garment
               and s.name = 'DELIVERYDAYS_US';
          exception
            when no_data_found then
              deliverydays_us := 'N';
          end;
          currentweek := getisoweek(currentdate);
          currentday  := getabsdaynumber(currentdate);
          pack_sort.getnextdeliveryweek(deedeliveryschemeid,
                                        currentday,
                                        currentdate,
                                        nextdeliveryweek,
                                        nextdeliveryyear);
          if currentweek <> nextdeliveryweek then
            begin
              if deliverydays_us = 'Y' then
                --deliverydays US
                begin
                  select min(p.day_id)
                    into dayid
                    from productdeliveryday p
                   where p.productlistpercustomer_id = plpcid
                     and p.deliverytype in ('B', 'D');
                  plannedoutdate := getdateforweekyear(dayid,
                                                       nextdeliveryweek,
                                                       nextdeliveryyear);
                exception
                  when others then
                    plannedoutdate := null;
                end;
              else
                --deliverydays EU
                begin
                  select min(c.day_id)
                    into dayid
                    from customerdeliveryday c, customerdeliveryscheme d
                   where c.customer_id = customerid
                     and c.customer_id = d.customer_id
                     and c.day_id = d.day_id
                     and c.typeofmerchadise = typeofmerch
                     and d.deliveryscheme_id = deedeliveryschemeid
                     and d.active = 'Y';
                  plannedoutdate := getdateforweekyear(dayid,
                                                       nextdeliveryweek,
                                                       nextdeliveryyear);
                exception
                  when others then
                    plannedoutdate := null;
                end;
              end if;
            end;
          else
            if deliverydays_us = 'Y' then
              --deliverydays US
              begin
                select min(p.day_id)
                  into dayid
                  from productdeliveryday p
                 where p.productlistpercustomer_id = plpcid
                   and p.deliverytype in ('B', 'D')
                   and p.day_id > currentday;
                if dayid is not null then
                  plannedoutdate := getdateforweekyear(dayid,
                                                       nextdeliveryweek,
                                                       nextdeliveryyear);
                else
                  begin
                    pack_sort.getnextdeliveryweek(deedeliveryschemeid,
                                                  currentday,
                                                  currentdate + 7,
                                                  nextdeliveryweek,
                                                  nextdeliveryyear);
                    select min(p.day_id)
                      into dayid
                      from productdeliveryday p
                     where p.productlistpercustomer_id = plpcid
                       and p.deliverytype in ('B', 'D');
                    plannedoutdate := getdateforweekyear(dayid,
                                                         nextdeliveryweek,
                                                         nextdeliveryyear);
                  exception
                    when others then
                      plannedoutdate := null;
                  end;
                end if;
              end;
            else
              --deliverydays EU
              begin
                select min(c.day_id)
                  into dayid
                  from customerdeliveryday c, customerdeliveryscheme d
                 where c.customer_id = customerid
                   and c.customer_id = d.customer_id
                   and c.day_id = d.day_id
                   and c.typeofmerchadise = typeofmerch
                   and d.deliveryscheme_id = deedeliveryschemeid
                   and c.day_id > currentday
                   and d.active = 'Y';
                if dayid is not null then
                  plannedoutdate := getdateforweekyear(dayid,
                                                       nextdeliveryweek,
                                                       nextdeliveryyear);
                else
                  begin
                    pack_sort.getnextdeliveryweek(deedeliveryschemeid,
                                                  currentday,
                                                  currentdate + 7,
                                                  nextdeliveryweek,
                                                  nextdeliveryyear);
                    select min(c.day_id)
                      into dayid
                      from customerdeliveryday c, customerdeliveryscheme d
                     where c.customer_id = customerid
                       and c.customer_id = d.customer_id
                       and c.day_id = d.day_id
                       and c.typeofmerchadise = typeofmerch
                       and d.deliveryscheme_id = deedeliveryschemeid
                       and d.active = 'Y';
                    plannedoutdate := getdateforweekyear(dayid,
                                                         nextdeliveryweek,
                                                         nextdeliveryyear);
                  exception
                    when others then
                      plannedoutdate := null;
                  end;
                end if;
              end;
            end if;
          end if;
          if plannedoutdate is not null and scanbyroute = 'Y' then
            begin
              routestopid := pack_sort.getroutestopforcustomer(plantid_garment,
                                                               plannedoutdate,
                                                               customerid,
                                                               vdeliverypointid);
              if routestopid is null then
                vdeliverypointid := null;
                routestopid      := pack_sort.getroutestopforcustomer(plantid_garment,
                                                                      plannedoutdate,
                                                                      customerid,
                                                                      vdeliverypointid);
              end if;
              select route_id
                into routeid
                from routestop s
               where s.routestop_id = routestopid;
            exception
              when no_data_found then
                begin
                  routeid        := lastinroute;
                  plannedoutdate := lastindate + 7;
                  routestopid    := routestopin;

                  dayid := -1;
                  select r.drivingday_id
                    into dayid
                    from route r
                   where r.route_id = routeid;
                  if (dayid <> -1 and
                     dayid <> getabsdaynumber(plannedoutdate)) then
                    getnextdeliverydatewithstop(plannedoutdate,
                                                plantid_garment,
                                                customerid,
                                                typeofmerch,
                                                vdeliverypointid,
                                                plannedoutdate,
                                                routeid);
                  end if;
                exception
                  when no_data_found then
                    begin
                      routeid := null;
                    end;
                end;
            end;
          end if;
        end;
      else
        begin
          routeid        := lastinroute;
          plannedoutdate := lastindate + 7;
          routestopid    := routestopin;
        end;
    end case;
    i := verify_routeid(plantid_garment, routeid, ' (for customerid = ' || customerid || ')');
  end fillplannedoutroute;

  procedure getflags(uniqueitemid        in uniqueitem.uniqueitem_id%type,
                     plantid_param       in plant.plant_id%type,
                     wearerflagid        in flag.flag_id%type,
                     wearerflagstartdate in date,
                     empflagid           in flag.flag_id%type,
                     empflagstartdate    in date,
                     languageid          in languages.language_id%type,
                     flagsusage          in integer,
                     flagcode1           out nocopy sortaddressperflag.sortaddress%type,
                     flagcode2           out nocopy sortaddressperflag.sortaddress%type,
                     flagcode3           out nocopy sortaddressperflag.sortaddress%type,
                     flagcode4           out nocopy sortaddressperflag.sortaddress%type,
                     flagdescription1    out nocopy flag_desc.description%type,
                     flagdescription2    out nocopy flag_desc.description%type,
                     flagdescription3    out nocopy flag_desc.description%type,
                     flagdescription4    out nocopy flag_desc.description%type,
                     flagsinfo           out nocopy varchar2, --300
                     destinationstring   out nocopy varchar2, --3
                     fp_kann_yes_no      in varchar2 default 'N', --Default N, options Y,N
                     fp_flag_freetext1   out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext2   out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext3   out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext4   out nocopy uniqueitemflag.freetextitem%type) is
  begin
    getflags(uniqueitemid,
             plantid_param,
             wearerflagid,
             wearerflagstartdate,
             empflagid,
             empflagstartdate,
             languageid,
             flagsusage,
             flagcode1,
             flagcode2,
             flagcode3,
             flagcode4,
             flagdescription1,
             flagdescription2,
             flagdescription3,
             flagdescription4,
             flagsinfo,
             destinationstring,
             fp_kann_yes_no,
             fp_flag_freetext1,
             fp_flag_freetext2,
             fp_flag_freetext3,
             fp_flag_freetext4,
             fp_flag_freetext1,
             fp_flag_freetext2,
             fp_flag_freetext3,
             fp_flag_freetext4);

  end getflags;
  procedure getflags(uniqueitemid           in uniqueitem.uniqueitem_id%type,
                     plantid_param          in plant.plant_id%type,
                     wearerflagid           in flag.flag_id%type,
                     wearerflagstartdate    in date,
                     empflagid              in flag.flag_id%type,
                     empflagstartdate       in date,
                     languageid             in languages.language_id%type,
                     flagsusage             in integer,
                     flagcode1              out nocopy sortaddressperflag.sortaddress%type,
                     flagcode2              out nocopy sortaddressperflag.sortaddress%type,
                     flagcode3              out nocopy sortaddressperflag.sortaddress%type,
                     flagcode4              out nocopy sortaddressperflag.sortaddress%type,
                     flagdescription1       out nocopy flag_desc.description%type,
                     flagdescription2       out nocopy flag_desc.description%type,
                     flagdescription3       out nocopy flag_desc.description%type,
                     flagdescription4       out nocopy flag_desc.description%type,
                     flagsinfo              out nocopy varchar2, --300
                     destinationstring      out nocopy varchar2, --3
                     fp_kann_yes_no         in varchar2 default 'N', --Default N, options Y,N
                     fp_flag_freetext1      out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext2      out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext3      out nocopy uniqueitemflag.freetextitem%type,
                     fp_flag_freetext4      out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext1         out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext2         out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext3         out nocopy uniqueitemflag.freetextitem%type,
                     flag_freetext4         out nocopy uniqueitemflag.freetextitem%type,
                     ui_status_assigned     in varchar2 default 'N',
                     freetext2descriptionyn in varchar2 default 'Y',
                     metricon               in varchar2 default 'N') is
    cnt                 integer;
    checkpointscan      integer;
    inscan              integer;
    tempflags           flags;
    showalways          varchar2(1);
    confirm             varchar2(1);
    stringdate          varchar2(8);
    stringc             varchar2(21);
    flagid              flag.flag_id%type;
    flagid2             flag.flag_id%type;
    flagid3             flag.flag_id%type;
    flagid4             flag.flag_id%type;
    freetext            varchar2(80);
    flagstring          varchar2(10);
    xsortaddress        sortaddressperflag.sortaddress%type;
    sortadressperrc     sortaddressperreasoncode.sortaddress%type;
    sortadressperrcdesc reasoncode_desc.description%type;
    --flagsusage takes following values:
    --0 for determining Destinationstring,
    --4 for determining flagcode1...flagcode4,
    --100 for filling flagsinfo with all founded flags linked to a uniqueitem
  begin
    select dialog_id
      into inscan
      from dialogs
     where dialogs.code = 'InScan';
    select dialog_id
      into checkpointscan
      from dialogs
     where dialogs.code = 'CheckPointScan';
    cnt               := 0;
    destinationstring := '';
    flagsinfo         := '';
    for vcursor in (select b.startdate,
                           f.flag_id,
                           f.priority,
                           f.showalways,
                           f.code
                      from uniqueitemflag b, flag f
                     where b.uniqueitem_id = uniqueitemid
                       and b.flag_id = f.flag_id
                    union
                    select wearerflagstartdate startdate,
                           f.flag_id,
                           f.priority,
                           f.showalways,
                           f.code
                      from flag f
                     where f.flag_id = wearerflagid
                    union
                    select empflagstartdate startdate,
                           f.flag_id,
                           f.priority,
                           f.showalways,
                           f.code
                      from flag f
                     where f.flag_id = empflagid
                     minus
                     SELECT coalesce(uf.startdate, wearerflagstartdate, empflagstartdate),
                           f.flag_id,
                           f.priority,
                           f.showalways,
                           f.code
                       FROM PLANTFLAGOPTIONS, DIALOGS,
                            FLAG f left outer join uniqueitemflag uf  on (uf.flag_id = f.flag_id and uf.uniqueitem_id = uniqueitemid)

                        WHERE PLANTFLAGOPTIONS.FLAG_ID = f.FLAG_ID
                          AND PLANTFLAGOPTIONS.DIALOG_ID = (select d.dialog_id from dialogs d where d.code = 'CheckPointScan')
                          AND PLANTFLAGOPTIONS.PLANT_ID = plantid_param
                          AND PLANTFLAGOPTIONS.SHOW = 'N'
                          AND f.FLAGTYPE = 1
                          and ( f.flag_id = wearerflagid or uf.uniqueitem_id = uniqueitemid or f.flag_id = empflagid)
                          and metricon = 'Y'
                          order by 3, 1, 2 --ABS-64648
            ) loop
      begin
        --first we check the plantflagoptions, if exist, ok use em.
        select decode(max(po.confirm), 'Y', '0', 'N', '1', '2')
          into confirm
          from plantflagoptions po
         where po.flag_id = vcursor.flag_id
           and po.plant_id = plantid_param
           and po.dialog_id in (inscan, checkpointscan)
           and po.show = 'Y';
        if nvl(confirm, '2') = '2' then
          --when confirm = 2 then no_data_found plantflagoptions, so check normal flagoptions
          select decode(max(o.confirm), 'Y', '0', 'N', '1', '2')
            into confirm
            from flagoptions o
           where o.flag_id = vcursor.flag_id
             and o.dialog_id in (inscan, checkpointscan)
             and o.show = 'Y';
        end if;
        if (vcursor.startdate <= sysdate) and confirm <> '2' then
          begin
            if vcursor.showalways = 'Y' then
              showalways := '0';
            else
              showalways := '1';
            end if;
            stringdate := to_char(vcursor.startdate, 'YYYYMMDD');
            flagstring := to_char(vcursor.flag_id);
            if (metricon = 'Y') then
              stringc := showalways || vcursor.priority || stringdate ||
                         flagstring; --string concatenat  dbms_output.put_line('string'||Stringc);
            else
              stringc := showalways || confirm || vcursor.priority ||
                         stringdate || flagstring; --string concatenat  dbms_output.put_line('string'||Stringc);
            end if;
            if tempflags.exists(stringc) then
              -- if combination of showalways/confirm/date exists already in the array
              begin
                flagid := tempflags(stringc);
                if flagid <> vcursor.flag_id then
                  --if flagID is NOT already stored in the array for the same combination of showalways/confirm/date then store it
                  tempflags(stringc) := vcursor.flag_id;
                  cnt := cnt + 1;
                end if;
              end;
            else
              -- if combination of showalways/confirm/date doesn't exists already in the array then add it
              tempflags(stringc) := vcursor.flag_id;
              cnt := cnt + 1;
            end if;
          end;
          if flagsusage = 0 then
            begin
              xsortaddress := '';
              select s.sortaddress
                into xsortaddress
                from sortaddressperflag s
               where s.flag_id = vcursor.flag_id
                 and s.plant_id = plantid_param;
              if xsortaddress is not null then
                destinationstring := substr(xsortaddress, 2, 2);
                -- end if;
                cnt := to_number(destinationstring);
                if cnt >= 0 then
                  destinationstring := substr(xsortaddress, 1, 3);
                  flagsinfo         := '';
                  exit;
                end if;
              end if;
            exception
              when others then
                destinationstring := '';
                flagsinfo         := '';
            end;
          end if;
          if flagsusage in (4, 100) then
            begin
              select fd.description
                into flagdescription1
                from flag_desc fd
               where fd.flag_id = vcursor.flag_id
                 and fd.language_id = languageid;
              flagsinfo := flagsinfo || vcursor.code || ':' ||
                           flagdescription1 || chr(13) || chr(10);
            exception
              when no_data_found then
                flagsinfo := flagsinfo || vcursor.code || ':' || chr(13) ||
                             chr(10);
            end;
            flagdescription1 := '';
          end if;
        end if;
      end;
    end loop;
    --added for order20011877
    begin
      if ui_status_assigned = 'Y' then
        select sarc.sortaddress, rsdesc.description
          into sortadressperrc, sortadressperrcdesc
          from uniqueitemfixedinfo      uif,
               sortaddressperreasoncode sarc,
               reasoncode               rs
          left outer join reasoncode_desc rsdesc
            on (rsdesc.reasoncode_id = rs.reasoncode_id and
               rsdesc.language_id = languageid)
         where uif.reasoncode_id = rs.reasoncode_id
           and rs.reasoncode_id = sarc.reasoncode_id
           and uif.uniqueitem_id = uniqueitemid
           and sarc.plant_id = plantid_param;
      end if;
    exception
      when others then
        sortadressperrc     := null;
        sortadressperrcdesc := null;
    end;
    --added for order501044
    if flagsusage = 4 then
      stringc := tempflags.first;
      if tempflags.exists(stringc) then
        cnt := 0;
        while stringc is not null loop
          begin
            if tempflags.exists(stringc) then
              cnt := cnt + 1;
              case cnt
                when 1 then
                  flagid := tempflags(stringc);
                when 2 then
                  flagid2 := tempflags(stringc);
                when 3 then
                  flagid3 := tempflags(stringc);
                when 4 then
                  flagid4 := tempflags(stringc);
              end case;
            end if;
            if cnt = 4 then
              exit;
            end if;
            stringc := tempflags.next(stringc); -- get subscript of next element
          end;
        end loop;
      end if; -- if tempflags.exists(stringc)
      if flagid > 0 then
        begin
          select s.sortaddress
            into flagcode1
            from sortaddressperflag s
           where s.flag_id = flagid
             and s.plant_id = plantid_param;
          begin
            select d.description
              into flagdescription1
              from flag_desc d
             where d.flag_id = flagid
               and d.language_id = languageid;
          exception
            when no_data_found then
              null;
          end;
          begin
            select u.freetextitem
              into freetext
              from uniqueitemflag u
             where u.flag_id = flagid
               and u.uniqueitem_id = uniqueitemid;
            flag_freetext1 := freetext;
            if length(freetext) > 0 and freetext2descriptionyn = 'Y' then
              begin
                if fp_kann_yes_no = 'Y' then
                  fp_flag_freetext1 := freetext;
                else
                  freetext         := flagdescription1 || ' ' || freetext;
                  flagdescription1 := substr(freetext, 1, 40);
                end if;
              end;
            end if;
          exception
            when no_data_found then
              null;
          end;
        exception
          when no_data_found then
            null;
        end;
      end if;
      if flagid2 > 0 then
        begin
          select s.sortaddress
            into flagcode2
            from sortaddressperflag s
           where s.flag_id = flagid2
             and s.plant_id = plantid_param;
          begin
            select d.description
              into flagdescription2
              from flag_desc d
             where d.flag_id = flagid2
               and d.language_id = languageid;
          exception
            when no_data_found then
              null;
          end;
          begin
            select u.freetextitem
              into freetext
              from uniqueitemflag u
             where u.flag_id = flagid2
               and u.uniqueitem_id = uniqueitemid;
            flag_freetext2 := freetext;
            if length(freetext) > 0 and freetext2descriptionyn = 'Y' then
              begin
                if fp_kann_yes_no = 'Y' then
                  fp_flag_freetext2 := freetext;
                else
                  freetext         := flagdescription2 || ' ' || freetext;
                  flagdescription2 := substr(freetext, 1, 40);
                end if;
              end;
            end if;
          exception
            when no_data_found then
              null;
          end;
        exception
          when no_data_found then
            null;
        end;
      end if; --end if flag2
      if flagid3 > 0 then
        begin
          select s.sortaddress
            into flagcode3
            from sortaddressperflag s
           where s.flag_id = flagid3
             and s.plant_id = plantid_param;
          begin
            select d.description
              into flagdescription3
              from flag_desc d
             where d.flag_id = flagid3
               and d.language_id = languageid;
          exception
            when no_data_found then
              null;
          end;
          begin
            select u.freetextitem
              into freetext
              from uniqueitemflag u
             where u.flag_id = flagid3
               and u.uniqueitem_id = uniqueitemid;
            flag_freetext3 := freetext;
            if length(freetext) > 0 and freetext2descriptionyn = 'Y' then
              begin
                if fp_kann_yes_no = 'Y' then
                  fp_flag_freetext3 := freetext;
                else
                  freetext         := flagdescription3 || ' ' || freetext;
                  flagdescription3 := substr(freetext, 1, 40);
                end if;
              end;
            end if;
          exception
            when no_data_found then
              null;
          end;
        exception
          when no_data_found then
            null;
        end;
      end if;
      if flagid4 > 0 then
        begin
          select s.sortaddress
            into flagcode4
            from sortaddressperflag s
           where s.flag_id = flagid4
             and s.plant_id = plantid_param;
          begin
            select d.description
              into flagdescription4
              from flag_desc d
             where d.flag_id = flagid4
               and d.language_id = languageid;
          exception
            when no_data_found then
              null;
          end;
          begin
            select u.freetextitem
              into freetext
              from uniqueitemflag u
             where u.flag_id = flagid4
               and u.uniqueitem_id = uniqueitemid;
            flag_freetext4 := freetext;
            if length(freetext) > 0 and freetext2descriptionyn = 'Y' then
              begin
                if fp_kann_yes_no = 'Y' then
                  fp_flag_freetext4 := freetext;
                else
                  freetext         := flagdescription4 || ' ' || freetext;
                  flagdescription4 := substr(freetext, 1, 40);
                end if;
              end;
            end if;
          exception
            when no_data_found then
              null;
          end;
          flagsinfo         := '';
          destinationstring := '';
        exception
          when no_data_found then
            null;
        end;
      end if;
      if (ui_status_assigned = 'Y' and sortadressperrc is not null) then
        flagdescription4 := flagdescription3;
        flagdescription3 := flagdescription2;
        flagdescription2 := flagdescription1;
        flagdescription1 := sortadressperrcdesc;
        flagcode4        := flagcode3;
        flagcode3        := flagcode2;
        flagcode2        := flagcode1;
        flagcode1        := sortadressperrc;
      end if;
    end if; --end for flagsusage 4
  exception
    when no_data_found then
      null;
  end getflags;
  procedure determinegarmentid(sortingsystem     in varchar2,
                               idcode            in uniqueitem.primaryid%type,
                               plantcode         in plant.code%type,
                               uniqueitemid      out nocopy uniqueitem.uniqueitem_id%type,
                               pool              out nocopy uniqueitem.poolitem%type,
                               unitcode          out nocopy businessunit.code%type,
                               businessunitid    out nocopy businessunit.businessunit_id%type,
                               plantid_garment   out nocopy plant.plant_id%type,
                               returnedplantcode out nocopy plant.code%type,
                               status            out nocopy integer,
                               idprimary         out uniqueitem.primaryid%type,
                               plantid_param     out nocopy plant.plant_id%type,
                               secondaryid       out secondaryuniqueitem.secondaryid%type) is
    lv_relatedcustid uniqueitem.relatedcustomer_id%type;
    lv_productid     product.product_id%type;
    lv_sizeid        sizedefinition.sizedefinition_id%type;
    batchnumber      uniqueitem.batchnumber%type;
    prevstayid       uniqueitem.prevstay_id%type;
    lastinscandate   uniqueitem.lastinscandate%type;
  begin
    determinegarmentid2(sortingsystem,
                        idcode,
                        plantcode,
                        uniqueitemid,
                        pool,
                        unitcode,
                        businessunitid,
                        plantid_garment,
                        returnedplantcode,
                        status,
                        idprimary,
                        plantid_param,
                        secondaryid,
                        lv_relatedcustid,
                        lv_productid,
                        lv_sizeid,
                        batchnumber,
                        prevstayid,
                        lastinscandate);
  end determinegarmentid;
  procedure determinegarmentid2(sortingsystem     in varchar2,
                                idcode            in uniqueitem.primaryid%type,
                                plantcode         in plant.code%type,
                                uniqueitemid      out nocopy uniqueitem.uniqueitem_id%type,
                                pool              out nocopy uniqueitem.poolitem%type,
                                unitcode          out nocopy businessunit.code%type,
                                businessunitid    out nocopy businessunit.businessunit_id%type,
                                plantid_garment   out nocopy plant.plant_id%type,
                                returnedplantcode out nocopy plant.code%type,
                                status            out nocopy integer,
                                idprimary         out uniqueitem.primaryid%type,
                                plantid_param     out nocopy plant.plant_id%type,
                                secondaryid       out secondaryuniqueitem.secondaryid%type,
                                relatedcustomerid out nocopy uniqueitem.relatedcustomer_id%type,
                                productid         out nocopy product.product_id%type,
                                sizeid            out nocopy sizedefinition.sizedefinition_id%type,
                                batchnumber       out nocopy uniqueitem.batchnumber%type,
                                prevstayid        out nocopy uniqueitem.prevstay_id%type,
                                plastinscandate   out nocopy uniqueitem.lastinscandate%type) is
    overalluniquegarmentid databasesettings.overalluniquegarmentid%type;
    codesequencenumber     uniqueitem.idcodesequencenumber%type;
    maxsequencenumber      integer;
    /*Same as determinegarmentid but with extra parameters*/

    procedure get_notoveralunique_primaryid(fp_primaryid in varchar2) is
    begin
      --get_notoveralunique_primaryid, overalluniquegarmentid = 'N'
      select u.uniqueitem_id,
             u.poolitem,
             u.businessunit_id,
             u.idcodesequencenumber,
             u.primaryid,
             u.relatedcustomer_id,
             u.product_id,
             u.sizedefinition_id,
             u.batchnumber,
             u.prevstay_id,
             u.lastinscandate
        into uniqueitemid,
             pool,
             businessunitid,
             codesequencenumber,
             idprimary,
             relatedcustomerid,
             productid,
             sizeid,
             batchnumber,
             prevstayid,
             plastinscandate
        from uniqueitem u
       where u.primaryid = fp_primaryid
         and u.idcodesequencenumber <= maxsequencenumber
         and exists (select 1
                from businessunit b
               where b.businessunit_id = u.businessunit_id
                 and b.plant_id = plantid_param);
    exception
      when no_data_found then
        begin
          select s.uniqueitem_id,
                 u.idcodesequencenumber,
                 u.poolitem,
                 u.businessunit_id,
                 u.primaryid,
                 u.relatedcustomer_id,
                 u.product_id,
                 u.sizedefinition_id,
                 u.batchnumber,
                 u.prevstay_id,
                 u.lastinscandate
            into uniqueitemid,
                 codesequencenumber,
                 pool,
                 businessunitid,
                 idprimary,
                 relatedcustomerid,
                 productid,
                 sizeid,
                 batchnumber,
                 prevstayid,
                 plastinscandate
            from secondaryuniqueitem s, uniqueitem u
           where s.secondaryid = fp_primaryid
             and u.idcodesequencenumber <= maxsequencenumber
             and s.uniqueitem_id = u.uniqueitem_id
             and exists (select 1
                    from businessunit b
                   where b.businessunit_id = u.businessunit_id
                     and b.plant_id = plantid_param);
        end;
    end get_notoveralunique_primaryid;

    procedure get_overalunique_primaryid(fp_primaryid in varchar2) is
    begin
      --get_overalunique_primaryid, overalluniquegarmentid = 'Y'
      select u.uniqueitem_id,
             u.poolitem,
             u.businessunit_id,
             u.idcodesequencenumber,
             u.primaryid,
             u.relatedcustomer_id,
             u.product_id,
             u.sizedefinition_id,
             u.batchnumber,
             u.prevstay_id,
             u.lastinscandate
        into uniqueitemid,
             pool,
             businessunitid,
             codesequencenumber,
             idprimary,
             relatedcustomerid,
             productid,
             sizeid,
             batchnumber,
             prevstayid,
             plastinscandate
        from uniqueitem u
       where u.primaryid = fp_primaryid
         and u.idcodesequencenumber <= maxsequencenumber;
    exception
      when no_data_found then
        begin
          select u.uniqueitem_id,
                 u.idcodesequencenumber,
                 u.poolitem,
                 u.businessunit_id,
                 u.primaryid,
                 u.relatedcustomer_id,
                 u.product_id,
                 u.sizedefinition_id,
                 u.batchnumber,
                 u.lastinscandate
            into uniqueitemid,
                 codesequencenumber,
                 pool,
                 businessunitid,
                 idprimary,
                 relatedcustomerid,
                 productid,
                 sizeid,
                 batchnumber,
                 plastinscandate
            from secondaryuniqueitem s, uniqueitem u
           where s.secondaryid = fp_primaryid
             and u.idcodesequencenumber <= maxsequencenumber
             and s.uniqueitem_id = u.uniqueitem_id;
        end;
    end get_overalunique_primaryid;

    function checktagfilter return varchar2 is
      newprimaryid varchar2(24);
    begin
      --if length=24, so UHF code, then check via uhftagfilter if newprimaryid maybe exists?
      if length(idcode) = 24 then
        begin
          select uhf.replacewith ||
                 substr(idcode, length(uhf.replaceprefix) + 1)
            into newprimaryid
            from uhftagfilter uhf
           where uhf.replaceprefix =
                 substr(idcode, 1, length(uhf.replaceprefix))
             and length(uhf.replaceprefix) between 4 and 16; --must have some length!
          return newprimaryid;
        end;
      else
        begin
          raise no_data_found;
        end;
      end if;
    end checktagfilter;
  begin
    maxsequencenumber := 99;
    if sortingsystem = 'KANNEGIESSER' then
      maxsequencenumber := 1;
    end if;
    status := 0;
    select overalluniquegarmentid
      into overalluniquegarmentid
      from databasesettings;
    if overalluniquegarmentid is null then
      overalluniquegarmentid := 'N';
    end if;
    begin
      --status
      if plantcode is not null then
        select p.plant_id
          into plantid_param
          from plant p
         where p.code = plantcode;
      else
        plantid_param := null;
      end if;
      if plantcode is not null and overalluniquegarmentid = 'N' then
        begin
          get_notoveralunique_primaryid(idcode);
        exception
          when no_data_found then
            begin
              get_notoveralunique_primaryid(checktagfilter);
            end;
        end;
      else
        begin
          --plantcode is null or overalluniqueID is Y
          get_overalunique_primaryid(idcode);
        exception
          when no_data_found then
            begin
              get_overalunique_primaryid(checktagfilter);
            end;
        end;
      end if;
    exception
      when no_data_found then
        begin
          pack_sort.write_logging('!> ' || 'Idcode ' ||
                                  nvl(idcode, 'NULL') || ' for plant ' ||
                                  nvl(plantcode, 'NULL') || case when
                                  plantid_param is null then
                                  '; (NULL)=No plant info, not found' else
                                  ' not found' end,
                                  1,
                                  'PACK_SORT.DETERMINEGARMENTID',
                                  plantid_garment,
                                  3,
                                  1);
          status := 1;
        end;
      when too_many_rows then
        begin
          pack_sort.write_logging('!> ' || 'Idcode ' ||
                                  nvl(idcode, 'NULL') || ' for plant ' ||
                                  nvl(plantcode, 'NULL') || case when
                                  plantid_param is null then
                                  ' (NULL)=No plant info, too many matching ID codes found' else
                                  ' too many matching ID codes found' end,
                                  1,
                                  'PACK_SORT.DETERMINEGARMENTID',
                                  plantid_garment,
                                  3,
                                  1);
          status := 1;
        end;
      when others then
        begin
          if sortingsystem = 'KANNEGIESSER' then
            status := 1;
          else
            status := 2;
          end if;
          pack_sort.write_logging('!> ' || 'Idcode ' ||
                                  nvl(idcode, 'NULL') || ' for plant ' ||
                                  nvl(plantcode, 'NULL') || case when
                                  plantid_param is null then
                                  ' (NULL)=No plant info, error ' else
                                  ' error ' end || sqlerrm,
                                  1,
                                  'PACK_SORT.DETERMINEGARMENTID',
                                  plantid_garment,
                                  3,
                                  1);
        end;
    end;
    if status = 0 then
      begin
        --BU
        select b.code, b.plant_id
          into unitcode, plantid_garment
          from businessunit b
         where b.businessunit_id = businessunitid;
      exception
        when no_data_found then
          status := 1;
        when others then
          if sortingsystem = 'KANNEGIESSER' then
            status := 1;
          else
            status := 2;
          end if;
      end;
    end if;
    if status = 0 and
       (sortingsystem = 'KANNEGIESSER' or sortingsystem = 'AMT') then
      select p.code
        into returnedplantcode
        from plant p
       where p.plant_id = plantid_garment;
    end if;
    --todo3437
    if status > 0 and plantcode is not null then
      begin
        select plant_id
          into plantid_param
          from plant
         where plant.code = plantcode;
      exception
        when no_data_found then
          select min(plant_id) into plantid_param from plant;
      end;
    elsif status > 0 and plantcode is null then
      select min(plant_id) into plantid_param from plant;
    end if;
    if plantid_garment is null then
      plantid_garment := plantid_param;
    end if;
    if plantid_param is null then
      plantid_param := plantid_garment;
    end if;
    --secondaryID
    begin
      select s.secondaryid
        into secondaryid
        from secondaryuniqueitem s
       where s.uniqueitem_id = uniqueitemid;
    exception
      when no_data_found then
        null;
    end;
  end determinegarmentid2;
  procedure getsystemsettings(plantid_param   in plant.plant_id%type,
                              debuglevel      out nocopy integer,
                              utldir          out nocopy varchar2,
                              allowrepairscan out nocopy integer,
                              getgarment      in number default 0) is
    lv_logdate date;

    procedure update_systemsetting is
      pragma autonomous_transaction;
    begin
      if getgarment = 0 then
        --turn of detailed logging
        update systemsetting ss
           set ss.value = '0'
         where ss.plant_id = plantid_param
           and ss.name = 'SORTLOGGETGARMENTDATA';
      else
        --turn of detailed logging
        update systemsetting ss
           set ss.value = '0'
         where ss.plant_id = plantid_param
           and ss.name = 'SORTLOGSENDTRACKINFO';
      end if;
      commit;
    end update_systemsetting;
  begin
    begin
      if getgarment = 0 then
        select s.value, trunc(s.timestamp) logdate
          into debuglevel, lv_logdate
          from systemsetting s
         where s.name = 'SORTLOGGETGARMENTDATA'
           and s.plant_id = plantid_param;
      else
        select s.value, trunc(s.timestamp) logdate
          into debuglevel, lv_logdate
          from systemsetting s
         where s.name = 'SORTLOGSENDTRACKINFO'
           and s.plant_id = plantid_param;
      end if;
      if debuglevel <> '0' and lv_logdate < trunc(sysdate) then
        update_systemsetting;
        debuglevel := '0';
      end if;
    exception
      when no_data_found then
        debuglevel := 0;
    end;
    begin
      select s.value
        into utldir
        from systemsetting s
       where s.name = 'DATABASELOGDIR'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        utldir := 'C:\';-- please see ABS-92804 variable needs the name of an existing oracle directory
    end;
    if getgarment = 0 then
      begin
        select s.value
          into allowrepairscan
          from systemsetting s
         where s.name = 'ALLOWREPAIRSCAN'
           and s.plant_id = plantid_param;
      exception
        when no_data_found then
          allowrepairscan := 1;
      end;
    end if;
  end getsystemsettings;
  procedure getgarmentlocation(lockerid             in locker.locker_id%type,
                               garmentdispenserid   in garmentdispenser.garmentdispenser_id%type,
                               deliverypointid      in out deliverypoint.deliverypoint_id%type,
                               banklocker           out nocopy varchar2,
                               garmentdispensercode out nocopy garmentdispenser.code%type,
                               deliverypointcode    out nocopy deliverypoint.code%type) is
    vbank             varchar2(6);
    vlocker           varchar2(6);
    auxnumeric_bank   integer;
    auxnumeric_locker integer;
    databasecode      databasesettings.code%type;
  begin
    select d.code into databasecode from databasesettings d;
    --banklocker
    if lockerid is not null then
      begin
        select l.bank, isnumeric(l.bank), l.locker, isnumeric(l.locker)
          into vbank, auxnumeric_bank, vlocker, auxnumeric_locker
          from locker l
         where l.locker_id = lockerid;
        if auxnumeric_bank = 1 then
          --isnumeric returns 1 for numeric and 0 for alfanumeric
          if (databasecode = 'HPL' or databasecode = 'SGS') then
            vbank := rpad(vbank, 6, ' ');
          else
            vbank := lpad(vbank, 6, ' ');
          end if;
        else
          --alfanumeric
          vbank := rpad(vbank, 6, ' ');
        end if;
        if auxnumeric_locker = 1 then
          if (databasecode = 'HPL' or databasecode = 'SGS') then
            vlocker := rpad(vlocker, 6, ' ');
          else
            vlocker := lpad(vlocker, 6, ' ');
          end if;
        else
          vlocker := rpad(vlocker, 6, ' ');
        end if;
      exception
        when others then
          null;

      end;
      if vbank is null then
        banklocker := '      ' || vlocker;
      else
        banklocker := vbank || vlocker;
      end if;
    else
      banklocker := '            ';
    end if;
    --garmentdispenser
    if garmentdispenserid is not null then
      select g.code
        into garmentdispensercode
        from garmentdispenser g
       where g.garmentdispenser_id = garmentdispenserid;
      garmentdispensercode := rpad(garmentdispensercode, 6, ' ');
    else
      garmentdispensercode := '      ';
    end if;
    begin
      --deliverypoint
      if deliverypointid is not null then
        select d.code
          into deliverypointcode
          from deliverypoint d
         where d.deliverypoint_id = deliverypointid;
        -- exception when no_data_found then null;
      elsif lockerid is not null then
        select d.code, d.deliverypoint_id
          into deliverypointcode, deliverypointid
          from locker l, deliverypoint d
         where l.deliverypoint_id = d.deliverypoint_id
           and l.locker_id = lockerid;
      elsif garmentdispenserid is not null then
        select d.code, d.deliverypoint_id
          into deliverypointcode, deliverypointid
          from garmentdispenser g, deliverypoint d
         where g.deliverypoint_id = d.deliverypoint_id
           and g.garmentdispenser_id = garmentdispenserid;
      end if;
    exception
      when no_data_found then
        null;
    end;
    if deliverypointcode is not null then
      deliverypointcode := rpad(deliverypointcode, 12, ' ');
    else
      deliverypointcode := '           ';
    end if;
  end getgarmentlocation;
procedure getgarmentdatainfo(sortingsystem           in varchar2,
                               plantid_garment         in plant.plant_id%type,
                               uniqueitemid            in uniqueitem.uniqueitem_id%type,
                               languageid              in out languages.language_id%type,
                               finishingcodeid         out nocopy finishingcode.finishingcode_id%type,
                               serviceteamid           out nocopy serviceteam.serviceteam_id%type,
                               vchargerepairs          out nocopy customer.chargerepairs%type,
                               vcustomerowned          out nocopy uniqueitem.customerowned%type,
                               colorid                 out nocopy color.color_id%type,
                               wearerflagid            out nocopy flag.flag_id%type,
                               wearerflagstartdate     out nocopy date,
                               empflagid               out nocopy flag.flag_id%type,
                               empflagstartdate        out nocopy date,
                               finishingmethodid       out nocopy finishingmethod.finishingmethod_id%type,
                               productid               out nocopy product.product_id%type,
                               productcode             out nocopy product.code%type,
                               productdescription      out nocopy product_desc.description%type,
                               sizecode                out nocopy sizedefinition.code%type,
                               customernumber          out nocopy customer.customernumber%type,
                               customerid              out nocopy customer.customer_id%type,
                               customername            out nocopy customer.name%type,
                               wearernumber            out nocopy wearer.wearernumber%type,
                               wearername              out nocopy wearer.searchname%type,
                               banklocker              out nocopy varchar2,
                               departmentnumber        out nocopy department.departmentnumber%type,
                               customeremployeenumber  out nocopy wearer.customeremployeenumber%type,
                               gender                  out nocopy wearer.sex%type,
                               garmentdispensercode    out nocopy garmentdispenser.code%type,
                               deliverypointcode       out nocopy deliverypoint.code%type,
                               infotext                out nocopy wearer.remark%type,
                               routenumber             out nocopy route.routenumber%type,
                               routeday                out nocopy day.daynumber%type,
                               stopnumber              out nocopy routestop.stopnumber%type,
                               packingsequence         out nocopy product.packingsequence%type,
                               stayid                  out nocopy stay.stay_id%type,
                               routeid                 out nocopy route.route_id%type,
                               imageid                 out nocopy product.image_id%type,
                               routestopid             out nocopy routestop.routestop_id%type,
                               planneddate             out nocopy date,
                               statusout               out nocopy integer,
                               valternatesortingstring out nocopy customer.alternatesorting%type,
                               debuglevel              in integer,
                               findpackingnote         in out varchar2,
                               pnnotenumber            out packingnote.notenumber%type,
                               --Order 502022
                               routedate in out date,
                               --Order#502901
                               fp_washestotal      out nocopy uniqueitem.washestotal%type,
                               fp_routecodeonlabel out nocopy route.codeonlabel%type,
                               fp_plant_idparam    in plant.plant_id%type default null,
                               fp_sortcustomerid   out nocopy customer.sortcustomer_id%type,
                               fp_languagecode     in languages.code%type default null) is
    sizedefinitionid            sizedefinition.sizedefinition_id%type;
    plpcid                      productlistpercustomer.productlistpercustomer_id%type;
    deliverymethod              productlistpercustomer.delayedevenexchange%type;
    lastinroute                 route.route_id%type;
    staynumber                  stay.staynr%type;
    pool                        uniqueitem.poolitem%type;
    typeofmerch                 product.typeofmerchandise%type;
    weareremploymentid          weareremployment.weareremployment_id%type;
    lockerid                    locker.locker_id%type;
    externallockerid            locker.locker_id%type;
    garmentdispenserid          garmentdispenser.garmentdispenser_id%type;
    deliverypointid             deliverypoint.deliverypoint_id%type;
    savedeliverypointid         deliverypoint.deliverypoint_id%type;
    routestopin                 routestop.routestop_id%type;
    lastindate                  date;
    scanbyroute                 varchar2(1);
    allowcustlockersharing      varchar2(1);
    checkinternalsortingplant   varchar2(1);
    internalplantid             plant.plant_id%type;
    countdeliveryscheme         integer;
    countroutes                 integer;
    deedeliveryschemeid         deliveryscheme.deliveryscheme_id%type;
    vmaxwashes                  integer;
    sortbatchstop               integer;
    sortbatchroute              integer;
    stopbatch                   integer;
    routebatch                  integer;
    wearerinventoryid           wearerinventory.wearerinventory_id%type;
    vqtytobereturneddecreasemax integer;
    flagid                      flag.flag_id%type;
    systemuserid                systemuser.systemuser_id%type;
    idcode                      uniqueitem.primaryid%type;
    plpcfinishingcode           productlistpercustomer.finishingcode_id%type;
    diremarkondeliverynote      distributionpoint.remarkondeliverynote%type;
    productgroupid              productgroup.productgroup_id%type;
    plantdepartmentid           plantdepartment.plantdepartment_id%type;
    statusnew                   status.status_id%type;
    businessunitid              businessunit.businessunit_id%type;
    packingnoteid               packingnote.packingnote_id%type;
    routecontrolid              routecontrol.routecontrol_id%type;
    distributionpointid         distributionpoint.distributionpoint_id%type;
    defaulttranspart            transportarticle.transportarticle_id%type;
    rcpackingdeadline           routecontrol.packingdeadline%type;
    rcsortingstatus             routecontrol.sortingstatus%type;
    minpackingnotelineid        packingnoteline.packingnoteline_id%type;
    bucode                      businessunit.code%type;
    stopid                      stop.stop_id%type;
    rdeadline                   packingnote.deadline%type;
    plpcustomcode               productlistpercustomer.customcode%type;
    plpcustomdescription        productlistpercustomer.customdescription%type;
    pchargewashesonlyforcog     varchar2(1);
    pbillingmethod              integer;
    char_notenumber             varchar2(8);
    plantdepartment_notfound    integer;
    packingdatetime             date;
    drivingdate                 date;
    packingday                  number;
    createnewpackingnote        varchar2(1);
    createnewpackingnoteline    varchar2(1);
    routeinprogress             varchar2(1);
    lv_treatmentcheckschemeid   treatmentcheckscheme.treatmentcheckscheme_id%type;
    -- Order 20014102
    deliverydetermination integer;
    inroutecontrol_id     number;
    instop_id             number;
    outroutecontrol_id    number;
    deparment_id          number := null;
    lv_log                varchar2(1) := 'N';
begin
    statusout := 0;
    --systemuser
    begin
      select s.systemuser_id
        into systemuserid
        from systemuser s
       where s.username = 'SORT';
    exception
      when no_data_found then
        select min(systemuser_id) into systemuserid from systemuser;
    end;
    begin
      --scan by route
      select s.value
      into   scanbyroute
      from   systemsetting s
      where  s.plant_id = plantid_garment
      and    s.name = 'SCANBYROUTE';
    exception
      when others then
        null;
    end;
    begin
      --scan by route
      select s.value
      into   allowcustlockersharing
      from   systemsetting s
      where  s.plant_id = plantid_garment
      and    s.name = 'ALLOWCUSTLOCKERSHARING';
    exception
      when others then
        null;
    end;
    -- Order 20014102
    begin
      select s.value
      into   deliverydetermination
      from   systemsetting s
      where  s.plant_id = plantid_garment
      and    s.name = 'DELIVERYDETERMINATION';
    exception
      when others then
        null;
    end;
    if fp_languagecode is not null then
      begin
        select max(l.language_id)
          into languageid
          from languages l
         where l.code = fp_languagecode;
      end;
    end if;
    if languageid is null then
      --language
      select languages.language_id
        into languageid
        from languages, plant
       where languages.language_id = plant.language_id
         and plant.plant_id = plantid_garment;
    end if;
    --unique item
    select u.primaryid,
           u.stay_id,
           u.finishingmethod_id,
           u.sizedefinition_id,
           p.product_id,
           p.code,
           p.packingsequence,
           cfsgetdesc_product(p.product_id, languageid),
           s.code,
           p.finishingcode_id,
           p.color_id,
           p.typeofmerchandise,
           u.customerowned,
           u.poolitem,
           p.image_id,
           p.productgroup_id,
           u.businessunit_id,
           u.washestotal
      into idcode,
           stayid,
           finishingmethodid,
           sizedefinitionid,
           productid,
           productcode,
           packingsequence,
           productdescription,
           sizecode,
           finishingcodeid,
           colorid,
           typeofmerch,
           vcustomerowned,
           pool,
           imageid,
           productgroupid,
           businessunitid,
           fp_washestotal
      from uniqueitem u, product p, sizedefinition s
     where u.uniqueitem_id = uniqueitemid
       and u.product_id = p.product_id
       and u.sizedefinition_id = s.sizedefinition_id;
    begin
      select stay.staynr
        into staynumber
        from stay
       where stay.stay_id = stayid;
    exception
      when others then
        null;
    end;
    if pool = 2 then
      begin
        --nonpool items
        begin
          select c.customernumber,
                 c.name,
                 c.customer_id,
                 c.serviceteam_id,
                 d.departmentnumber,
                 w.wearernumber,
                 w.searchname,
                 w.sex,
                 e.weareremployment_id,
                 w.customeremployeenumber,
                 w.remark,
                 w.flag_id,
                 w.flagstartdate,
                 e.flag_id,
                 e.flagstartdate,
                 e.locker_id,
                 e.garmentdispenser_id,
                 e.deliverypoint_id,
                 c.chargerepairs,
                 c.alternatesorting,
                 di.remarkondeliverynote,
                 di.distributionpoint_id,
                 c.sortcustomer_id,
                 e.externallocker_id
            into customernumber,
                 customername,
                 customerid,
                 serviceteamid,
                 departmentnumber,
                 wearernumber,
                 wearername,
                 gender,
                 weareremploymentid,
                 customeremployeenumber,
                 infotext,
                 wearerflagid,
                 wearerflagstartdate,
                 empflagid,
                 empflagstartdate,
                 lockerid,
                 garmentdispenserid,
                 deliverypointid,
                 vchargerepairs,
                 valternatesortingstring,
                 diremarkondeliverynote,
                 distributionpointid,
                 fp_sortcustomerid,
                 externallockerid
            from uniqueitemnonpool n,
                 customer          c,
                 department        d,
                 wearer            w,
                 weareremployment  e,
                 distributionpoint di
           where n.uniqueitem_id = uniqueitemid
          and    n.weareremployment_id = e.weareremployment_id
          and    e.wearer_id = w.wearer_id
          and    w.customer_id = c.customer_id
          and    e.distributionpoint_id = di.distributionpoint_id
          and    di.department_id = d.department_id;
        exception
          when no_data_found then
            null;
        end;
        --order 501516
        begin
          select a.wearerinventory_id, a.qtytobereturneddecreasemax
          into   wearerinventoryid, vqtytobereturneddecreasemax
          from   wearerinventory a
          where  a.weareremployment_id = weareremploymentid
          and    a.product_id = productid
          and    a.sizedefinition_id = sizedefinitionid
          and    a.finishingmethod_id = finishingmethodid;
        exception
          when no_data_found then
            wearerinventoryid := null;
        end;
        if wearerinventoryid is not null then
          if vqtytobereturneddecreasemax > 0 then
            begin
              select flag_id
              into   flagid
              from   automaticflag a
              where  --a.event ='Return to stock because of decrease max inventory';
               a.automaticflag_id = 7;
              if pack_sort.create_uniqueitemflag('PACK_SORT.GETGARMENTDATAINFO',
                                                 debuglevel,
                                                 systemuserid,
                                                 uniqueitemid,
                                                 flagid,
                                                 sysdate,
                                                 null,
                                                 null,
                                                 null,
                                                 plantid_garment) then
                update wearerinventory w
                   set w.qtytobereturneddecreasemax = qtytobereturneddecreasemax - 1
                 where w.wearerinventory_id = wearerinventoryid;
                --add debug information when needed
                if debuglevel > 0 then
                  pack_sort.write_logging('update wearerinventory ' ||
                                          nvl(to_char(wearerinventoryid),
                                              'NULL'),
                                          debuglevel,
                                          'PACK_SORT.GETGARMENTDATAINFO',
                                          plantid_garment,
                                          1,
                                          1);
                end if;
                commit;
              end if;
            exception
              when others then
                rollback;
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PACK_SORT.GETGARMENTDATAINFO',
                                        plantid_garment,
                                        3,
                                        1);
            end;
          end if; -- end if qtytobereturneddecrease
        end if; -- end if wearerinventory is not null
        --end order501516
        if customerid is not null then
          select count(*)
            into countdeliveryscheme
            from customerdeliveryscheme c
           where c.customer_id = customerid;
          if countdeliveryscheme = 0 then
            statusout := 1;
          elsif scanbyroute = 'Y' then
            select count(*)
              into countroutes
              from routestop r
             where r.customer_id = customerid;
          end if;
          if countroutes = 0 then
            statusout := 1;
          end if;
        end if;
        if statusout = 0 then
          -- Order 20013679
          -- do not use sortcustomer when wearer is not linked to external locker
          -- but only when systemsetting ALLOWCUSTLOCKERSHARING=1 for backwards compatibility
          if allowcustlockersharing = '1' and externallockerid is null and
             fp_sortcustomerid is not null then
            fp_sortcustomerid := null;
          end if;
          -- End Order 20013679
          pack_sort.getgarmentlocation(lockerid,
                                       garmentdispenserid,
                                       deliverypointid,
                                       banklocker,
                                       garmentdispensercode,
                                       deliverypointcode);
          -- use external locker if filled
          if externallockerid is not null then
            lockerid            := externallockerid;
            savedeliverypointid := deliverypointid;
            deliverypointid     := null;
            pack_sort.getgarmentlocation(lockerid,
                                         garmentdispenserid,
                                         deliverypointid,
                                         banklocker,
                                         garmentdispensercode,
                                         deliverypointcode);
            deliverypointid := savedeliverypointid;
          end if;
          -- End Order 20013679
          --route
          ---plpc info
          pack_sort.findplpcinfo(customerid,
                                 productid,
                                 sizedefinitionid,
                                 finishingmethodid,
                                 deliverymethod,
                                 deedeliveryschemeid,
                                 plpcid,
                                 vmaxwashes,
                                 plpcfinishingcode,
                                 plpcustomcode,
                                 plpcustomdescription,
                                 pchargewashesonlyforcog,
                                 pbillingmethod,
                                 lv_treatmentcheckschemeid);
        end if; --for statusout=0
      end; -- finish nonpool items
    else
      begin
        --pool items
        wearernumber    := 0;
        deliverypointid := null;
        routedate       := sysdate;

        select c.customernumber, c.name, c.serviceteam_id, c.customer_id, c.chargerepairs,
               c.sortcustomer_id, (select dt.deliverypoint_id
               from distributionpoint dt where dt.distributionpoint_id = nvl(u.distributionpoint_id, u.lastdistributionpoint_link_id))
        into   customernumber, customername, serviceteamid, customerid, vchargerepairs, fp_sortcustomerid, deliverypointid
        from   uniqueitem u
        join   customer c
        on     c.customer_id = u.relatedcustomer_id
        where  u.uniqueitem_id = uniqueitemid;

        pack_sort.findplpcinfo(customerid, productid, sizedefinitionid, finishingmethodid,
                               deliverymethod, deedeliveryschemeid, plpcid, vmaxwashes,
                               plpcfinishingcode, plpcustomcode, plpcustomdescription,
                               pchargewashesonlyforcog, pbillingmethod, lv_treatmentcheckschemeid);
      exception
        when no_data_found then
          begin
            vchargerepairs := 0;
            customernumber := 0;
            customername   := '';
            routenumber    := 0;
            stopnumber     := 0;
            routeday       := getabsdaynumber(sysdate);
          end;
      end;
    end if; --end pool/nonpool
    begin
      --Order 502022
      if routedate is null then
        routedate := sysdate;
      end if;
            -- Order 20014102
            if deliverydetermination = 1 then
              pack_deliverybasics.determinedeldateroutesoil(plantid_garment,
                                                            customerid,
                                                            deliverypointid,
                                                            deparment_id,
                                                            typeofmerch,
                                                            routedate,
                                                            plpcid,
                                                            distributionpointid,
                                                            lv_log,
                                                            lastinroute,
                                                            routestopin,
                                                            inroutecontrol_id,
                                                            instop_id,
                                                            lastindate,
                                                            routeid,
                                                            routestopid,
                                                            outroutecontrol_id,
                                                            stopid,
                                                            planneddate);

            else
              pack_sort.getlastinroute_debug(customerid,
                                             routedate,
                                             deliverypointid,
                                             typeofmerch,
                                             plantid_garment,
                                             lastinroute,
                                             routestopin,
                                             lastindate);

              pack_sort.fillplannedoutroute(plantid_garment,
                                            routedate,
                                            typeofmerch,
                                            deliverymethod,
                                            deedeliveryschemeid,
                                            plpcid,
                                            customerid,
                                            deliverypointid,
                                            lastinroute,
                                            lastindate,
                                            routestopin,
                                            routestopid,
                                            routeid,
                                            planneddate,
                                            scanbyroute);
            end if;
      /* Start Todo 8605 HVH 7/5/2009*/
      -- For Check if route is closed. If yes then determine next one
      if findpackingnote = 'Y' and pool = 2 then
        begin
          routecontrolid  := null;
          rcsortingstatus := null;
          begin
            select rc.routecontrol_id, rc.sortingstatus
            into   routecontrolid, rcsortingstatus
            from   routecontrol rc
            where  rc.route_id = routeid
            and    rc.drivingdate = trunc(planneddate); --HVH added trunc todo 7550
          exception
            when no_data_found then
              null;
          end;
          if rcsortingstatus = 2 /*Closed*/
           then
            begin
              if debuglevel > 0 then
                      pack_sort.write_logging(idcode || ' Route ID ' ||
                                              routecontrolid || ' on ' ||
                                              planneddate ||
                                              ' Closed. Try next visit for customer ' ||
                                              customernumber,
                                              debuglevel,
                                              'PACK_SORT.GETGARMENTDATAINFO',
                                              plantid_garment,
                                              1,
                                              1);
                    end if;
              -- Order 20014102
                    if deliverydetermination = 1 then
                      pack_deliverybasics.determinedeldaterouteclean(plantid_garment,
                                                                    customerid,
                                                                    deliverypointid,
                                                                    deparment_id,
                                                                    typeofmerch,
                                                                    planneddate+1,
                                                                    plpcid,
                                                                    distributionpointid,
                                                                    lv_log,
                                                                    routestopid,
                                                                    routeid,
                                                                    stopid,
                                                                    outroutecontrol_id,
                                                                    planneddate);
              else
                      -- Determine first next delivery day after previous determined next del.day
                      pack_sort.fillplannedoutroute(plantid_garment,
                                                    planneddate,
                                                    --routedate, (start from just determined del.date)
                                                    typeofmerch,
                                                    1,
                                                    --deliverymethod,  (always first next visit)
                                                    deedeliveryschemeid,
                                                    plpcid,
                                                    customerid,
                                                    deliverypointid,
                                                    lastinroute,
                                                    planneddate,
                                                    --lastindate, (start from just determined del.date)
                                                    routestopin,
                                                    routestopid,
                                                    routeid,
                                                    planneddate,
                                                    scanbyroute);
              end if;
              routecontrolid  := null;
              rcsortingstatus := null;
              begin
                select rc.routecontrol_id, rc.sortingstatus
                into   routecontrolid, rcsortingstatus
                from   routecontrol rc
                where  rc.route_id = routeid
                and    rc.drivingdate = trunc(planneddate); --HVH added trunc todo 7550
              exception
                when no_data_found then
                  null;
              end;
              -- if the next one is closed as well
                    if rcsortingstatus = 2 /*Closed*/
                     then
                      pack_sort.write_logging(idcode ||
                                              ' Next Route, Route ID ' ||
                                              routecontrolid || ' on ' ||
                                              planneddate ||
                                              ' also Closed.',
                                              debuglevel,
                                              'PACK_SORT.GETGARMENTDATAINFO',
                                              plantid_garment,
                                              1,
                                              1);
                    end if;
            end;
          end if;
        end;
      end if;
            -- Order 20014102, todo 24578
            if deliverydetermination = 1 and stopid is not null then
              begin
                select s.stopnumber
                  into stopnumber
                  from stop s
                 where s.stop_id = stopid;
              exception
                when others then
                  null;
              end;
              begin
                select r.routenumber,
                       r.drivingday_id,
                       r.sortbatchdefinition_id,
                       r.codeonlabel
                  into routenumber,
                       routeday,
                       sortbatchroute,
                       fp_routecodeonlabel
                  from route r
                 where r.route_id = routeid;
              exception
          when others then
            null;
        end;
        begin
          select s.specificsortbatchdefinition_id
          into   sortbatchstop
          from   routestop s
          where  s.routestop_id = routestopid;
        exception
          when others then
            null;
        end;
            else
              /* End Todo 8605 HVH 7/5/2009*/
              select r.routenumber,
                     r.drivingday_id,
                     s.specificsortbatchdefinition_id,
                     r.sortbatchdefinition_id,
                     r.codeonlabel
                into routenumber,
                     routeday,
                     sortbatchstop,
                     sortbatchroute,
                     fp_routecodeonlabel
                from route r, routestop s
               where s.route_id = routeid
        and    s.customer_id = customerid
        and    s.route_id = r.route_id
        and    s.routestop_id = routestopid;
        --> order 502746
        select s.stopnumber
        into   stopnumber
        from   route r, routestop s
        where  s.route_id = routeid
        and    s.customer_id = customerid
        and    s.route_id = r.route_id
        and    s.routestop_id = routestopid; --< order 502746
      end if;
      if sortingsystem = 'METRIC' then
        if sortbatchstop is not null then
          begin
            select s.batchnumber
            into   stopbatch
            from   sortbatchdefinition s
            where  s.sortbatchdefinition_id = sortbatchstop
            and    s.plant_id = plantid_garment
            and    s.day_id = routeday;
          exception
            when others then
              null;
          end;
        else
          begin
            select s.batchnumber
            into   routebatch
            from   sortbatchdefinition s
            where  s.sortbatchdefinition_id = sortbatchroute
            and    s.plant_id = plantid_garment
            and    s.day_id = routeday;
          exception
            when others then
              null;
          end;
        end if;
        if stopbatch is not null then
          routenumber := stopbatch;
        elsif routebatch is not null then
          routenumber := routebatch;
        end if;
      end if; --for METRIC
    exception
      when no_data_found then
        begin
          routenumber := 0;
          stopnumber  := 0;
          routeday    := getabsdaynumber(sysdate);
        end;
    end;
    --20011459
    if fp_plant_idparam is not null and sortingsystem = 'METRIC' then
      begin
        select s.value
        into   checkinternalsortingplant
        from   systemsetting s
        where  s.plant_id = fp_plant_idparam
        and    s.name = 'CHECKINTERNALSORTINGPLANT';
      exception
        when others then
          --default is 1, so when the system setting is not there work as normal
          checkinternalsortingplant := 1;
      end;
      if checkinternalsortingplant = 0 then
        begin
          select bu.plant_id
          into   internalplantid
          from   productgroup g, customeractivities ca, businessunit bu
          where  g.productgroup_id = productgroupid
          and    g.activity_id = ca.activity_id
          and    ca.customer_id = customerid
          and    ca.processbusinessunit_id = businessunitid
          and    ca.internalprocessingbu_id = bu.businessunit_id;
          if internalplantid <> fp_plant_idparam then
            --status 2, so getgarmentdatabasic can give a specific message internalplantid <> fp_plant_idparam
            statusout := 2;
          end if;
        exception
          when others then
            statusout := 2;
        end;
      end if;
    end if; --end 20011459
    --todo4964
    if plpcfinishingcode is not null then
      finishingcodeid := plpcfinishingcode;
    end if;
    --501875
    if findpackingnote = 'Y' and pool = 2 then
      begin
        plantdepartment_notfound := 1;
        begin
          select a.plantdepartment_id
          into   plantdepartmentid
          from   packingdepartmentdefinition a, plantdepartment pd
          where  a.productgroup_id = productgroupid
          and    a.plant_id = plantid_garment
          and    a.plantdepartment_id = pd.plantdepartment_id
          and    pd.code = 'METRIC';
        exception
          when others then
            plantdepartment_notfound := 0;
            pnnotenumber             := 0;
            findpackingnote          := '00000000';
        end;
        if plantdepartment_notfound = 1 then
          select s.status_id
          into   statusnew
          from   status s
          where  s.statustype = 'PN'
          and    s.code = '10';
          select t.transportarticle_id
          into   defaulttranspart
          from   transportarticle t
          where  t.defaulttransportarticle = 'Y';
          begin
            select rc.routecontrol_id,
                   rc.packingdeadline,
                   rc.packingday_id,
                   rc.drivingdate
              into routecontrolid,
                   rcpackingdeadline,
                   packingday,
                   drivingdate
            from   routecontrol rc
            where  rc.route_id = routeid
            and    rc.drivingdate = trunc(planneddate); --HVH added trunc todo 7550
          exception
            when no_data_found then
              select r.packingdeadline, r.drivingday_id
              into   rcpackingdeadline, routeday
              from   route r
              where  r.route_id = routeid;
              routecontrolid := null;
          end;
          if planneddate is null then
            planneddate := trunc(sysdate);
          else
            planneddate := trunc(planneddate); --HVH added trunc todo 7550
          end if;
          if substr(to_char(rcpackingdeadline, 'yyyymmddhh24miss'), -6, 6) is null then
            rcpackingdeadline := sysdate;
          end if;
          rdeadline                := to_date(substr(to_char(planneddate,
                                                             'yyyymmddhh24miss'),
                                                     1,
                                                     8) ||
                                              substr(to_char(rcpackingdeadline,
                                                             'yyyymmddhh24miss'),
                                                     -6,
                                                     6),
                                              'YYYYMMDDHH24MISS');
          packingnoteid            := null;
          createnewpackingnote     := 'N';
          createnewpackingnoteline := 'N';
          routeinprogress          := 'N';
          if routeinprogress = 'N' then
            createnewpackingnote     := 'Y'; -- assume yes, until one is found
            createnewpackingnoteline := 'Y'; -- assume yes, until one is found
            -- search for existing packingnotes:
            for vcursor in (select pn.packingnote_id,
                                   pn.notenumber,
                                   pn.routecontrol_id
                              from packingnote pn
                             where pn.route_id = routeid
                               and trunc(pn.deliverydate) = planneddate
                               and pn.deliverypoint_id = deliverypointid
                               and pn.distributionpoint_id =
                                   distributionpointid
                               and pn.status_id = statusnew
                               and pn.origin = 2 --in (0, 2) 24/9/2008/HVH COG always on separate PN
                               and pn.plantdepartment_id = plantdepartmentid) --;
             loop
              begin
                createnewpackingnote := 'N'; -- found one, so no new note to be created
                pnnotenumber         := vcursor.notenumber;
                packingnoteid        := vcursor.packingnote_id;
                -- Link packingnote to routecontrol:
                if (vcursor.routecontrol_id is null and
                   routecontrolid is not null) then
                  update packingnote p
                     set p.routecontrol_id = routecontrolid
                  where  p.packingnote_id = vcursor.packingnote_id;
                  -- update RouteControl packingstatus to 'Put Up Printed' when PN is linked to it - todo 8927
                  update routecontrol rc
                  set    rc.packingstatus = 2 -- put up printed
                  where  rc.routecontrol_id = routecontrolid;
                end if;
                select min(pl.packingnoteline_id)
                into   minpackingnotelineid
                from   packingnoteline pl
                where  pl.packingnote_id = vcursor.packingnote_id
                and    pl.product_id = productid
                and    pl.sizedefinition_id = sizedefinitionid;
                if minpackingnotelineid is not null then
                  update packingnoteline pl
                  set    pl.variationamount = pl.variationamount + 1,
                         pl.tobedeliveredamount = pl.tobedeliveredamount + 1
                   where pl.packingnoteline_id = minpackingnotelineid;
                  createnewpackingnoteline := 'N'; -- found row to update, so no new row needs to be created
                  if debuglevel > 0 then
                    pack_sort.write_logging(' update packingnoteline ID ' ||
                                            minpackingnotelineid ||
                                            ' at PN# ' || pnnotenumber,
                                            debuglevel,
                                            'PACK_SORT.GETGARMENTDATAINFO',
                                            plantid_garment,
                                            1,
                                            1);
                  end if;
                  exit; -- exit loop when packingnoteline found.
                end if; --minpackingnotelineid is not null
              exception
                when others then
                  pack_sort.write_logging('!> ' || idcode || ' ' ||
                                          sqlerrm,
                                          debuglevel,
                                          'PACK_SORT.GETGARMENTDATAINFO',
                                          plantid_garment,
                                          3,
                                          1);
              end;
            end loop;
          end if; -- route in progress
          if debuglevel > 0 then
            pack_sort.write_logging('After loop: ' || chr(10) ||
                                    pnnotenumber || ' pnnotenumber ' ||
                                    chr(10) || packingnoteid ||
                                    ' packingnoteid ' || chr(10) ||
                                    createnewpackingnote ||
                                    ' createnewpackingnote ' || chr(10) ||
                                    createnewpackingnoteline ||
                                    ' createnewpackingnoteline ',
                                    debuglevel,
                                    'PACK_SORT.GETGARMENTDATAINFO',
                                    plantid_garment,
                                    1,
                                    1);
          end if;
          begin
            --            if packingnoteid is null and pnnotenumber <> 0 then
            if createnewpackingnote = 'Y' then
              select b.code
                into bucode
                from businessunit b
               where b.businessunit_id = businessunitid;
              /* Start HVH 08/05/2009 Todo 8605 Solve issue when stop has no link to routestop*/
              begin
                if routecontrolid is not null and
                   deliverydetermination <> 1 then
                  select stop.stop_id, stop.stopnumber
                    into stopid, stopnumber
                    from stop
                   where stop.routecontrol_id = routecontrolid
                     and stop.routestop_id = routestopid
                     and stop.customer_link_id = customerid;
                end if;
              exception
                when no_data_found then
                  stopid := null;
              end;
              begin
                -- when not found try to find the first stop in route for customer
                if routecontrolid is not null and stopid is null then
                  select stop.stop_id, stop.stopnumber
                    into stopid, stopnumber
                    from stop
                   where stop.stop_id =
                         (select min(stop1.stop_id)
                            from stop stop1
                           where stop1.routecontrol_id = routecontrolid
                             and stop1.customer_link_id = customerid);
                end if;
              exception
                -- when still not found, then don't link Packingnote to routecontrol
                when no_data_found then
                  routecontrolid := null;
                  stopid         := null;
                  stopnumber     := 0;
              end;
              /* End HVH 08/05/2009 Todo 8605 Solve issue when stop has no link to routestop*/
              execute immediate 'select SEQ_DELIVERYNOTE_' || bucode ||
                                '.nextval from DUAL'
                into pnnotenumber;

              insert into packingnote
                (employee_id,
                 packingnote_id,
                 notenumber,
                 productiondate,
                 deliverydate,
                 status_id,
                 remark,
                 distributionpoint_id,
                 deliverypoint_id,
                 plantdepartment_id,
                 transportarticle_id,
                 systemuser_id,
                 processbusinessunit_id,
                 route_id,
                 timestamp,
                 cleanreturn,
                 sequencenumber,
                 deadline,
                 occupancy,
                 invoicebusinessunit_id,
                 routecontrol_id,
                 originaldeliverydate,
                 --invoiceheader_id,
                 enddateforuse,
                 origin,
                 stopnumber,
                 daynumber,
                 correctednotenumber,
                 creationtimestamp,
                 referencenumber,
                 returndateloan,
                 stop_id,
                 consignmentnote_id,
                 straightevenreturn,
                 numberofgarmentsinlocker,
                 numberoflockers,
                 bulkpackingnote_id,
                 freeofchargereason_id,
                 week,
                 year,
                 weighingticket_id,
                 totalamount,
                 totalamountexcludingvat,
                 pricescalculated,
                 showoninvoiceappendix,
                 deliveryremark)
              values
                (null,
                 seq_packingnote.nextval,
                 pnnotenumber,
                 --
                 trunc(sysdate),
                 trunc(planneddate),
                 statusnew,
                 diremarkondeliverynote,
                 distributionpointid,
                 deliverypointid,
                 plantdepartmentid,
                 defaulttranspart,
                 systemuserid,
                 businessunitid,
                 routeid,
                 sysdate,
                 'N',
                 1,
                 rdeadline,
                 --
                 0,
                 businessunitid,
                 routecontrolid,
                 planneddate,
                 --null,
                 planneddate,
                 2,
                 stopnumber,
                 ---
                 getabsdaynumber(planneddate),
                 0,
                 sysdate,
                 null,
                 null,
                 stopid,
                 null,
                 'N',
                 0,
                 0,
                 null,
                 null,
                 getisoweek(planneddate),
                 year(planneddate),
                 null,
                 0,
                 0,
                 'N',
                 'N',
                 'N'); --

              /*              -- update RouteControl packingstatus to 'Put Up Printed' when PN is linked to it - todo 8927
              update routecontrol rc
              set    rc.packingstatus = 2 -- put up printed
              where  rc.routecontrol_id = routeid;*/
              execute immediate 'select SEQ_PACKINGNOTE.currval from DUAL'
                into packingnoteid;
              if debuglevel > 0 then
                pack_sort.write_logging(' Create new Packnote with ID ' ||
                                        packingnoteid,
                                        debuglevel,
                                        'PACK_SORT.GETGARMENTDATAINFO',
                                        plantid_garment,
                                        1,
                                        1);
              end if;
            end if;
            if createnewpackingnoteline = 'Y' then
              begin
                insert into packingnoteline
                  (packingnoteline_id,
                   product_id,
                   packingsequence,
                   finishingmethod_id,
                   price,
                   discount,
                   packingnote_id,
                   sizedefinition_id,
                   systemuser_id,
                   location,
                   timestamp,
                   remarkforpackinginstructions,
                   customcode,
                   customdescription,
                   replacementqty,
                   autoreplacementqty,
                   updaterentqty,
                   adjustmentreason_id,
                   origin,
                   putuptype,
                   freeofchargereason_id,
                   nochargefirstissue,
                   nochargeactiveseason,
                   deliveredcogqty,
                   auxiliarystatus,
                   standardamount,
                   variationamount,
                   deliveredamount,
                   tobedeliveredamount,
                   amount,
                   taxgroupcode,
                   bundleqty,
                   nochargefirstissuecog,
                   scannedbundles,
                   pricecog,
                   invoiceheader_id)
                values
                  (seq_packingnoteline.nextval,
                   productid,
                   0,
                   finishingmethodid,
                   0,
                   --
                   0,
                   --
                   packingnoteid,
                   --seq_packingnote.currval,
                   sizedefinitionid,
                   systemuserid,
                   null,
                   sysdate,
                   '',
                   plpcustomcode,
                   plpcustomdescription,
                   0,
                   --replacementqty,
                   0,
                   --autoreplacementqty,
                   0,
                   --updaterentqty,
                   null,
                   --adjustmentreason_id,
                   2,
                   1,
                   null,
                   --freeofchargereason_id,
                   0,
                   --nochargefirstissue,
                   0,
                   --nochargeactiveseason,
                   0,
                   --deliveredcogqty,
                   null,
                   --auxiliarystatus,
                   0,
                   --standardamount,
                   1,
                   --variationamount,
                   0,
                   --deliveredamount,
                   1,
                   --tobedeliveredamount,
                   0,
                   --amount,
                   null,
                   --taxgroupcode,
                   0,
                   --bundleqty,
                   0,
                   --nochargefirstissuecog,
                   0,
                   --scannedbundles,
                   0,
                   --pricecog
                   null
                   --invoiceHeader
                   );
                if debuglevel > 0 then
                  pack_sort.write_logging(' Create new Packnoteline for PN# ' ||
                                          pnnotenumber,
                                          debuglevel,
                                          'PACK_SORT.GETGARMENTDATAINFO',
                                          plantid_garment,
                                          1,
                                          1);
                end if;
              exception
                when others then
                  pack_sort.write_logging('!> Create new Packnoteline for PN# ' ||
                                          pnnotenumber || ' for IDCODE ' ||
                                          idcode || ' ' || sqlerrm,
                                          debuglevel,
                                          'PACK_SORT.GETGARMENTDATAINFO',
                                          plantid_garment,
                                          3,
                                          1);
              end;
            end if;
          end;
          if length(to_char(pnnotenumber)) <= 8 then
            char_notenumber := lpad(to_char(pnnotenumber), 8, '0');
          elsif length(to_char(pnnotenumber)) > 8 then
            char_notenumber := substr(to_char(pnnotenumber), -8, 8);
          end if;
          if (drivingdate is not null or packingday is not null) then
            if (getabsdaynumber(drivingdate) - packingday >= 0) then
              packingdatetime := drivingdate -
                                 (getabsdaynumber(drivingdate) - packingday);
            else
              packingdatetime := drivingdate - (getabsdaynumber(drivingdate) +
                                 (7 - packingday));
            end if;
          else
            if (routeday - getabsdaynumber(sysdate + 1) >= 0) then
              packingdatetime := sysdate + 1 +
                                 (routeday - getabsdaynumber(sysdate + 1));
            else
              packingdatetime := sysdate + 1 +
                                 ((7 - getabsdaynumber(sysdate + 1)) +
                                 routeday);
            end if;
          end if;
          findpackingnote := char_notenumber ||
                             substr(to_char(packingdatetime,
                                            'yyyymmddhh24miss'),
                                    1,
                                    8) || substr(to_char(rcpackingdeadline,
                                                         'yyyymmddhh24miss'),
                                                 -6,
                                                 4);
          ---daca nu e plantdepartment atunci findpackingnote ar trebui sa returneze?
        end if;
      end;
    elsif findpackingnote = 'Y' and pool <> 2 then
      findpackingnote := '';
    end if; --end of 501875 packingnote
  end getgarmentdatainfo;
  function convertstringdesc(receivedstring varchar2) return varchar2 is
    aux          varchar2(1);
    newaux       varchar2(1);
    returnstring varchar2(100);
    cnt          integer;
  begin
    returnstring := '';
    cnt          := length(receivedstring);
    if cnt > 0 then
      for i in 1 .. cnt loop
        aux := substr(receivedstring, i, 1);
        if 32 <= ascii(aux) and ascii(aux) <= 126 then
          newaux := chr(126 - (ascii(aux) - 32));
        else
          newaux := aux;
        end if;
        returnstring := returnstring || newaux;
      end loop;
    end if;
    return returnstring;
  end convertstringdesc;
  function get_sortroutestop(fp_plantid_param  in plant.plant_id%type,
                             fp_stopnumber     in stop.stopnumber%type,
                             fp_customernumber in customer.customernumber%type)
    return varchar2 is
    lv_sortstring varchar2(255);
    lv_maxsortlengthstop number;
    lv_maxsortlengthcustomer number;

  begin
    --Sort string --Stack change info
    begin
      select s.value
        into gv_sortroutestop
        from systemsetting s
       where s.plant_id = fp_plantid_param
         and s.name = 'SORTROUTESTOP';
    exception
      when others then
        gv_sortroutestop := 'A';
    end;
    begin
      select to_number(s.value)
        into lv_maxsortlengthstop
        from systemsetting s
       where s.plant_id = fp_plantid_param
         and s.name = 'MAXSORTLENGTHSTOP';
    exception
      when others then
        lv_maxsortlengthstop := 6;
    end;
    begin
      select to_number(s.value)
        into lv_maxsortlengthcustomer
        from systemsetting s
       where s.plant_id = fp_plantid_param
         and s.name = 'MAXSORTLENGTHCUSTOMER';
    exception
      when others then
        lv_maxsortlengthcustomer := 12;
    end;
    case gv_sortroutestop
      when 'A' then
        --default is 'A' ascending
        lv_sortstring := substr(lpad(to_char(fp_stopnumber), 6, 0),lv_maxsortlengthstop*-1,lv_maxsortlengthstop) ||
                         substr(lpad(fp_customernumber, 12, 0),lv_maxsortlengthcustomer*-1,lv_maxsortlengthcustomer);
      when 'D' then
        --other option 'D' descending
        lv_sortstring := substr(lpad(to_char(999999 - fp_stopnumber), 6, 0),lv_maxsortlengthstop*-1,lv_maxsortlengthstop) ||
                         substr(lpad(999999999999 - fp_customernumber, 12, 0),lv_maxsortlengthcustomer*-1,lv_maxsortlengthcustomer);
      when 'Y' then
        --new option 'Y' is customer only export
        lv_sortstring := substr(lpad(fp_customernumber, 12, 0),lv_maxsortlengthcustomer*-1,lv_maxsortlengthcustomer);
      when 'Z' then
        --new option 'Z' no customer nor stopnumber; order#502901
        lv_sortstring := null;
      when 'S' then
        --new short option 'S', to use shorter values for different field
        --customer length 10, deliverypoint 3, wearer# 6, wearer searchname 12
        lv_sortstring := lpad(to_char(fp_stopnumber), 6, 0) ||
                         lpad(substr(to_char(fp_customernumber), 1, 10),
                              10,
                              0);
      else
        lv_sortstring := substr(lpad(to_char(fp_stopnumber), 6, 0),lv_maxsortlengthstop*-1,lv_maxsortlengthstop) ||
                         substr(lpad(fp_customernumber, 12, 0),lv_maxsortlengthcustomer*-1,lv_maxsortlengthcustomer);
    end case;
    return lv_sortstring;
  end get_sortroutestop;
  function buildsortstring(productcode          in product.code%type,
                           sizecode             in sizedefinition.code%type,
                           customernumber       in customer.customernumber%type,
                           customerid           in customer.customer_id%type,
                           wearernumber         in wearer.wearernumber%type,
                           wearername           in wearer.searchname%type,
                           banklocker           in varchar2,
                           departmentnumber     in department.departmentnumber%type,
                           customeremployee#    in wearer.customeremployeenumber%type,
                           gender               in wearer.sex%type,
                           garmentdispensercode in garmentdispenser.code%type,
                           deliverypointcode    in deliverypoint.code%type,
                           stopnumber           in routestop.stopnumber%type,
                           plantid_param        in plant.plant_id%type,
                           customerownedyn      in varchar2,
                           ordernumber          in packingnote.notenumber%type,
                           productsortgroupseq  in productsortgroupperplant.sequencenumber%type,
                           lockersortgroup#     in lockersortgroup.lockersortgroupnumber%type,
                           distributionpoint#   in distributionpoint.distributionpointnumber%type,
                           fp_sortcustomerid    in customer.sortcustomer_id%type,
                           fp_seasoncode        in season.code%type,
                           fp_finsortstring     in sortaddressperfinishingcode.sortaddress%type default null,
                           fp_stackchange in sortingdefinition.stackchange%type default 'N')
    return varchar2 is
    --replaces getsortstrings together with build stackchangeinfo
    cnt                   integer;
    customerowned10       integer;
    vwearernumber         wearer.wearernumber%type;
    vwearername           wearer.searchname%type;
    vbanklocker           varchar2(12);
    vdepartmentnumber     department.departmentnumber%type;
    vcustomeremployee#    wearer.customeremployeenumber%type;
    vgender               wearer.sex%type;
    vgarmentdispensercode garmentdispenser.code%type;
    vdeliverypointcode    deliverypoint.code%type;
    vproductcode          product.code%type;
    vsizecode             sizedefinition.code%type;
    sortstringlength      integer;
    vordernumber          packingnote.notenumber%type;
    sortstring            varchar2(255);
    vproductsortgroup     productsortgroupperplant.sequencenumber%type;
    vlockersortgroup      lockersortgroup.lockersortgroupnumber%type;
    vdistributionpoint#   distributionpoint.distributionpointnumber%type;
    lv_prodsizesequence   productsize.sequencenumber%type;
    lvcustomernumber      customer.customernumber%type;

    procedure build_string(fp_sortfield      in sortingdefinition.sortfield%type,
                           fp_sortdescending in sortingdefinition.sortdescending%type) is
      lvbanklocker             varchar2(12) := vbanklocker;
      lv_maxsortlengthwearernr number;
      lv_maxsortlengthdelpoint number;

      function get_sort_string(fp_string in varchar2, fp_length in number) return varchar2 is
      begin
        --get_sort_string
        if fp_sortdescending = 'Y' then
          return substr(convertstringdesc(rpad(nvl(fp_string, ' '), fp_length, ' ')), 1, fp_length);
        else
          return rpad(substr(nvl(fp_string, ' '), 1, fp_length), fp_length, ' ');
        end if;
      end get_sort_string;
    begin
      case fp_sortfield
        when 1 then
          begin
            if fp_sortdescending = 'Y' then
              vdepartmentnumber := 999999 - departmentnumber;
            else
              vdepartmentnumber := departmentnumber;
            end if;
            sortstring := sortstring ||
                          lpad(to_char(vdepartmentnumber), 6, 0);
          end;
        when 2 then
          begin
            begin
              select to_number(s.value)
                into lv_maxsortlengthwearernr
                from systemsetting s
               where s.plant_id = plantid_param
                 and s.name = 'MAXSORTLENGTHWEARERNR';
            exception
              when others then
                lv_maxsortlengthwearernr := 12;
            end;
            if fp_sortdescending = 'Y' then
              vwearernumber := 999999999999 - wearernumber;
            else
              vwearernumber := wearernumber;
            end if;
            if gv_sortroutestop = 'S' then
              sortstring := sortstring ||
                            lpad(substr(to_char(vwearernumber), 1, 6), 6, 0);
            else
              sortstring := sortstring ||
                            substr(lpad(to_char(vwearernumber), 12, 0),lv_maxsortlengthwearernr*-1,lv_maxsortlengthwearernr);
            end if;
          end;
        when 3 then
          begin
            if fp_sortdescending = 'Y' then
              vwearername := convertstringdesc(rpad(wearername, 20, ' '));
            else
              vwearername := rpad(wearername, 20, ' ');
            end if;
            if gv_sortroutestop = 'S' then
              sortstring := sortstring || substr(vwearername, 1, 4);
            else
              sortstring := sortstring || vwearername;
            end if;
          end;
        when 4 then
          begin
            if fp_sortdescending = 'Y' then
              vcustomeremployee# := convertstringdesc(rpad(vcustomeremployee#,
                                                           10,
                                                           ' '));
            else
              vcustomeremployee# := rpad(vcustomeremployee#, 10, ' ');
            end if;
            sortstring := sortstring || vcustomeremployee#;
          end;
        when 5 then
          begin
            if fp_sortdescending = 'Y' then
              lvbanklocker := convertstringdesc(lvbanklocker);
            end if;
            sortstring := sortstring || lvbanklocker;
          end;
        when 6 then
          begin
            if fp_sortdescending = 'Y' then
              vgender := convertstringdesc(gender);
            else
              vgender := gender;
            end if;
            sortstring := sortstring || vgender;
          end;
        when 7 then
          begin
            if fp_sortdescending = 'Y' then
              vproductcode := convertstringdesc(rpad(productcode, 12, ' '));
            else
              vproductcode := rpad(productcode, 12, ' ');
            end if;
            sortstring := sortstring || vproductcode;
          end;
        when 8 then
          begin
            if fp_sortdescending = 'Y' then
              vsizecode := convertstringdesc(rpad(sizecode, 12, ' '));
            else
              vsizecode := rpad(sizecode, 12, ' ');
            end if;
            sortstring := sortstring || vsizecode;
          end;
        when 9 then
          begin
            begin
              select to_number(s.value)
                into lv_maxsortlengthdelpoint
                from systemsetting s
               where s.plant_id = plantid_param
                 and s.name = 'MAXSORTLENGTHDELPOINT';
            exception
              when others then
                lv_maxsortlengthdelpoint := 12;
            end;

            if fp_sortdescending = 'Y' then
              vdeliverypointcode := convertstringdesc(rpad(deliverypointcode,
                                                           12,
                                                           ' '));
            else
              vdeliverypointcode := rpad(deliverypointcode, 12, ' ');
            end if;
            if gv_sortroutestop = 'S' then
              sortstring := sortstring || substr(vdeliverypointcode, 1, 3);
            else
              sortstring := sortstring || substr(vdeliverypointcode,1,lv_maxsortlengthdelpoint);
            end if;
          end;
        when 10 then
          begin
            if fp_sortdescending = 'Y' then
              vgarmentdispensercode := convertstringdesc(rpad(garmentdispensercode,
                                                              6,
                                                              ' '));
            else
              vgarmentdispensercode := rpad(garmentdispensercode, 6, ' ');
            end if;
            sortstring := sortstring || vgarmentdispensercode;
          end;
        when 11 then
          begin
            if fp_sortdescending = 'Y' then
              customerowned10 := 9 - customerowned10;
            end if;
            sortstring := sortstring || customerowned10;
          end;
        when 12 then
          begin
            if fp_sortdescending = 'Y' then
              vordernumber := 99999999 - ordernumber;
            else
              vordernumber := ordernumber;
            end if;
            if ordernumber = 0 then
              sortstring := sortstring || '00000000';
            else
              sortstring := sortstring || lpad(to_char(vordernumber), 8, 0);
            end if;
          end;
          --order#502177
        when 13 then
          begin
            if fp_sortdescending = 'Y' then
              lvbanklocker := convertstringdesc(substr(lvbanklocker, 1, 6));
            else
              lvbanklocker := substr(lvbanklocker, 1, 6);
            end if;
            sortstring := sortstring || lvbanklocker;
          end;
        when 14 then
          begin
            if fp_sortdescending = 'Y' then
              vproductsortgroup := 999 - productsortgroupseq;
            else
              vproductsortgroup := productsortgroupseq;
            end if;
            if vproductsortgroup = 0 then
              sortstring := sortstring || '000';
            else
              sortstring := sortstring ||
                            lpad(to_char(vproductsortgroup), 3, 0);
            end if;
          end;
        when 15 then
          begin
            if fp_sortdescending = 'Y' then
              vlockersortgroup := 999 - lockersortgroup#;
            else
              vlockersortgroup := lockersortgroup#;
            end if;
            if vlockersortgroup = 0 then
              sortstring := sortstring || '000';
            else
              sortstring := sortstring ||
                            lpad(to_char(vlockersortgroup), 3, 0);
            end if;
          end;
        when 16 then
          begin
            if fp_sortdescending = 'Y' then
              vdistributionpoint# := 99 - distributionpoint#;
            else
              vdistributionpoint# := distributionpoint#;
            end if;
            if vdistributionpoint# = 0 then
              sortstring := sortstring || '00';
            else
              sortstring := sortstring ||
                            lpad(to_char(vdistributionpoint#), 2, 0);
            end if;
          end;
        when 17 then
          --order#20012684
          begin
            select nvl(max(ps.sequencenumber), 0)
              into lv_prodsizesequence
              from productsize ps
              join product p
                on p.product_id = ps.product_id
              join sizedefinition s
                on s.sizedefinition_id = ps.sizedefinition_id
             where p.code = productcode
               and s.code = sizecode;
            if fp_sortdescending = 'Y' then
              lv_prodsizesequence := 999 - lv_prodsizesequence;
            end if;
            if lv_prodsizesequence = 0 then
              sortstring := sortstring || '000';
            else
              sortstring := sortstring ||
                            lpad(substr(to_char(lv_prodsizesequence), 1, 3),
                                 3,
                                 0);
            end if;
          end;
        when 18 then
          begin
            --fp_seasoncode
            sortstring := sortstring || get_sort_string(fp_seasoncode, 6);
          end;
        when 19 then
          begin
            --fp_finsortstring
            sortstring := sortstring || get_sort_string(fp_finsortstring, 6);
          end;
        else
          begin
            write_logging('sortfield ' || fp_sortfield || ' unknown/not implemented', 0,
                          'pack_sort.buildsortstring', null, 3);
          end;
      end case;
    end build_string;
  begin
    if fp_sortcustomerid is null then
      lvcustomernumber := customernumber;
    else
      begin
        select nvl(max(c.customernumber), 0)
          into lvcustomernumber
          from customer c
         where c.customer_id = fp_sortcustomerid;
      end;
    end if;
    --order#502901
    sortstring := get_sortroutestop(plantid_param,
                                    stopnumber,
                                    lvcustomernumber);
    --
    if customerownedyn = 'Y' then
      customerowned10 := 1;
    else
      customerowned10 := 0;
    end if;
    if customeremployee# is not null then
      vcustomeremployee# := rpad(to_char(customeremployee#), 10, ' ');
    else
      vcustomeremployee# := '          ';
    end if;
    if banklocker is null then
      vbanklocker := '            ';
    else
      vbanklocker := rpad(banklocker, 12, ' ');
    end if;
    cnt := 0;
    if fp_sortcustomerid is not null then
      for vcursor in (select s.sortfield,
                             s.sortdescending,
                             s.stackchange,
                             (select count(t.sortingdefinition_id)
                                from sortingdefinition t
                               where t.customer_id = s.customer_id
                                 and t.stackchange = 'Y') stackyescount
                        from sortingdefinition s
                       where s.customer_id = fp_sortcustomerid
                       order by s.priority asc) loop
        begin
          cnt := cnt + 1;
          exit when(fp_stackchange = 'Y' and vcursor.stackyescount = 0);
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    if cnt = 0 then
      for vcursor in (select s.sortfield,
                             s.sortdescending,
                             s.stackchange,
                             (select count(t.sortingdefinition_id)
                                from sortingdefinition t
                               where t.customer_id = s.customer_id
                                 and t.stackchange = 'Y') stackyescount
                        from sortingdefinition s
                       where s.customer_id = customerid
                       order by s.priority asc) loop
        begin
          cnt := cnt + 1;
          exit when(fp_stackchange = 'Y' and vcursor.stackyescount = 0);
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    if cnt = 0 then
      for vcursor in (select s.sortfield,
                             s.sortdescending,
                             s.stackchange,
                             (select count(t.sortingdefinition_id)
                                from sortingdefinition t
                               where t.plant_id = s.plant_id
                                 and t.stackchange = 'Y') stackyescount
                        from sortingdefinition s
                       where s.plant_id = plantid_param
                       order by s.priority asc) loop
        begin
          exit when(fp_stackchange = 'Y' and vcursor.stackyescount = 0);
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    --order 501781
    begin
      select s.value
        into sortstringlength
        from systemsetting s
       where s.plant_id = plantid_param
         and s.name = 'SORTSTRINGLENGTH';
      if sortstringlength = 2 then
        sortstringlength := 80;
      else
        sortstringlength := 60;
      end if;
    exception
      when others then
        sortstringlength := 60;
    end;
    sortstring := substr(sortstring, 1, sortstringlength);
    return sortstring;
  end buildsortstring;
  function buildstackchangeinfo(productcode          in product.code%type,
                                sizecode             in sizedefinition.code%type,
                                customernumber       in customer.customernumber%type,
                                customerid           in customer.customer_id%type,
                                wearernumber         in wearer.wearernumber%type,
                                wearername           in wearer.searchname%type,
                                banklocker           in varchar2,
                                departmentnumber     in department.departmentnumber%type,
                                customeremployee#    in wearer.customeremployeenumber%type,
                                gender               in wearer.sex%type,
                                garmentdispensercode in garmentdispenser.code%type,
                                deliverypointcode    in deliverypoint.code%type,
                                stopnumber           in routestop.stopnumber%type,
                                plantid_param        in plant.plant_id%type,
                                customerownedyn      in varchar2,
                                ordernumber          in packingnote.notenumber%type,
                                productsortgroupseq  in productsortgroupperplant.sequencenumber%type,
                                lockersortgroup#     in lockersortgroup.lockersortgroupnumber%type,
                                distributionpoint#   in distributionpoint.distributionpointnumber%type,
                                fp_sortcustomerid    in customer.sortcustomer_id%type,
                                fp_seasoncode        in season.code%type,
                                fp_finsortstring     in sortaddressperfinishingcode.sortaddress%type default null)
    return varchar2 is
  begin
    --replaces getsortstrings this one builds stackchangeinfo
    return pack_sort.buildsortstring(productcode,
                                     sizecode,
                                     customernumber,
                                     customerid,
                                     wearernumber,
                                     wearername,
                                     banklocker,
                                     departmentnumber,
                                     customeremployee#,
                                     gender,
                                     garmentdispensercode,
                                     deliverypointcode,
                                     stopnumber,
                                     plantid_param,
                                     customerownedyn,
                                     ordernumber,
                                     productsortgroupseq,
                                     lockersortgroup#,
                                     distributionpoint#,
                                     fp_sortcustomerid,
                                     fp_seasoncode,
                                     fp_finsortstring,
                                     'Y');
  end buildstackchangeinfo;
  function getsortstring(plantid_param in plant.plant_id%type,
                         customerid    in customer.customer_id%type,
                         routestopid   in routestop.routestop_id%type,
                         uniqueitemid  in uniqueitem.uniqueitem_id%type)
    return varchar2 is
    sortstring                 varchar2(255);
    productcode                product.code%type;
    sizecode                   sizedefinition.code%type;
    customernumber             customer.customernumber%type;
    wearernumber               wearer.wearernumber%type;
    wearername                 wearer.searchname%type;
    banklocker                 varchar2(12);
    departmentnumber           department.departmentnumber%type;
    customeremployee#          wearer.customeremployeenumber%type;
    gender                     wearer.sex%type;
    garmentdispensercode       garmentdispenser.code%type;
    deliverypointcode          deliverypoint.code%type;
    lockerid                   locker.locker_id%type;
    garmentdispenserid         garmentdispenser.garmentdispenser_id%type;
    deliverypointid            deliverypoint.deliverypoint_id%type;
    stopnumber                 routestop.stopnumber%type;
    packingsequence            product.packingsequence%type;
    vcustomerowned             varchar2(1);
    vordernumber               packingnote.notenumber%type;
    productsortgroupseq        productsortgroupperplant.sequencenumber%type;
    lockersortgroup#           lockersortgroup.lockersortgroupnumber%type;
    distributionpoint#         distributionpoint.distributionpointnumber%type;
    sortcustomerid             customer.sortcustomer_id%type;
    seasoncode                 season.code%type;
    lv_customerid              customer.customer_id%type;
    lv_productid               product.product_id%type;
    lv_sizeid                  sizedefinition.sizedefinition_id%type;
    lv_finishingmethodid       finishingmethod.finishingmethod_id%type;
    lv_deliverymethod          number;
    lv_deedeliveryschemeid     number;
    lv_plpcid                  number;
    lv_vmaxwashes              number;
    lv_p_finishingid           number; --from product
    lv_l_finishingid           number; --from plpc
    lv_plpcustomcode           productlistpercustomer.customcode%type;
    lv_plpcustomdescription    productlistpercustomer.customdescription%type;
    lv_pchargewashesonlyforcog number;
    lv_pbillingmethod          number;
    lv_treatmentcheckschemeid  number;
    lv_finishingsortaddr       sortaddressperfinishingcode.sortaddress%type;
  begin
    sortstring := '';
    begin
      begin
        select p.code,
               s.code,
               w.wearernumber,
               w.searchname,
               w.customeremployeenumber,
               w.sex,
               (select d.departmentnumber
                  from department d, distributionpoint di
                 where di.distributionpoint_id =
                       coalesce(e.distributionpoint_id,
                                u.distributionpoint_id)
                   and di.department_id = d.department_id),
               e.deliverypoint_id,
               e.locker_id,
               e.garmentdispenser_id,
               p.packingsequence,
               u.customerowned,
               nvl(psgp.sequencenumber, 0),
               nvl(lsg.lockersortgroupnumber, 0),
               (select di.distributionpointnumber
                  from distributionpoint di
                 where di.distributionpoint_id =
                       coalesce(e.distributionpoint_id,
                                u.distributionpoint_id)) distributionpointnumber,
               c.customernumber,
               c.sortcustomer_id,
               p.finishingcode_id,
               (select ss.code --show season when NOT in the season!!
                from   season ss
                where  ss.season_id = wi.season_id
                and    not exists (select 1
                           from   seasonweek sw
                           where  sw.season_id = ss.season_id
                           and    sw.weeknumber = getisoweek(sysdate))) seasoncode
          into productcode,
               sizecode,
               wearernumber,
               wearername,
               customeremployee#,
               gender,
               departmentnumber,
               deliverypointid,
               lockerid,
               garmentdispenserid,
               packingsequence,
               vcustomerowned,
               productsortgroupseq,
               lockersortgroup#,
               distributionpoint#,
               customernumber,
               sortcustomerid,
               lv_p_finishingid,
               seasoncode
          from uniqueitem u
          left outer join(uniqueitemnonpool n
          join weareremployment e
            on e.weareremployment_id = n.weareremployment_id
          join wearerinventory wi
            on wi.wearerinventory_id = n.wearerinventory_id
          join wearer w
            on w.wearer_id = e.wearer_id) on n.uniqueitem_id = u.uniqueitem_id
          join customer c
            on c.customer_id = w.customer_id
          left outer join(locker l
          join lockersortgroup lsg
            on lsg.lockersortgroup_id = l.lockersortgroup_id) on e.locker_id = l.locker_id
          join product p
            on p.product_id = u.product_id
          left outer join productsortgroupperplant psgp
            on (psgp.productsortgroup_id = p.productsortgroup_id and
               psgp.plant_id = plantid_param)
          join sizedefinition s
            on s.sizedefinition_id = u.sizedefinition_id
         where u.uniqueitem_id = uniqueitemid;
      exception
        when no_data_found then
          sortstring := '01';
      end;
      if sortstring is null then
        pack_sort.getgarmentlocation(lockerid,
                                     garmentdispenserid,
                                     deliverypointid,
                                     banklocker,
                                     garmentdispensercode,
                                     deliverypointcode);
        begin
          select rs.stopnumber
            into stopnumber
            from routestop rs
           where rs.routestop_id = routestopid;
        exception
          when no_data_found then
            sortstring := '02';
        end;
      end if;
      --Sort string
      if sortstring is null then
        begin
          findplpcinfo(lv_customerid, lv_productid, lv_sizeid, lv_finishingmethodid,
                       lv_deliverymethod, lv_deedeliveryschemeid, lv_plpcid, lv_vmaxwashes,
                       lv_l_finishingid, lv_plpcustomcode, lv_plpcustomdescription,
                       lv_pchargewashesonlyforcog, lv_pbillingmethod, lv_treatmentcheckschemeid);
          --
          select max(sx.sortaddress)
          into   lv_finishingsortaddr
          from   sortaddressperfinishingcode sx
          where  sx.plant_id = plantid_param
          and    sx.finishingcode_id = nvl(lv_l_finishingid, lv_p_finishingid);
          --
          sortstring := pack_sort.buildsortstring(productcode,
                                                  sizecode,
                                                  customernumber,
                                                  customerid,
                                                  wearernumber,
                                                  wearername,
                                                  banklocker,
                                                  departmentnumber,
                                                  customeremployee#,
                                                  gender,
                                                  garmentdispensercode,
                                                  deliverypointcode,
                                                  stopnumber,
                                                  plantid_param,
                                                  vcustomerowned,
                                                  vordernumber,
                                                  productsortgroupseq,
                                                  lockersortgroup#,
                                                  distributionpoint#,
                                                  sortcustomerid,
                                                  seasoncode,
                                                  lv_finishingsortaddr);
        end;
      end if;
    exception
      when others then
        sortstring := '0';
    end;
    return(sortstring);
  end getsortstring;
  procedure getdeliverydaysmask(customerid      in customer.customer_id%type,
                                deliverydaymask out nocopy varchar2) is
    aux varchar2(8);
  begin
    -- delivery day mask
    deliverydaymask := 'NNNNNNN';
    for vcursor in (select x.day_id
                      from customerdeliveryday x
                     where x.customer_id = customerid
                       and x.typeofmerchadise = 2) loop
      begin
        aux             := replace(substr(deliverydaymask,
                                          vcursor.day_id,
                                          1),
                                   'N',
                                   'Y');
        deliverydaymask := substr(deliverydaymask, 1, vcursor.day_id - 1) || aux ||
                           substr(deliverydaymask, vcursor.day_id + 1, 7);
      end;
    end loop;
  end getdeliverydaysmask;
  procedure getdepot(routeid in route.route_id%type,
                     depot   out nocopy depot.code%type) is
  begin
    --depot
    select d.code
      into depot
      from depot d, route r
     where r.route_id = routeid
       and r.depot_id = d.depot_id;
  exception
    when no_data_found then
      depot := 0;
  end getdepot;
  --update flags
  function updateflags(flagsstring    in varchar2,
                       uniqueitemid   in uniqueitem.uniqueitem_id%type,
                       fplastscandate in date,
                       systemuserid   in systemuser.systemuser_id%type,
                       debuglevel     in integer) return integer is
    statusout    integer;
    flagcode     flag.code%type;
    aux          varchar2(500);
    laststring   varchar2(300);
    flagid       flag.flag_id%type;
    flaginserted boolean;
  begin
    statusout  := 0;
    laststring := flagsstring;
    while laststring is not null loop
      --aux := substr(laststring, 1, instr(laststring, chr(10), 1) - 1);
      aux := replace(laststring, chr(10));
      if aux is null then
        flagcode   := null;
        laststring := null;
      else
        flagcode   := substr(aux, 1, instr(aux, ':', 1) - 1);
        aux        := aux || chr(13) || chr(10);
        laststring := ltrim(laststring, aux);
      end if;
      flagid := null;
      begin
        begin
          select f.flag_id
            into flagid
            from flag f
           where f.code = flagcode
             and not exists (select u.flag_id
                    from uniqueitemflag u
                   where u.uniqueitem_id = uniqueitemid
                     and u.flag_id = f.flag_id);
        exception
          when no_data_found then
            null;
        end;
        if flagid is not null then
          flaginserted := pack_sort.create_uniqueitemflag('PACK_SORT.UPDATEFLAGS',
                                                          debuglevel,
                                                          systemuserid,
                                                          uniqueitemid,
                                                          flagid,
                                                          fplastscandate);
        end if;
      exception
        when others then
          begin
            statusout := 1;
            pack_sort.write_logging(' NOT insert uniqueitemflag - scanflag for uniqueitemID/flagID ' ||
                                    uniqueitemid || '/' || flagid,
                                    debuglevel,
                                    'PACK_SORT.UPDATEFLAGS',
                                    null,
                                    3,
                                    1);
          end;
      end;
    end loop;
    return(statusout);
  end updateflags;
  procedure getsendtrackinfo(pool                 in uniqueitem.poolitem%type,
                             uniqueitemid         in uniqueitem.uniqueitem_id%type,
                             stayid               out nocopy stay.stay_id%type,
                             statusid             out nocopy status.status_id%type,
                             productid            out nocopy product.product_id%type,
                             sizeid               out nocopy sizedefinition.sizedefinition_id%type,
                             weareremploymentid   out nocopy weareremployment.weareremployment_id%type,
                             customerid           out nocopy customer.customer_id%type,
                             vissuedate           out nocopy date,
                             finishingmethodid    out nocopy finishingmethod.finishingmethod_id%type,
                             distributionpointid  out nocopy distributionpoint.distributionpoint_id%type,
                             lastdistribpointid   out nocopy distributionpoint_link.distributionpoint_link_id%type,
                             vwashestotal         out nocopy integer,
                             vcustomerowned       out nocopy varchar2,
                             qualitygradeid       out nocopy qualitygrade.qualitygrade_id%type,
                             vfirstissuedate      out nocopy date,
                             vnumberofissues      out nocopy integer,
                             vlastonstockdate     out nocopy date,
                             vdaysinstockprevious out nocopy integer,
                             vstatuschangedate    out nocopy date,
                             vstartrentfrom       out nocopy integer,
                             vdaysincircprevissue out nocopy integer,
                             vwashesthisissue     out nocopy integer,
                             unrelatedloanid      out nocopy unrelatedloan.unrelatedloan_id%type,
                             vlastinscandate      out nocopy date,
                             deliverypointid      out nocopy deliverypoint.deliverypoint_id%type,
                             lockerid             out nocopy locker.locker_id%type,
                             garmentdispenserid   out nocopy garmentdispenser.garmentdispenser_id%type,
                             accept               in out varchar2) is
  begin
    if pool = 2 then
      --nonpool
      begin
        select u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               n.weareremployment_id,
               w.customer_id,
               f.lastissuedate,
               u.lastinscandate,
               u.stay_id,
               u.status_id,
               u.statuschangedate,
               u.washestotal,
               u.customerowned,
               f.qualitygrade_id,
               f.firstissuedate,
               f.numberofissues,
               f.lastonstockdate,
               f.daysinstockprevious,
               f.daysincircprevissue,
               n.washesthisissue,
               u.unrelatedloan_id,
               u.startrentfrom,
               e.distributionpoint_id,
               e.deliverypoint_id,
               e.locker_id,
               e.garmentdispenser_id
          into productid,
               sizeid,
               finishingmethodid,
               weareremploymentid,
               customerid,
               vissuedate,
               vlastinscandate,
               stayid,
               statusid,
               vstatuschangedate,
               vwashestotal,
               vcustomerowned,
               qualitygradeid,
               vfirstissuedate,
               vnumberofissues,
               vlastonstockdate,
               vdaysinstockprevious,
               vdaysincircprevissue,
               vwashesthisissue,
               unrelatedloanid,
               vstartrentfrom,
               distributionpointid,
               deliverypointid,
               lockerid,
               garmentdispenserid
          from uniqueitem          u,
               uniqueitemnonpool   n,
               uniqueitemfixedinfo f,
               weareremployment    e,
               wearer              w
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = n.uniqueitem_id
           and n.weareremployment_id = e.weareremployment_id
           and e.wearer_id = w.wearer_id
           and u.uniqueitem_id = f.uniqueitem_id;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || uniqueitemid ||
                                  ' No data found',
                                  1,
                                  'PACK_SORT.GETSENDTRACKINFO',
                                  null,
                                  3,
                                  1);
      end;
    else
      --pool
      begin
       select coalesce((select d.customer_id
                          from department d, distributionpoint dp
                         where dp.distributionpoint_id = u.distributionpoint_id
                           and d.department_id = dp.department_id), (select d.customer_id
                            from department d, distributionpoint dp
                           where dp.distributionpoint_id = u.lastdistributionpoint_link_id
                             and d.department_id = dp.department_id), u.relatedcustomer_id), u.product_id, u.sizedefinition_id, u.finishingmethod_id,
              f.lastissuedate, u.distributionpoint_id, u.lastdistributionpoint_link_id, u.lastinscandate, u.stay_id, u.status_id, u.statuschangedate,
              u.washestotal, u.customerowned, f.qualitygrade_id, f.firstissuedate, f.numberofissues, f.lastonstockdate, f.daysinstockprevious,
              f.daysincircprevissue, u.unrelatedloan_id, u.startrentfrom
         into customerid, productid, sizeid, finishingmethodid, vissuedate, distributionpointid, lastdistribpointid, vlastinscandate, stayid, statusid,
              vstatuschangedate, vwashestotal, vcustomerowned, qualitygradeid, vfirstissuedate, vnumberofissues, vlastonstockdate, vdaysinstockprevious,
              vdaysincircprevissue, unrelatedloanid, vstartrentfrom
          from uniqueitem u, uniqueitemfixedinfo f
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = f.uniqueitem_id;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || uniqueitemid || ' ' || sqlerrm,
                                  1,
                                  'PACK_SORT.GETSENDTRACKINFO',
                                  null,
                                  3,
                                  1);
      end;
    end if;
  end getsendtrackinfo;
  procedure writelogfile(sortsystem           in varchar2,
                         debuglevel           in integer,
                         plantcode            in plant.code%type,
                         idcode               in uniqueitem.primaryid%type,
                         unitcode             in businessunit.code%type,
                         status               in varchar2,
                         finishselection      in varchar2,
                         checkpointselection  in varchar2,
                         repairselection      in varchar2,
                         destination          in varchar2,
                         fold                 in varchar2,
                         stackchangeinfo      in varchar2,
                         routenumber          in integer,
                         stopnumber           in integer,
                         routeday             in day.daynumber%type,
                         depot                in varchar2,
                         sortstring           in varchar2,
                         alternatesortstring  in varchar2,
                         customernumber       in customer.customernumber%type,
                         customername         in customer.name%type,
                         wearernumber         in wearer.wearernumber%type,
                         wearername           in wearer.searchname%type,
                         department           in department.departmentnumber%type,
                         customeremployee#    in wearer.customeremployeenumber%type,
                         gender               in wearer.sex%type,
                         banklocker           in varchar2,
                         garmentdispensercode in garmentdispenser.code%type,
                         deliverypointcode    in deliverypoint.code%type,
                         productcode          in product.code%type,
                         productdescription   in product_desc.description%type,
                         sizecode             in sizedefinition.code%type,
                         productpicturecode   in image.code%type,
                         deliverydaymask      in varchar2,
                         secondaryid          in secondaryuniqueitem.secondaryid%type,
                         flagcode1            in sortaddressperflag.sortaddress%type,
                         flagcode2            in sortaddressperflag.sortaddress%type,
                         flagcode3            in sortaddressperflag.sortaddress%type,
                         flagcode4            in sortaddressperflag.sortaddress%type,
                         flagdescription1     in flag_desc.description%type,
                         flagdescription2     in flag_desc.description%type,
                         flagdescription3     in flag_desc.description%type,
                         flagdescription4     in flag_desc.description%type,
                         infotext             in wearer.remark%type,
                         requiredrepairs      in varchar2,
                         flags                in varchar2,
                         staycode             in varchar2,
                         sortbatchnumber      in integer,
                         spare2               in varchar2) is
  begin
    if debuglevel > 0 then
      pack_sort.write_logging('PlantCode ' || plantcode || ' IDCode ' ||
                              idcode || ' UnitCode ' || unitcode ||
                              ' Status ' || status || case sortsystem when
                              'METRIC' then
                              ' FinishSelection ' || finishselection ||
                              ' FoldProgram ' || fold || ' Depot' || depot ||
                              ' ProductPicture ' || productpicturecode ||
                              ' DeliveryDayMask ' || deliverydaymask ||
                              ' SecondaryID ' || secondaryid ||
                              ' FlagCode1 ' || flagcode1 || ' FlagCode2 ' ||
                              flagcode2 || ' FlagCode3 ' || flagcode3 ||
                              ' FlagCode4 ' || flagcode4 || ' FlagDescr1 ' ||
                              flagdescription1 || ' FlagDescr2 ' ||
                              flagdescription2 || ' FlagDescr3 ' ||
                              flagdescription3 || ' FlagDescr4 ' ||
                              flagdescription4 when 'KANNEGIESSER' then
                              ' FinisherSelection ' || finishselection ||
                              ' Fold ' || fold || ' Flags' || flags when
                              'SORTBATCH' then
                              ' StayCode ' || staycode || ' SortBatch# ' ||
                              sortbatchnumber else null
                              end || ' StackChangeInfo' || stackchangeinfo ||
                              ' Route# ' || routenumber || ' Stop# ' ||
                              stopnumber || ' RouteDay ' || routeday ||
                              ' SortString ' || sortstring ||
                              ' AlternateSortString ' ||
                              alternatesortstring || ' Customer# ' ||
                              customernumber || ' CustomerName ' ||
                              customername || ' Wearer# ' || wearernumber ||
                              ' WearerName ' || wearername || ' info ' ||
                              infotext || ' Department# ' || department ||
                              ' CustomerEmployee# ' || customeremployee# ||
                              '  Gender ' || gender || ' BankLocker ' ||
                              trim(banklocker) || ' GarmentDispenserCode ' ||
                              trim(garmentdispensercode) ||
                              ' DeliveryPointCode ' ||
                              trim(deliverypointcode) || ' Product ' ||
                              productcode || ' ProductDescr ' ||
                              productdescription || ' Size ' || sizecode || case when
                              spare2 <> ' ' then
                              ' OrderInformation ' || spare2 else null
                              end || ' CheckpointSelection ' ||
                              checkpointselection || ' RepairSel. ' ||
                              repairselection || ' Dest. ' || destination ||
                              ' RequiredRepairs ' || requiredrepairs,
                              debuglevel,
                              'PACK_SORT.WRITELOGFILE',
                              null,
                              1,
                              1);
    end if;
  end writelogfile;
  function iscustomer_nonbusinessday(customerid  customer.customer_id%type,
                                     planneddate date) return boolean is
    nonbusinessday date;
  begin
    begin
      select A.NONBUSINESSDAY
        into nonbusinessday
        from NONBUSINESSDAY A, CUSTOMER B, BUSINESSUNIT C
       WHERE B.CUSTOMER_ID = customerid
         AND B.DEFAULTBUSINESSUNIT_ID = C.BUSINESSUNIT_ID
         AND A.PLANT_ID = C.PLANT_ID
         AND nvl(A.CUSTOMER_ID, 0) = 0
         and nvl(A.DEPARTMENT_ID, 0) = 0
         AND A.NONBUSINESSDAY = planneddate
         AND NOT EXISTS (select NONBUSINESSDAY_ID
                from NONBUSINESSDAY
               WHERE CUSTOMER_ID = customerid
                 AND nvl(DEPARTMENT_ID, 0) = 0
                 AND NONBUSINESSDAY = planneddate
                 AND CLOSESTATUS = 3)
      UNION
      select A.NONBUSINESSDAY
        from NONBUSINESSDAY A
       WHERE A.CUSTOMER_ID = customerid
         AND nvl(DEPARTMENT_ID, 0) = 0
         AND A.NONBUSINESSDAY = planneddate
         AND (A.CLOSESTATUS = 1 OR A.CLOSESTATUS = 2);
    exception
      when no_data_found then
        return false;
    end;
    return true;
  end iscustomer_nonbusinessday;
  function iscustomervisitdate(customerid  customer.customer_id%type,
                               planneddate date) return boolean is
    xyear integer;
    xweek integer;
    xday  integer;
    i     integer;
  begin
    i     := 0;
    xday  := getabsdaynumber(planneddate);
    xweek := getisoweek(planneddate);
    xyear := getyearofweek(planneddate);
    for dcursor in (select d.deliveryscheme_id,
                           x.frequency,
                           x.offsetweek,
                           c.day_id
                      from customerdeliveryday    c,
                           customerdeliveryscheme d,
                           deliveryscheme         x
                     where c.customer_id = customerid
                       and c.customer_id = d.customer_id
                       and c.day_id = d.day_id
                       and d.deliveryscheme_id = x.deliveryscheme_id
                       and c.day_id = xday) loop
      begin
        if isweekdeliveryweek(xyear,
                              xweek,
                              dcursor.frequency,
                              dcursor.offsetweek) then
          i := 1;
          exit;
        end if;
      end;
    end loop;
    if i = 1 then
      return true;
    else
      return false;
    end if;
  end iscustomervisitdate;
  --  procedure
  function createroutecontrol(plannedroute    in route.route_id%type,
                              planneddate     in date,
                              plantid_garment in plant.plant_id%type,
                              systemuserid    in systemuser.systemuser_id%type,
                              debuglevel      in varchar2,
                              idcode          in uniqueitem.primaryid%type)
    return number is
    routecontrolid        routecontrol.routecontrol_id%type;
    vpackingday           integer;
    vloadingdock          route.loadingdock%type;
    vpackingdeadline      date;
    driverid              employee.employee_id%type;
    vdrivernumber         employee.employeenumber%type;
    instructions          routestop.routelistinstructions%type;
    truckid               truck.truck_id%type;
    vtruckcode            truck.code%type;
    vroutecontrolcreation varchar2(1);
    lv_stopid             stop.stop_id%type;
    vstatus               integer;
    lvplantid             plant.plant_id%type;
  begin
    if plannedroute is null then
      return null; --do not create routecontrol
    else
      lvplantid := verify_routeid(plantid_garment, plannedroute, ' (for primaryid = ' || idcode || ')');
      if (lvplantid = 0) then
        lvplantid := plantid_garment;
      end if;
      begin
        begin
          select r.routecontrol_id
            into routecontrolid
            from routecontrol r
           where r.route_id = plannedroute
             and trunc(r.drivingdate) = trunc(planneddate);
          return routecontrolid; --return existing route control
        exception
          when no_data_found then
            null; --continue to create it
        end;
        select s.value
          into vroutecontrolcreation
          from systemsetting s
         where s.plant_id = lvplantid
           and s.name = 'ROUTECONTROLCREATION';
        if vroutecontrolcreation < 3 then
          return null; --do not create routecontrol
        end if; --vroutecontrolcreation <> 3
      end;
    end if; --plannedroute is null
    ---- create RouteControl
    select r.packingday_id,
           r.loadingdock,
           r.packingdeadline,
           r.driver_id,
           r.truck_id
      into vpackingday, vloadingdock, vpackingdeadline, driverid, truckid
      from route r
     where r.route_id = plannedroute;
    if driverid is not null then
      select e.employeenumber
        into vdrivernumber
        from employee e
       where e.employee_id = driverid;
    end if;
    if truckid is not null then
      -- LCO, todo 8189
      select t.code
        into vtruckcode
        from truck t
       where t.truck_id = truckid;
    end if;
    select seq_routecontrol.nextval into routecontrolid from dual;
    insert into routecontrol
      (routecontrol_id,
       route_id,
       routelistprinted,
       soilticketsprinted,
       soilcountstatus,
       settlementstatus,
       packingstatus,
       originaldrivingdate,
       drivingdate,
       packingday_id,
       timestamp,
       systemuser_id,
       overageamount,
       voucheramount,
       totalcashcollected,
       totalcoddelayed,
       totalcodpaythisamnt,
       totalcodundelivered,
       totalcodplusadj,
       totalcodminusadj,
       totalcodprebilled,
       totalchargecollections,
       totalchargepaythisamnt,
       totalchargeundelivered,
       totalchargeplusadj,
       totalchargeminusadj,
       totalchargeprebilled,
       returntime,
       returndate,
       starttime,
       loadingdock,
       packingdeadline,
       truckcode,
       drivernumber,
       plant_id,
       invoicesgenerated,
       arbalance_id,
       pocketpcstatus,
       startmileage,
       endmileage,
       straightevenreturnstatus,
       routesettlementprinted,
       activestockcompleted,
       bulkputuproutecompleted,
       safetyremarks)
    values
      (routecontrolid,
       plannedroute,
       'N',
       'N',
       1,
       1,
       1,
       trunc(planneddate),
       trunc(planneddate),
       vpackingday,
       sysdate,
       systemuserid,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       0,
       null,
       null,
       null,
       vloadingdock,
       vpackingdeadline,
       vtruckcode,
       vdrivernumber,
       lvplantid,
       1,
       null,
       0,
       0,
       0,
       0,
       'N',
       'N',
       'N',
       null);
    if debuglevel > 0 then
      pack_sort.write_logging(' insert routecontrol for route ' ||
                              plannedroute,
                              debuglevel,
                              'PACK_SORT.ROUTECONTROLCREATION',
                              lvplantid,
                              1,
                              1);
    end if;
    --insert stops for routecontrol
    for stopcursor in (select rs.routestop_id,
                              rs.stopnumber,
                              rs.customer_id,
                              rs.deliverypoint_id,
                              rs.routelistinstructions,
                              rs.instructionsstartdate,
                              rs.instructionsenddate,
                              rs.contactperson_id,
                              rs.stoptype,
                              rs.chargedeliveryfee
                         from routestop rs
                        where rs.route_id = plannedroute
                          and rs.dateactive <= planneddate
                          and rs.dateinactive >= planneddate
                          and rs.stoptype <> 4 -- not incidental
                       ) loop
      begin
        --check for customer active
        /*check for customer active and for stop status - TD 25261*/
        vstatus := pack_sort.getstopstatus(stopcursor.customer_id,
                                           trunc(planneddate));
       if not pack_sort.iscustomer_nonbusinessday(stopcursor.customer_id, planneddate) then
        if vstatus >= 0 and --pack_sort.iscustomeractive(stopcursor.customer_id, trunc(planneddate)) and
           pack_sort.iscustomervisitdate(stopcursor.customer_id,
                                         trunc(planneddate)) then
          if (trunc(planneddate) >= stopcursor.instructionsstartdate and
             trunc(planneddate) <= stopcursor.instructionsenddate) then
            instructions := stopcursor.routelistinstructions;
          else
            instructions := null;
          end if;
          insert into stop
            (stop_id,
             routecontrol_id,
             routestop_id,
             customer_link_id,
             stopnumber,
             arrivaltime,
             departuretime,
             travelminutes,
             visitminutes,
             routelistinstructions,
             systemuser_id,
             timestamp,
             movedtostop_id,
             status,
             deliverypoint_id,
             contactperson_id,
             stoptype,
             chargedeliveryfee)
          values
            (seq_stop.nextval,
             routecontrolid,
             stopcursor.routestop_id,
             stopcursor.customer_id,
             stopcursor.stopnumber,
             null,
             null,
             0,
             0,
             instructions,
             systemuserid,
             sysdate,
             null,
             vstatus,
             stopcursor.deliverypoint_id,
             stopcursor.contactperson_id,
             stopcursor.stoptype,
             stopcursor.chargedeliveryfee)
          returning stop_id into lv_stopid;
          --link packingnotes to routecontrol
          update packingnote up
             set up.routecontrol_id = routecontrolid,
                 up.stop_id         = lv_stopid,
                 up.stopnumber      = stopcursor.stopnumber,
                 up.timestamp       = sysdate,
                 up.systemuser_id   = systemuserid
           where up.packingnote_id in
                 (select p.packingnote_id
                    from packingnote p, deliverypoint delp
                   where p.route_id = plannedroute
                     and p.deliverydate = planneddate
                     and p.deliverypoint_id =
                         coalesce(stopcursor.deliverypoint_id,
                                  p.deliverypoint_id)
                     and p.routecontrol_id is null
                     and p.deliverypoint_id = delp.deliverypoint_id
                     and delp.customer_id = stopcursor.customer_id);
          --link ClientDeliveryNote to routecontrol
          update clientdeliverynote cdn
             set cdn.routecontrol_id = routecontrolid,
                 cdn.stop_id         = lv_stopid,
                 cdn.stopnumber      = stopcursor.stopnumber,
                 cdn.timestamp       = sysdate,
                 cdn.systemuser_id   = systemuserid
           where cdn.clientdeliverynote_id in
                 (select cdnl.clientdeliverynote_id
                    from clientdeliverynote cdnl, deliverypoint delp
                   where cdnl.route_id = plannedroute
                     and cdnl.deliverydate = planneddate
                     and delp.deliverypoint_id =
                         coalesce(stopcursor.deliverypoint_id,
                                  delp.deliverypoint_id)
                     and cdnl.routecontrol_id is null
                     and delp.deliverypoint_id =
                         (select dp.deliverypoint_id
                            from clientresident    cr,
                                 departmentroom    de,
                                 department        d,
                                 distributionpoint dp
                           where cdnl.customer_link_id =
                                 stopcursor.customer_id
                             and cdnl.client_link_id = cr.client_id
                             and cr.departmentroom_id = de.departmentroom_id
                             and de.department_id = d.department_id
                             and de.distributionpoint_id =
                                 dp.distributionpoint_id
                          union
                          select cp.deliverypoint_id
                            from clientprivateperson cp
                           where cdnl.customer_link_id =
                                 stopcursor.customer_id
                             and cdnl.client_link_id = cp.client_id));
          --link straightevenreturn to routecontrol
          update straightevenreturn us
             set us.stop_id       = lv_stopid,
                 us.timestamp     = sysdate,
                 us.systemuser_id = systemuserid
           where us.straightevenreturn_id in
                 (select s.straightevenreturn_id
                    from straightevenreturn s,
                         status             st,
                         distributionpoint  di,
                         department         d
                   where s.stop_id is null
                     and s.pickupdate <= planneddate
                     and di.distributionpoint_id = s.distributionpoint_id
                     and d.department_id = di.department_id
                     and d.customer_id = stopcursor.customer_id
                     and (di.deliverypoint_id = stopcursor.deliverypoint_id or
                         stopcursor.deliverypoint_id is null)
                     and s.status_id = st.status_id
                     and st.code = '10');
        end if;
       end if;
      end;
    end loop;
    -- insert routecontrol internal bu
    createroutecontrolinternalbu(routecontrolid , systemuserid, lvplantid);
    -- insert RSC ExtraInfo for virtual route (if missing)
    createroutecontrolextrainfo(routecontrolid, systemuserid);
    return(routecontrolid);
  exception
    when others then
      begin
        -- order 20014102
        pack_sort.write_logging('!> error during createroutecontrol for idcode ' ||
                                idcode || ' ' || sqlerrm,
                                debuglevel,
                                'PACK_SORT.ROUTECONTROLCREATION',
                                lvplantid,
                                3,
                                1);
        return null;
      end;
  end createroutecontrol;
  procedure createscanflag(vscanflagid  in scan.scan_id%type,
                           systemuserid in systemuser.systemuser_id%type,
                           debuglevel   in integer,
                           flagcode1    in sortaddressperflag.sortaddress%type,
                           flagcode2    in sortaddressperflag.sortaddress%type,
                           flagcode3    in sortaddressperflag.sortaddress%type,
                           flagcode4    in sortaddressperflag.sortaddress%type,
                           plantid      in plant.plant_id%type) is
    type flagcodes_type is varray(4) of sortaddressperflag.sortaddress%type;
    flagcodes flagcodes_type;
  begin
    flagcodes := flagcodes_type(flagcode1, flagcode2, flagcode3, flagcode4);
    for i in 1 .. 4 loop
      if (flagcodes(i) is not null) then
        begin
          insert into scanflag
            (scan_id, flag_id, flagresponse, systemuser_id, timestamp)
            select vscanflagid, f.flag_id, null, systemuserid, sysdate
              from flag f, sortaddressperflag s
             where f.flagtype = 1
               and f.flag_id = s.flag_id
               and s.sortaddress = flagcodes(i)
               and s.plant_id = plantid;
          if debuglevel > 0 then
            pack_sort.write_logging(' inserted scanflag(s) ' ||
                                    sql%rowcount || ' for scanid ' ||
                                    vscanflagid,
                                    debuglevel,
                                    'PACK_SORT.CREATESCANFLAG',
                                    plantid,
                                    1,
                                    1);
          end if;
        exception
          when dup_val_on_index then
            null; --no problem scan flag is already there
          when no_data_found then
            pack_sort.write_logging(' flagcode ' || flagcodes(i) ||
                                    ' not found',
                                    debuglevel,
                                    'PACK_SORT.CREATESCANFLAG',
                                    plantid,
                                    3,
                                    1);
        end;
      end if;
    end loop;
  end createscanflag;
  procedure add_scanflag(fp_scanid       in scan.scan_id%type,
                         fp_uniqueitemid in uniqueitem.uniqueitem_id%type,
                         fp_dialogcode   in dialogs.code%type,
                         fp_plantid      in plant.plant_id%type,
                         fp_systemuserid in systemuser.systemuser_id%type) is
    lv_counter number;
    lv_remove  flagoptions.remove%type;
  begin
    --get the uniqueitem flags
    for vcursor in (select uif.flag_id, uif.rowid
                      from uniqueitemflag uif
                     where uif.startdate <= sysdate
                       and uif.uniqueitem_id = fp_uniqueitemid) loop
      begin
        --first we check the plantflagoptions, if exist, ok use em.
        select count(1), nvl(max(po.remove), 'N')
          into lv_counter, lv_remove
          from plantflagoptions po
          join dialogs d
            on d.dialog_id = po.dialog_id
         where po.flag_id = vcursor.flag_id
           and po.plant_id = fp_plantid
           and d.garmentscan = 'Y'
           and d.code = fp_dialogcode;
        if nvl(lv_counter, 0) = 0 then
          --not found then check the options on flagoptions level
          select count(1), nvl(max(o.remove), 'N')
            into lv_counter, lv_remove
            from flagoptions o
            join dialogs d
              on d.dialog_id = o.dialog_id
           where o.flag_id = vcursor.flag_id
             and d.garmentscan = 'Y'
             and d.code = fp_dialogcode;
        end if;
        if nvl(lv_counter, 0) >= 1 then
          --add the scan flag
          insert into scanflag
            (scan_id, flag_id, flagresponse, systemuser_id, timestamp)
          values
            (fp_scanid, vcursor.flag_id, null, fp_systemuserid, sysdate);
        end if;
        if nvl(lv_remove, 'N') = 'Y' then
          begin
            --flag must be removed
            delete from uniqueitemflag uf
             where uf.uniqueitem_id = fp_uniqueitemid
               and uf.flag_id = vcursor.flag_id
               and rowid = vcursor.rowid;
          end;
        end if;
      exception
        when no_data_found then
          null; --nothing to be done
        when dup_val_on_index then
          null; --was already there
      end;
    end loop;
  end add_scanflag;
  procedure processcheckpointscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                                  idcode          in uniqueitem.primaryid%type,
                                  pool            in integer,
                                  secondaryid     in secondaryuniqueitem.secondaryid%type,
                                  businessunitid  in businessunit.businessunit_id%type,
                                  uniqueitemid    in uniqueitem.uniqueitem_id%type,
                                  workstationcode in workstation.code%type,
                                  datep           in number,
                                  timep           in varchar2, --number,
                                  systemuserid    in systemuser.systemuser_id%type,
                                  debuglevel      in integer,
                                  accept          out varchar2,
                                  scanbyroute     in varchar2,
                                  plantid_garment in plant.plant_id%type,
                                  flagcode1       in sortaddressperflag.sortaddress%type default null,
                                  flagcode2       in sortaddressperflag.sortaddress%type default null,
                                  flagcode3       in sortaddressperflag.sortaddress%type default null,
                                  flagcode4       in sortaddressperflag.sortaddress%type default null,
                                  fpbatchnumber   in scan.batchnumber%type default null) is
    stayid                    stay.stay_id%type;
    statusid                  status.status_id%type;
    assigned                  status.status_id%type;
    incirc                    status.status_id%type;
    productid                 product.product_id%type;
    sizeid                    sizedefinition.sizedefinition_id%type;
    weareremploymentid        weareremployment.weareremployment_id%type;
    customerid                customer.customer_id%type;
    vissuedate                date;
    finishingmethodid         finishingmethod.finishingmethod_id%type;
    distributionpointid       distributionpoint.distributionpoint_id%type;
    lastdistribpointid        distributionpoint_link.distributionpoint_link_id%type;
    vlastscandate             date;
    vlastscandatetime         timestamp;
    voldlastscandatetime      timestamp;
    vpreviousstay             stay.stay_id%type;
    vwashestotal              integer;
    vyear                     integer;
    vweek                     integer;
    vdayno                    integer;
    vcustomerowned            varchar2(1);
    routeid                   route.route_id%type;
    plannedrouteid            route.route_id%type;
    planneddate               date;
    lastdatein                date;
    plannedroute              route.route_id%type;
    lastinroute               route.route_id%type;
    qualitygradeid            qualitygrade.qualitygrade_id%type;
    deliverypointid           deliverypoint.deliverypoint_id%type;
    vfirstissuedate           date;
    vlastonstockdate          date;
    vtypeofmerch              product.typeofmerchandise%type;
    vnumberofissues           integer;
    routestopin               routestop.routestop_id%type;
    deliverymethod            integer;
    deedeliveryschemeid       deliveryscheme.deliveryscheme_id%type;
    vdaysinstockprevious      integer;
    vdaysincircprevissue      integer;
    plpcid                    productlistpercustomer.productlistpercustomer_id%type;
    vstatuschangedate         date;
    routestopid               routestop.routestop_id%type;
    vstartrentfrom            integer;
    vlastinscandate           date;
    vwashesthisissue          integer;
    unrelatedloanid           unrelatedloan.unrelatedloan_id%type;
    lockerid                  locker.locker_id%type;
    garmentdispenserid        garmentdispenser.garmentdispenser_id%type;
    vmaxwashes                integer;
    plpcfinishingcode         productlistpercustomer.finishingcode_id%type;
    lastoutrouteid            route.route_id%type;
    plpcustomcode             productlistpercustomer.customcode%type;
    plpcustomdescription      productlistpercustomer.customdescription%type;
    pchargewashesonlyforcog   varchar2(1);
    pbillingmethod            integer;
    vscanid                   scanflag.scan_id%type; -- MBA td 9345
    lv_treatmentcheckschemeid treatmentcheckscheme.treatmentcheckscheme_id%type;
    -- Order 20014102
    deliverydetermination integer;
    inroutecontrol_id     number;
    instop_id             number;
    outroutecontrol_id    number;
    stopid                number;
    deparment_id          number := null;
    lv_log                varchar2(1) := 'N';
    lv_lastoutdate        date;
    lv_lastoutstopid      number;
    lv_lastoutrouteid     number;
  begin
    -- Order 20014102
    begin
      select s.value
        into deliverydetermination
        from systemsetting s
       where s.plant_id = plantid_garment
         and s.name = 'DELIVERYDETERMINATION';
    exception
      when others then
        null;
    end;
    accept            := 'Y';
    vlastscandate     := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vlastscandatetime := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vyear             := getyearofweek(vlastscandate); --to_number(to_char(vlastscandate,  ' IYYY '));
    vweek             := getisoweek(vlastscandate); --to_char(vlastscandate,' IW ');
    vdayno            := getabsdaynumber(vlastscandate);
    vscanid           := 0;
    pack_sort.getsendtrackinfo(pool,
                               uniqueitemid,
                               stayid,
                               statusid,
                               productid,
                               sizeid,
                               weareremploymentid,
                               customerid,
                               vissuedate,
                               finishingmethodid,
                               distributionpointid,
                               lastdistribpointid,
                               vwashestotal,
                               vcustomerowned,
                               qualitygradeid,
                               vfirstissuedate,
                               vnumberofissues,
                               vlastonstockdate,
                               vdaysinstockprevious,
                               vstatuschangedate,
                               vstartrentfrom,
                               vdaysincircprevissue,
                               vwashesthisissue,
                               unrelatedloanid,
                               vlastinscandate,
                               deliverypointid,
                               lockerid,
                               garmentdispenserid,
                               accept);
    --stay, status
    vpreviousstay := stayid;
    select stay_id
      into stayid
      from stay
     where stay.staytype = 1
       and stay.staynr = 33; --CheckPointScan
    select status_id
      into assigned
      from status
     where status.statustype = 'UI'
       and status.code = '30'; --assigned
    select status_id
      into incirc
      from status
     where status.statustype = 'UI'
       and status.code = '20'; --in circulation
    if statusid = incirc or statusid = assigned then
      accept := 'Y';
    else
      accept := 'N';
      if debuglevel > 0 then
        pack_sort.write_logging('!> ' ||
                                ' status not in circulation or assigned for IDCode:' ||
                                idcode,
                                debuglevel,
                                'PROCESSCHECKPOINTSCAN',
                                plantid_garment,
                                1,
                                1);
      end if;
    end if;
    if accept = 'Y' then
      begin
        begin
          select u.staychangedate
            into voldlastscandatetime
            from uniqueitem u
           where u.uniqueitem_id = uniqueitemid;

          if voldlastscandatetime < vlastscandatetime then
            update uniqueitem u
               set u.lastscandate   = vlastscandatetime,
                   u.prevstay_id    = vpreviousstay,
                   u.stay_id        = stayid,
                   u.staychangedate = vlastscandatetime,
                   u.systemuser_id  = systemuserid,
                   u.timestamp      = sysdate
             where u.uniqueitem_id = uniqueitemid;
          end if;

          if debuglevel > 0 then
            pack_sort.write_logging(' update uniqueitem ' || uniqueitemid ||
                                    ' for IDCode:' || idcode,
                                    debuglevel,
                                    'PROCESSCHECKPOINTSCAN',
                                    plantid_garment,
                                    1,
                                    1);
          end if;
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSCHECKPOINTSCAN',
                                    plantid_garment,
                                    3,
                                    1);
        end;
        --scan record
        routeid := -1;
        begin
          select u.lastoutroute_id,
                 u.plannedoutroute_id,
                 u.plannedoutdate,
                 u.lastoutdate,
                 u.lastoutroute_id,
                 u.lastoutstop_id
            into lastoutrouteid,
                 plannedrouteid,
                 planneddate,
                 lv_lastoutdate,
                 lv_lastoutrouteid,
                 lv_lastoutstopid
            from uniqueitemroute u
           where u.uniqueitem_id = uniqueitemid;
        exception
          when no_data_found then
            routeid        := null;
            plannedrouteid := null;
            lastoutrouteid := null;
        end;
        ---order563
        begin
          if scanbyroute = 'Y' then
            begin
              ------------
              pack_sort.findplpcinfo(customerid,
                                     productid,
                                     sizeid,
                                     finishingmethodid,
                                     deliverymethod,
                                     deedeliveryschemeid,
                                     plpcid,
                                     vmaxwashes,
                                     plpcfinishingcode,
                                     plpcustomcode,
                                     plpcustomdescription,
                                     pchargewashesonlyforcog,
                                     pbillingmethod,
                                     lv_treatmentcheckschemeid);
              if plpcid is null then
                if pool = 2 then
                  deliverymethod := 1;
                else
                  deliverymethod := 0;
                end if;
              end if;
              --deliverypoint
              begin
                if deliverypointid is null and pool = 2 then
                  if lockerid is not null then
                    select l.deliverypoint_id
                      into deliverypointid
                      from locker l
                     where l.locker_id = lockerid;
                  elsif garmentdispenserid is not null then
                    select g.deliverypoint_id
                      into deliverypointid
                      from garmentdispenser g
                     where g.garmentdispenser_id = garmentdispenserid;
                  end if;
                end if;
                if pool = 1 then
                  begin
                    select d.deliverypoint_id
                      into deliverypointid
                      from distributionpoint d
                     where d.distributionpoint_id = distributionpointid;
                  exception
                    when no_data_found then
                      null;
                  end;
                end if;
              end;
              ------------
              -----
              if deliverydetermination <> 1 then
                if customerid is not null then
                  select p.typeofmerchandise
                    into vtypeofmerch
                    from product p
                   where p.product_id = productid;
                  pack_sort.getlastinroute_debug(customerid,
                                                 vlastscandate,
                                                 deliverypointid,
                                                 vtypeofmerch,
                                                 plantid_garment,
                                                 lastinroute,
                                                 routestopin,
                                                 lastdatein);
                end if;

                if pool = 1 then
                  plannedroute := null;
                  planneddate  := null;
                elsif pool = 2 then
                  pack_sort.fillplannedoutroute(plantid_garment,
                                                vlastscandate,
                                                vtypeofmerch,
                                                deliverymethod,
                                                deedeliveryschemeid,
                                                plpcid,
                                                customerid,
                                                deliverypointid,
                                                lastinroute,
                                                lastdatein,
                                                routestopin,
                                                routestopid,
                                                plannedroute,
                                                planneddate,
                                                scanbyroute);
                end if;
              end if;
              ------------------------------
              if routeid is null and deliverydetermination <> 1 then
                insert into uniqueitemroute
                  (uniqueitem_id,
                   lastinroute_id,
                   lastoutroute_id,
                   plannedoutroute_id,
                   lastindate,
                   lastoutdate,
                   plannedoutdate,
                   systemuser_id,
                   timestamp)
                values
                  (uniqueitemid,
                   lastinroute,
                   null,
                   plannedroute,
                   lastdatein,
                   null,
                   planneddate,
                   systemuserid,
                   sysdate);
                if debuglevel > 0 then
                  pack_sort.write_logging(' insert uniqueitemroute ' ||
                                          uniqueitemid || ' for IDCode:' ||
                                          idcode,
                                          debuglevel,
                                          'PROCESSCHECKPOINTSCAN',
                                          plantid_garment,
                                          1,
                                          1);
                end if;
              elsif plannedrouteid is null and deliverydetermination <> 1 then
                update uniqueitemroute u
                   set u.lastinroute_id     = lastinroute,
                       u.plannedoutroute_id = plannedroute,
                       u.lastindate         = to_date(lastdatein),
                       u.plannedoutdate     = to_date(planneddate),
                       u.systemuser_id      = systemuserid,
                       u.timestamp          = sysdate
                 where u.uniqueitem_id = uniqueitemid;
                if debuglevel > 0 then
                  pack_sort.write_logging(' update uniqueitemroute ' ||
                                          uniqueitemid || ' for IDCode:' ||
                                          idcode,
                                          debuglevel,
                                          'PROCESSCHECKPOINTSCAN',
                                          plantid_garment,
                                          1,
                                          1);
                end if;
                -- order 20014102
              elsif planneddate is null and deliverydetermination = 1 then
                if (lv_lastoutdate is not null and
                   lv_lastoutdate >= trunc(sysdate)) and
                   (lv_lastoutstopid is not null) and
                   (lv_lastoutrouteid is not null) then
                  select uir.lastindate,
                         uir.lastinroute_id,
                         uir.lastinstop_id,
                         uir.lastoutdate,
                         uir.lastoutroute_id,
                         uir.lastoutstop_id
                    into lastdatein,
                         lastinroute,
                         instop_id,
                         planneddate,
                         plannedroute,
                         stopid
                    from uniqueitemroute uir
                   where uir.uniqueitem_id = uniqueitemid;

                  update uniqueitem ui
                     set ui.planneddeliverydate = planneddate
                   where ui.uniqueitem_id = uniqueitemid;
                else
                  pack_deliverybasics.determinedeldateroutesoil(plantid_garment,
                                                                customerid,
                                                                deliverypointid,
                                                                deparment_id,
                                                                vtypeofmerch,
                                                                vlastscandate,
                                                                plpcid,
                                                                distributionpointid,
                                                                lv_log,
                                                                lastinroute,
                                                                routestopin,
                                                                inroutecontrol_id,
                                                                instop_id,
                                                                lastdatein,
                                                                plannedroute,
                                                                routestopid,
                                                                outroutecontrol_id,
                                                                stopid,
                                                                planneddate);
                end if;

                update uniqueitemroute u
                   set u.lastinroute_id     = lastinroute,
                       u.plannedoutroute_id = plannedroute,
                       u.lastindate         = to_date(lastdatein),
                       u.plannedoutdate     = to_date(planneddate),
                       u.systemuser_id      = systemuserid,
                       u.timestamp          = sysdate,
                       lastinstop_id        = instop_id,
                       plannedoutstop_id    = stopid
                 where u.uniqueitem_id = uniqueitemid;
                if debuglevel > 0 then
                  pack_sort.write_logging(' update uniqueitemroute ' ||
                                          uniqueitemid || ' for IDCode:' ||
                                          idcode,
                                          debuglevel,
                                          'PROCESSCHECKPOINTSCAN',
                                          plantid_garment,
                                          1,
                                          1);
                end if;
              elsif planneddate < trunc(sysdate) and
                    deliverydetermination = 1 then
                pack_deliverybasics.determinedeldaterouteclean(plantid_garment,
                                                               customerid,
                                                               deliverypointid,
                                                               deparment_id,
                                                               vtypeofmerch,
                                                               vlastscandate,
                                                               plpcid,
                                                               distributionpointid,
                                                               lv_log,
                                                               routestopid,
                                                               plannedroute,
                                                               stopid,
                                                               outroutecontrol_id,
                                                               planneddate);
                update uniqueitemroute u
                   set u.plannedoutroute_id = plannedroute,
                       u.plannedoutdate     = to_date(planneddate),
                       u.systemuser_id      = systemuserid,
                       u.timestamp          = sysdate,
                       plannedoutstop_id    = stopid
                 where u.uniqueitem_id = uniqueitemid;
                if debuglevel > 0 then
                  pack_sort.write_logging(' update uniqueitemroute ' ||
                                          uniqueitemid || ' for IDCode:' ||
                                          idcode,
                                          debuglevel,
                                          'PROCESSCHECKPOINTSCAN',
                                          plantid_garment,
                                          1,
                                          1);
                end if;
                -- end order 20014102
              end if;
            end;
          end if; --end scanbyroute='Y'
        end;
        if routeid = -1 then
          routeid := plannedrouteid;
        end if;
        begin
          insert into scan
            (scan_id,
             businessunit_id,
             scantimestamp,
             primaryid,
             customer_link_id,
             weareremployment_link_id,
             distributionpoint_link_id,
             product_link_id,
             sizedefinition_link_id,
             stay_id,
             status_id,
             scanstation,
             issuedate,
             route_id,
             reasoncode_id,
             customerowned,
             year,
             week,
             dayno,
             qualitygrade_id,
             systemuser_id,
             timestamp,
             prevstay_id,
             transactiontype_id,
             dayslate,
             uniqueitem_link_id,
             secondaryid,
             batchnumber)
          values
            (seq_scan.nextval,
             businessunitid,
             vlastscandatetime,
             idcode,
             customerid,
             weareremploymentid,
             distributionpointid,
             productid,
             sizeid,
             stayid,
             statusid,
             workstationcode,
             vissuedate,
             routeid,
             null,
             vcustomerowned,
             vyear,
             vweek,
             vdayno,
             null,
             systemuserid,
             sysdate,
             vpreviousstay,
             transactiontp,
             0,
             uniqueitemid,
             secondaryid,
             fpbatchnumber)
          returning scan_id into vscanid;
          if debuglevel > 0 then
            pack_sort.write_logging(' insert into scan ' || uniqueitemid ||
                                    ' for IDCode:' || idcode,
                                    debuglevel,
                                    'PROCESSCHECKPOINTSCAN',
                                    plantid_garment,
                                    1,
                                    1);
          end if;
          -- MBA td 9345
          --          select seq_scan.currval into vscanflagid from dual;
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSCHECKPOINTSCAN',
                                    plantid_garment,
                                    3,
                                    1);
        end;
        -- MBA td 9345 - insert also scanflag if flag1/2/3/4 is provided
        if (vscanid > 0 and (flagcode1 is not null or flagcode2 is not null or
           flagcode3 is not null or flagcode4 is not null)) then
          createscanflag(vscanid,
                         systemuserid,
                         debuglevel,
                         flagcode1,
                         flagcode2,
                         flagcode3,
                         flagcode4,
                         plantid_garment);
        end if;
        if (vscanid > 0) then
          add_scanflag(vscanid,
                       uniqueitemid,
                       'CheckPointScan',
                       plantid_garment,
                       systemuserid);
        end if;
        -- end td 9345
      end; --for accept='Y'
    end if; --for accept='Y'
  end processcheckpointscan;
  procedure processinscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                          idcode          in uniqueitem.primaryid%type,
                          pool            in integer,
                          secondaryid     in secondaryuniqueitem.secondaryid%type,
                          plantid_garment in plant.plant_id%type,
                          plantid_param   in plant.plant_id%type,
                          businessunitid  in businessunit.businessunit_id%type,
                          uniqueitemid    in uniqueitem.uniqueitem_id%type,
                          workstationcode in workstation.code%type,
                          datep           in number,
                          timep           in varchar2, --number,
                          countwashesat   in varchar2,
                          scanbyroute     in varchar2,
                          systemuserid    in systemuser.systemuser_id%type,
                          debuglevel      in integer,
                          accept          out varchar2,
                          scaninterval    out varchar2,
                          pickuproutedate in date,
                          --502595
                          fpsretransferyn in varchar2 default 'N',
                          flagcode1       in sortaddressperflag.sortaddress%type default null,
                          flagcode2       in sortaddressperflag.sortaddress%type default null,
                          flagcode3       in sortaddressperflag.sortaddress%type default null,
                          flagcode4       in sortaddressperflag.sortaddress%type default null,
                          fpbatchnumber   in scan.batchnumber%type default null) is
    stayid                    stay.stay_id%type;
    statusid                  status.status_id%type;
    assigned                  status.status_id%type;
    incirc                    status.status_id%type;
    productid                 product.product_id%type;
    sizeid                    sizedefinition.sizedefinition_id%type;
    weareremploymentid        weareremployment.weareremployment_id%type;
    customerid                customer.customer_id%type;
    vissuedate                date;
    plpcid                    productlistpercustomer.productlistpercustomer_id%type;
    finishingmethodid         finishingmethod.finishingmethod_id%type;
    deliverymethod            integer;
    planneddate               date;
    plannedroute              route.route_id%type;
    distributionpointid       distributionpoint.distributionpoint_id%type;
    lastdistribpointid        distributionpoint_link.distributionpoint_link_id%type;
    vlastscandate             date;
    vlastscandatetime         timestamp(0); --21-09-2005
    vpreviousstay             stay.stay_id%type;
    vpreviousstatus           status.status_id%type;
    vmaxwashes                integer;
    productmaxwashes          integer;
    vwashestotal              integer;
    vyear                     integer;
    vweek                     integer;
    vdayno                    integer;
    cnt                       integer;
    vcustomerowned            varchar2(1);
    flagid                    flag.flag_id%type;
    qualitygradeid            qualitygrade.qualitygrade_id%type;
    vfirstissuedate           date;
    vnumberofissues           integer;
    vlastonstockdate          date;
    vdaysinstockprevious      integer;
    routestopid               routestop.routestop_id%type;
    lastdatein                date;
    vdeliverydate             date;
    vstatuschangedate         date;
    vstartrentfrom            integer;
    venddatefullrent          date;
    vdaysincircprevissue      integer;
    vwashesthisissue          integer;
    unrelatedloanid           unrelatedloan.unrelatedloan_id%type;
    lastinroute               route.route_id%type;
    routestopin               routestop.routestop_id%type;
    lastdistributionpointlink distributionpoint.distributionpoint_id%type;
    reconsiteinv              varchar2(1);
    prodlistid                productlistperdistribpoint.productlistperdistribpoint_id%type;
    vinscaninterval           integer;
    vlastinscandate           date;
    deliverypointid           deliverypoint.deliverypoint_id%type;
    lockerid                  locker.locker_id%type;
    garmentdispenserid        garmentdispenser.garmentdispenser_id%type;
    vtypeofmerch              product.typeofmerchandise%type;
    vtransactiontype          sortingimportdefinition.transactiontype%type;
    deedeliveryschemeid       deliveryscheme.deliveryscheme_id%type;
    inscandif                 number;
    plpcfinishingcode         productlistpercustomer.finishingcode_id%type;
    plpcustomcode             productlistpercustomer.customcode%type;
    plpcustomdescription      productlistpercustomer.customdescription%type;
    pchargewashesonlyforcog   varchar2(1);
    pbillingmethod            integer;
    vbringincircatinscan      integer;
    --502595
    lvcustomerstayid stay.stay_id%type;
    lvretransferyn   varchar2(1);
    -- td 9545
    wearerinventoryid           wearerinventory.wearerinventory_id%type;
    vqtytobereturneddecreasemax wearerinventory.qtytobereturneddecreasemax%type;
    vscanid                     scan.scan_id%type; -- MBA td 9345
    lv_treatmentcheckschemeid   treatmentcheckscheme.treatmentcheckscheme_id%type;
    lv_use_treatmentcheck       systemsetting.value%type;
    lv_sortingdaysrecalcdeldate systemsetting.value%type;
    currentuniquebundleid       uniqueitem.currentuniquebundle_id%type;
    flaginserted                boolean;
    -- Order 20014102
    deliverydetermination integer;
    inroutecontrol_id     number;
    instop_id             number;
    outroutecontrol_id    number;
    stopid                number;
    department_id         number := null;
    lv_log                varchar2(1) := 'N';
    cntDelivered          number := 0;
    internalbusinessunitid businessunit.businessunit_id%type;

    procedure get_routeinfo_inscan is
    begin
      -- Order 20014102
      if deliverydetermination = 1 then
        pack_deliverybasics.determinedeldateroutesoil(plantid_garment,
                                                      customerid,
                                                      deliverypointid,
                                                      department_id,
                                                      vtypeofmerch,
                                                      vlastscandate,
                                                      plpcid,
                                                      distributionpointid,
                                                      lv_log,
                                                      lastinroute,
                                                      routestopin,
                                                      inroutecontrol_id,
                                                      instop_id,
                                                      lastdatein,
                                                      plannedroute,
                                                      routestopid,
                                                      outroutecontrol_id,
                                                      stopid,
                                                      planneddate);

        vdeliverydate := planneddate;
         if pool = 1 then
          if distributionpointid is not null then
            lastdistributionpointlink := distributionpointid;
            distributionpointid       := null;
          end if;
          plannedroute := null;
          planneddate  := null;
        end if;

      else
        if customerid is not null then
          pack_sort.getlastinroute_debug(customerid,
                                         nvl(pickuproutedate, vlastscandate),
                                         deliverypointid,
                                         vtypeofmerch,
                                         plantid_garment,
                                         lastinroute,
                                         routestopin,
                                         lastdatein);
        end if;
        if pool = 1 then
          if distributionpointid is not null then
            lastdistributionpointlink := distributionpointid;
            distributionpointid       := null;
          end if;
          plannedroute := null;
          planneddate  := null;
        end if;
        if pool = 2 then
          if customerid is not null then
            pack_sort.fillplannedoutroute(plantid_garment,
                                          vlastscandate,
                                          vtypeofmerch,
                                          deliverymethod,
                                          deedeliveryschemeid,
                                          plpcid,
                                          customerid,
                                          deliverypointid,
                                          lastinroute,
                                          lastdatein,
                                          routestopin,
                                          routestopid,
                                          plannedroute,
                                          planneddate,
                                          scanbyroute);
          else
            plannedroute := null;
            planneddate  := null;
          end if;
        end if;
      end if;
    end get_routeinfo_inscan;

  begin
    vtransactiontype  := transactiontp;
    accept            := 'Y';
    vlastscandate     := to_date(to_char(datep), 'YYYYMMDD'); --21-09-2005
    vlastscandatetime := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS'); --21-09-2005
    vyear             := getyearofweek(vlastscandate); --to_number(to_char(vlastscandate, 'IYYY'));
    vweek             := getisoweek(vlastscandate); --to_char(vlastscandate, 'IW');
    vdayno            := getabsdaynumber(vlastscandate);
    --502346 fill pickuproutedate in case its NULL
    pack_sort.getsendtrackinfo(pool,
                               uniqueitemid,
                               stayid,
                               statusid,
                               productid,
                               sizeid,
                               weareremploymentid,
                               customerid,
                               vissuedate,
                               finishingmethodid,
                               distributionpointid,
                               lastdistribpointid,
                               vwashestotal,
                               vcustomerowned,
                               qualitygradeid,
                               vfirstissuedate,
                               vnumberofissues,
                               vlastonstockdate,
                               vdaysinstockprevious,
                               vstatuschangedate,
                               vstartrentfrom,
                               vdaysincircprevissue,
                               vwashesthisissue,
                               unrelatedloanid,
                               vlastinscandate,
                               deliverypointid,
                               lockerid,
                               garmentdispenserid,
                               accept);
    begin
      -- INSCANALLOWHOURINTERVAL
      select s.value
        into vinscaninterval
        from systemsetting s
       where s.name = 'INSCANALLOWHOURINTERVAL'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        vinscaninterval := 0;
    end;
    begin
      -- USETREATMENTCHECK
      select s.value
        into lv_use_treatmentcheck
        from systemsetting s
       where s.name = 'USETREATMENTCHECK'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        lv_use_treatmentcheck := '0';
    end;
    -- Order 20014102
    begin
      select s.value
        into deliverydetermination
        from systemsetting s
       where s.plant_id = plantid_garment
         and s.name = 'DELIVERYDETERMINATION';
    exception
      when others then
        null;
    end;
    -- Order 20014732
    select nvl(max(s.value), 0)
      into lv_sortingdaysrecalcdeldate
      from systemsetting s
     where s.plant_id = plantid_garment
       and s.name = 'SORTINGDAYSRECALCDELDATE';
    --stay, status
    vpreviousstay   := stayid;
    vpreviousstatus := statusid;
    select stay_id
      into stayid
      from stay
     where stay.staytype = 1
       and stay.staynr = 30; --inscan/soil received
    select status_id
      into assigned
      from status
     where status.statustype = 'UI'
       and status.code = '30'; --assigned
    select status_id
      into incirc
      from status
     where status.statustype = 'UI'
       and status.code = '20'; --in circulation
    -- Order 20014732
    scaninterval := 'Y';
    if lv_sortingdaysrecalcdeldate = -1 then
      begin
        /*
        field 'plannedoutdate' in table 'uniqueitemroute'
        and field 'planneddeliverydate ' in table 'uniqueitem'
        is filled and the value is not in the past
        then: do not do any processing
        else: it shall work as before.
        */
        select max(u.planneddeliverydate),
               nvl(max(ur.plannedoutdate), vlastscandate - 1)
          into vdeliverydate, planneddate
          from uniqueitem u
          left outer join uniqueitemroute ur
            on ur.uniqueitem_id = u.uniqueitem_id
         where ur.uniqueitem_id = uniqueitemid;
        if vdeliverydate > vlastscandate and planneddate > vlastscandate then
          begin
            --do nothing, so skip doing anythings setting this to N
            scaninterval := 'N';
          end;
        end if;
      end;
    elsif lv_sortingdaysrecalcdeldate > 0 then
      begin
        if vpreviousstay = stayid and vlastscandate > vlastinscandate and
           vlastscandate - vlastinscandate < lv_sortingdaysrecalcdeldate then
          begin
            --only now do something special, item was scanned in before
            select nvl(max(ur.plannedoutdate), vlastscandate - 1)
              into planneddate
              from uniqueitemroute ur
             where ur.uniqueitem_id = uniqueitemid;
            --do nothing, so skip doing anythings setting this to N
            scaninterval := 'N';
            if planneddate < vlastscandate and pool = 2 then
              begin
                --only redetermine the planned out date/route
                pack_sort.findplpcinfo(customerid,
                                       productid,
                                       sizeid,
                                       finishingmethodid,
                                       deliverymethod,
                                       deedeliveryschemeid,
                                       plpcid,
                                       vmaxwashes,
                                       plpcfinishingcode,
                                       plpcustomcode,
                                       plpcustomdescription,
                                       pchargewashesonlyforcog,
                                       pbillingmethod,
                                       lv_treatmentcheckschemeid);
                if customerid is not null then
                  --deliverypoint
                  if deliverypointid is null then
                    if lockerid is not null then
                      select l.deliverypoint_id
                        into deliverypointid
                        from locker l
                       where l.locker_id = lockerid;
                    elsif garmentdispenserid is not null then
                      select g.deliverypoint_id
                        into deliverypointid
                        from garmentdispenser g
                       where g.garmentdispenser_id = garmentdispenserid;
                    end if;
                  end if;
                  --get product ino
                  select p.typeofmerchandise, p.maxwashes
                    into vtypeofmerch, productmaxwashes
                    from product p
                   where p.product_id = productid;
                  --get_routeinfo_inscan
                  get_routeinfo_inscan;
                  --update uniqueitemroute
                  update uniqueitemroute u
                     set u.plannedoutroute_id = plannedroute,
                         u.plannedoutdate     = to_date(planneddate),
                         u.systemuser_id      = systemuserid,
                         u.timestamp          = sysdate,
                         plannedoutstop_id    = stopid
                   where u.uniqueitem_id = uniqueitemid;
                  update uniqueitem u
                     set u.planneddeliverydate = to_date(planneddate),
                         u.systemuser_id       = systemuserid,
                         u.timestamp           = sysdate
                   where u.uniqueitem_id = uniqueitemid;
                end if;
              end;
            end if;
          end;
        end if;
      end;
    end if;
    --502595 get customer stayid
    select st.stay_id
      into lvcustomerstayid
      from stay st
     where st.staytype = 1
       and st.staynr = 20;
    -- HVH bug fix 1-jun-2009
    if nvl(fpsretransferyn, 'N') = 'N' then
      --this covers also value null
      --End change HVH 1-jun-2009
      lvretransferyn := 'N';
    else
      if vpreviousstay = lvcustomerstayid then
        lvretransferyn := 'N';
      else
        lvretransferyn := 'Y';
      end if;
    end if;
    --end 502595
    inscandif := vinscaninterval -
                 to_number(to_date(to_char(vlastscandatetime,
                                           'YYYYMMDDHH24'),
                                   'YYYYMMDDHH24') -
                           to_date(to_char(vlastinscandate, 'YYYYMMDDHH24'),
                                   'YYYYMMDDHH24')) * 24;
    if scaninterval = 'Y' then
      if accept = 'Y' and vlastinscandate is not null and
         vpreviousstay = stayid and vinscaninterval > 0 and
         inscandif > 0 and lvretransferyn = 'N' then
        --21-09-2005
        scaninterval := 'N';
        pack_sort.write_logging('! > idcode ' || idcode ||
                                ' was scanned less then ' ||
                                vinscaninterval || ' before',
                                debuglevel,
                                'PROCESSINSCAN',
                                plantid_param,
                                3,
                                1);
      else
        scaninterval := 'Y';
      end if;
    end if;
    if scaninterval = 'Y' then
      --for scaninterval
      --if status is not incirc or assigned then doesn't scan
      if statusid not in (assigned, incirc) then
        accept := 'N';
        pack_sort.write_logging('!>' || idcode ||
                                ' not in circulation or assigned ',
                                debuglevel,
                                'PROCESSINSCAN',
                                plantid_param,
                                3,
                                1);
      end if;
      --put flags and update wearerinventory
      if accept = 'Y' then
        begin
          --plpc
          pack_sort.findplpcinfo(customerid,
                                 productid,
                                 sizeid,
                                 finishingmethodid,
                                 deliverymethod,
                                 deedeliveryschemeid,
                                 plpcid,
                                 vmaxwashes,
                                 plpcfinishingcode,
                                 plpcustomcode,
                                 plpcustomdescription,
                                 pchargewashesonlyforcog,
                                 pbillingmethod,
                                 lv_treatmentcheckschemeid);
          if plpcid is null then
            if pool = 2 then
              deliverymethod := 1;
            else
              deliverymethod := 0;
            end if;
          end if;
          -- vmaxwashes:=0;--should be commented for 7.26
          --deliverypoint
          begin
            if deliverypointid is null and pool = 2 then
              if lockerid is not null then
                select l.deliverypoint_id
                  into deliverypointid
                  from locker l
                 where l.locker_id = lockerid;
              elsif garmentdispenserid is not null then
                select g.deliverypoint_id
                  into deliverypointid
                  from garmentdispenser g
                 where g.garmentdispenser_id = garmentdispenserid;
              end if;
            end if;
            if pool = 1 then
              begin
                select d.deliverypoint_id
                  into deliverypointid
                  from distributionpoint d
                 where d.distributionpoint_id = distributionpointid;
              exception
                when no_data_found then
                  null;
              end;
            end if;
          end;
          --502595
          select p.typeofmerchandise, p.maxwashes
            into vtypeofmerch, productmaxwashes
            from product p
           where p.product_id = productid;
          -- get last in route
          select count(u.uniqueitem_id)
            into cnt
            from uniqueitemroute u
           where u.uniqueitem_id = uniqueitemid;
          --get_routeinfo_inscan
          get_routeinfo_inscan;
          --countwashes
          if countwashesat = 'I' or
             (countwashesat = 'O' and to_number(vinscaninterval) > 0 and
             vpreviousstay = stayid) then
            begin
              vwashestotal := vwashestotal + 1;
              if pool = 2 then
                vwashesthisissue := vwashesthisissue + 1;
              end if;
            end;
          end if;
          --502595
          if lvretransferyn = 'N' then
            begin
              --assigned
              -- 20011868.50
              -- get value of system setting BRINGINCIRCATINSCAN
              begin
                select s.value
                  into vbringincircatinscan
                  from systemsetting s
                 where s.name = 'BRINGINCIRCATINSCAN'
                   and s.plant_id = plantid_param;
              exception
                when no_data_found then
                  vbringincircatinscan := 0;
              end;
              if statusid = assigned and vfirstissuedate is null and vbringincircatinscan = 1 then
                select count(1)
                into cntdelivered
                from deliveryscan ds join uniqueitem ui  on ds.uniqueitem_link_id = ui.uniqueitem_id
                where ds.packingnote_id is not null
                and ui.uniqueitem_id = uniqueitemid
                and ds.weareremployment_link_id = weareremployment_link_id
                and ui.startRentFrom = 3;
              end if;
              if statusid = assigned and ( vbringincircatinscan = 0 or cntdelivered > 0 )then
                begin
                  statusid          := incirc;
                  vstatuschangedate := vlastscandatetime; --21-09-2005
                  vstartrentfrom    := 1;
                  vtransactiontype  := 24;
                  --scan record
                  begin
                    insert into scan
                      (scan_id,
                       businessunit_id,
                       scantimestamp,
                       primaryid,
                       customer_link_id,
                       weareremployment_link_id,
                       distributionpoint_link_id,
                       product_link_id,
                       sizedefinition_link_id,
                       stay_id,
                       status_id,
                       scanstation,
                       issuedate,
                       route_id,
                       reasoncode_id,
                       customerowned,
                       year,
                       week,
                       dayno,
                       qualitygrade_id,
                       systemuser_id,
                       timestamp,
                       prevstay_id,
                       transactiontype_id,
                       dayslate,
                       uniqueitem_link_id,
                       secondaryid,
                       batchnumber)
                    values
                      (seq_scan.nextval,
                       businessunitid,
                       vlastscandatetime - 0.00001,
                       --21-09-2005
                       idcode,
                       customerid,
                       weareremploymentid,
                       distributionpointid,
                       productid,
                       sizeid,
                       stayid,
                       statusid,
                       workstationcode,
                       vissuedate,
                       lastinroute,
                       null,
                       vcustomerowned,
                       vyear,
                       vweek,
                       vdayno,
                       qualitygradeid,
                       systemuserid,
                       sysdate,
                       vpreviousstay,
                       vtransactiontype,
                       0,
                       uniqueitemid,
                       secondaryid,
                       fpbatchnumber)
                    returning scan_id into vscanid;
                    if debuglevel > 0 then
                      pack_sort.write_logging(' insert scan for assigned ' ||
                                              idcode,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              1,
                                              1);
                    end if;
                    --todo3602
                    if vmaxwashes = 0 then
                      vmaxwashes := productmaxwashes;
                    end if;
                    if lv_use_treatmentcheck = '0' then
                      if vmaxwashes != 0 and vmaxwashes <= vwashestotal then
                        begin
                          select flag_id
                            into flagid
                            from automaticflag a
                           where a.automaticflag_id = 1;
                          flaginserted := pack_sort.create_uniqueitemflag('PACK_SORT.PROCESSINSCAN',
                                                                          debuglevel,
                                                                          systemuserid,
                                                                          uniqueitemid,
                                                                          flagid,
                                                                          vlastscandate,
                                                                          vscanid,
                                                                          null,
                                                                          null,
                                                                          plantid_param);
                        end;
                      end if;
                    else
                      add_treatmentcheck_flags(debuglevel,
                                               systemuserid,
                                               uniqueitemid,
                                               vlastscandate,
                                               vscanid,
                                               null,
                                               lv_treatmentcheckschemeid,
                                               vwashestotal,
                                               plantid_param,
                                               productid,
                                               plpcid);
                    end if;
                  exception
                    when others then
                      accept := 'N';
                      pack_sort.write_logging('!> ' || idcode || ' ' ||
                                              sqlerrm,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              3,
                                              1);
                  end;
                  --update uniqueitemfixedinfo for firstissuedate
                  if vfirstissuedate is null then
                    vfirstissuedate := vlastscandate;
                  end if;
                  if vlastonstockdate is not null then
                    vdaysinstockprevious := vdaysinstockprevious +
                                            (vlastscandate -
                                            vlastonstockdate);
                  end if;
                  venddatefullrent := getenddatefullrent(vlastscandate,
                                                         customerid,
                                                         productid,
                                                         sizeid,
                                                         finishingmethodid,
                                                         vdaysincircprevissue);
                  if venddatefullrent is null then
                    venddatefullrent := getenddatefullrent(vlastscandate,
                                                           customerid,
                                                           productid,
                                                           gv_specialsizeid,
                                                           finishingmethodid,
                                                           vdaysincircprevissue);
                  end if;
                  begin
                    update uniqueitemfixedinfo u
                       set u.firstissuedate      = vfirstissuedate,
                           u.lastissuedate       = vlastscandate,
                           u.numberofissues      = vnumberofissues + 1,
                           u.daysinstockprevious = vdaysinstockprevious,
                           u.enddatefullrent     = venddatefullrent,
                           u.systemuser_id       = systemuserid,
                           u.timestamp           = sysdate
                     where u.uniqueitem_id = uniqueitemid;
                    if debuglevel > 0 then
                      pack_sort.write_logging(' update uniqueitemfixedinfo ' ||
                                              uniqueitemid,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              1,
                                              1);
                    end if;
                  exception
                    when others then
                      accept := 'N';
                      pack_sort.write_logging('!> ' || idcode || ' ' ||
                                              sqlerrm,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              3,
                                              1);
                  end;
                  begin
                    update issuehistory
                       set incircdate    = vlastscandate,
                           incircyear    = vyear,
                           incircweek    = vweek,
                           incircday     = vdayno,
                           systemuser_id = systemuserid,
                           timestamp     = sysdate
                     where uniqueitem_link_id = uniqueitemid
                       and incircdate is null;
                    if debuglevel > 0 then
                      pack_sort.write_logging(' update issuehistory ' ||
                                              uniqueitemid,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              1,
                                              1);
                    end if;
                  exception
                    when others then
                      accept := 'N';
                      pack_sort.write_logging('!> ' || idcode || ' ' ||
                                              sqlerrm,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              3,
                                              1);
                  end;
                end;
              end if; --assigned
              -- unrelated loan
              if unrelatedloanid is not null then
                begin
                  update unrelatedloan u
                     set u.returnedqty   = u.returnedqty + 1,
                         u.returndate    = vlastscandate,
                         u.systemuser_id = systemuserid,
                         u.timestamp     = sysdate
                   where u.unrelatedloan_id = unrelatedloanid;
                  if debuglevel > 0 then
                    pack_sort.write_logging('ID code ' || idcode ||
                                            ' update unrelatedloan ' ||
                                            unrelatedloanid,
                                            debuglevel,
                                            'PROCESSINSCAN',
                                            plantid_param,
                                            1,
                                            1);
                  end if;
                  unrelatedloanid := null;
                exception
                  when others then
                    accept := 'N';
                    pack_sort.write_logging('!> ' || idcode || ' ' ||
                                            sqlerrm,
                                            debuglevel,
                                            'PROCESSINSCAN',
                                            plantid_param,
                                            3,
                                            1);
                end;
              end if;
              --deliveryvariations
              if plpcid is not null and deliverymethod > 0 and pool = 1 and
                /* OLD */ --       distributionpointid is not null then
                /* NEW */
                 lastdistributionpointlink is not null then
                begin
                  select w.businessunit_id
                         into internalbusinessunitid
                  from   workstation w
                  where  w.code = workstationcode
                  and exists (select 1 from customeractivities ca
                       where ca.customer_id = customerid
                       and ca.internalprocessingbu_id is not null);
                exception
                when no_data_found then
                  internalbusinessunitid := businessunitid;
                end ;
                begin
                  if cnt > 0 then
                    --exits uniqueitemroute
                    begin
                      select nvl(u.plannedoutdate, vlastscandate)
                        into vdeliverydate
                        from uniqueitemroute u
                       where u.uniqueitem_id = uniqueitemid;
                    exception
                      when others then
                        vdeliverydate := vlastscandate;
                    end;
                  else
                    vdeliverydate := vlastscandate;
                  end if;
                  insert into deliveryvariations
                    (deliveryvariations_id,
                     product_id,
                     packingnote_id,
                     causenote_id,
                     deliverydate,
                     origin,
                     amount,
                     finishingmethod_id,
                     fixedamount,
                     distributionpoint_id,
                     sizedefinition_id,
                     reference,
                     systemuser_id,
                     processed,
                     timestamp,
                     updaterentqty,
                     adjustmentreason_id,
                     soilcountsubtype,
                     processbusinessunit_id,
                     internalprocessingbu_id)
                  values
                    (seq_deliveryvariations.nextval,
                     productid,
                     null,
                     null,
                     /* OLD */
                     --            to_date(vdeliverydate, 'YYYYMMDD'), 2, 1, finishingmethodid, 'N',
                     /* NEW */
                     trunc(vdeliverydate),
                     1,
                     1,
                     finishingmethodid,
                     'N',
                     /* OLD */
                     --            distributionpointid, sizeid, null, systemuserid, 'N', sysdate, 'N', null);
                     /* NEW */
                     lastdistributionpointlink,
                     sizeid,
                     null,
                     systemuserid,
                     'N',
                     sysdate,
                     'N',
                     null,
                     7,
                     businessunitid,
                     internalbusinessunitid);
                  if debuglevel > 0 then
                    pack_sort.write_logging('ID code ' || idcode ||
                                            ' insert deliveryvariations - product -size - fm ' ||
                                            productid || ' ' || sizeid || ' ' ||
                                            finishingmethodid,
                                            debuglevel,
                                            'PROCESSINSCAN',
                                            plantid_param,
                                            1,
                                            1);
                  end if;
                  --> TD 20481
                  begin
                    select ui.currentuniquebundle_id
                      into currentuniquebundleid
                      from uniqueitem ui
                     where ui.uniqueitem_id = uniqueitemid;
                  end;
                  if currentuniquebundleid is not null then
                    begin
                      update uniqueitem ui
                         set ui.currentuniquebundle_id = null
                       where ui.uniqueitem_id = uniqueitemid;
                    end;
                  end if;
                  --< TD 20481
                exception
                  when dup_val_on_index then
                    begin
                      update deliveryvariations d
                         set d.amount        = d.amount + 1,
                             d.systemuser_id = systemuserid,
                             d.timestamp     = sysdate,
                             -- Order 20014102
                             d.deliverydate = nvl(planneddate,
                                                  trunc(vdeliverydate))
                       where d.product_id = productid
                         and d.sizedefinition_id = sizeid
                         and d.finishingmethod_id = finishingmethodid
                         and d.packingnote_id is null
                         and d.processed = 'N'
                         and d.soilcountsubtype = 7
                         and d.causenote_id is null
                         and d.updaterentqty = 'N'
                            /* OLD */ --          and    d.origin = 2
                            /* NEW */
                         and d.origin = 1
                            /* OLD */ --           and    trunc(d.deliverydate) = trunc(planneddate)
                            /* NEW */
                         and trunc(d.deliverydate) = trunc(vdeliverydate)
                            /* OLD */ --          and    d.distributionpoint_id = distributionpointid;
                            /* NEW */
                         and d.distributionpoint_id =
                             lastdistributionpointlink;
                      if debuglevel > 0 then
                        pack_sort.write_logging('ID code ' || idcode ||
                                                ' update deliveryvariations - product -size - fm ' ||
                                                productid || ' ' || sizeid || ' ' ||
                                                finishingmethodid,
                                                debuglevel,
                                                'PROCESSINSCAN',
                                                plantid_param,
                                                1,
                                                1);
                      end if;
                    end;
                end;
              end if;
            end;
          end if; --if fpRetransferYN = 'N' then
          --uniqueitemroute
          if scanbyroute = 'Y' then

            -- Order 20014102 add lastoutstop_id
            begin
              ---- create RouteControl
              cnt := createroutecontrol(plannedroute,
                                        planneddate,
                                        plantid_garment,
                                        systemuserid,
                                        debuglevel,
                                        idcode);
              if cnt is not null and debuglevel > 0 then
                pack_sort.write_logging('ID code ' || idcode ||
                                        ' create/select routecontrol count ' || cnt,
                                        debuglevel,
                                        'PROCESSINSCAN',
                                        plantid_param,
                                        1,
                                        1);
              end if;
              -- order 20014102
              if (plannedroute > 0 and planneddate is not null and
                 planneddate <> to_date('31-12-2099', 'dd/mm/yyyy') and
                 (stopid is null or stopid = 0) and outroutecontrol_id = 0) then
                begin
                  select s.stop_id
                    into stopid
                    from stop s
                   where s.customer_link_id = customerid
                     and s.routecontrol_id = cnt
                     and s.routestop_id = routestopid;
                exception
                  when no_data_found then
                    null;
                end;
              end if;

              begin
                insert into uniqueitemroute
                  (uniqueitem_id,
                   lastinroute_id,
                   lastoutroute_id,
                   plannedoutroute_id,
                   lastindate,
                   lastoutdate,
                   plannedoutdate,
                   systemuser_id,
                   timestamp,
                   plannedoutstop_id)
                values
                  (uniqueitemid,
                   lastinroute,
                   null,
                   plannedroute,
                   lastdatein,
                   null,
                   planneddate,
                   systemuserid,
                   sysdate,
                   stopid);
                if debuglevel > 0 then
                  pack_sort.write_logging('ID code ' || idcode ||
                                          ' insert uniqueitemroute uniqueitemid ' ||
                                          uniqueitemid,
                                          debuglevel,
                                          'PROCESSINSCAN',
                                          plantid_param,
                                          1,
                                          1);
                end if;
              exception
                when dup_val_on_index then
                  begin
                    update uniqueitemroute u
                       set u.lastinroute_id     = lastinroute,
                           u.plannedoutroute_id = plannedroute,
                           u.lastindate         = to_date(lastdatein),
                           u.plannedoutdate     = to_date(planneddate),
                           u.systemuser_id      = systemuserid,
                           u.timestamp          = sysdate,
                           plannedoutstop_id    = stopid
                     where u.uniqueitem_id = uniqueitemid;
                    if debuglevel > 0 then
                      pack_sort.write_logging('ID code ' || idcode ||
                                              ' update uniqueitemroute uniqueitemid ' ||
                                              uniqueitemid,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              1,
                                              1);
                    end if;
                  end;
              end; -- end order 20014102
            end;
          end if; --scan by route
          begin
            --502595
            if lvretransferyn = 'N' then
              begin
                --21-09-2005 - line was moved in the begining
                update uniqueitem u
                   set u.statuschangedate = vstatuschangedate,
                       u.lastinscandate   = vlastscandatetime,
                       --21-09-2005
                       u.lastscandate = vlastscandatetime,
                       --21-09-2005
                       u.washestotal    = vwashestotal,
                       u.status_id      = statusid,
                       u.prevstatus_id  = vpreviousstatus,
                       u.prevstay_id    = vpreviousstay,
                       u.stay_id        = stayid,
                       u.staychangedate = vlastscandatetime,
                       --21-09-2005
                       u.distributionpoint_id         =
                       (case u.poolitem
                         when 2 then
                          null
                         else
                          distributionpointid
                       end),
                       u.lastdistributionpoint_link_id = lastdistributionpointlink,
                       u.systemuser_id                 = systemuserid,
                       u.timestamp                     = sysdate,
                       u.planneddeliverydate           = planneddate,
                       u.startrentfrom                 = vstartrentfrom,
                       u.unrelatedloan_id              = unrelatedloanid
                 where u.uniqueitem_id = uniqueitemid;
              end;
            else
              begin
                update uniqueitem u
                   set u.systemuser_id       = systemuserid,
                       u.timestamp           = sysdate,
                       u.planneddeliverydate = planneddate
                 where u.uniqueitem_id = uniqueitemid;
              end;
            end if; --if fpRetransferYN <> 'Y' then
            if debuglevel > 0 then
              pack_sort.write_logging('ID code ' || idcode ||
                                      ' update uniqueitem uniqueitemid ' ||
                                      uniqueitemid,
                                      debuglevel,
                                      'PROCESSINSCAN',
                                      plantid_param,
                                      1,
                                      1);
            end if;
          exception
            when others then
              accept := 'N';
              pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                      debuglevel,
                                      'PROCESSINSCAN',
                                      plantid_param,
                                      3,
                                      1);
          end;
          --502595
          if lvretransferyn = 'N' then
            begin
              --update uniqueitem non pool
              if pool = 2 then
                begin
                  update uniqueitemnonpool u
                     set u.washesthisissue = vwashesthisissue,
                         u.systemuser_id   = systemuserid,
                         u.timestamp       = sysdate
                   where u.uniqueitem_id = uniqueitemid;
                  if debuglevel > 0 then
                    pack_sort.write_logging('ID code ' || idcode ||
                                            ' update uniqueitemnonpool uniqueitemid ' ||
                                            uniqueitemid,
                                            debuglevel,
                                            'PROCESSINSCAN',
                                            plantid_param,
                                            1,
                                            1);
                  end if;
                exception
                  when others then
                    accept := 'N';
                    pack_sort.write_logging('!> ' || idcode || ' ' ||
                                            sqlerrm,
                                            debuglevel,
                                            'PROCESSINSCAN',
                                            plantid_param,
                                            3,
                                            1);
                end;
              end if;
              --scan record
              begin
                insert into scan
                  (scan_id,
                   businessunit_id,
                   scantimestamp,
                   primaryid,
                   customer_link_id,
                   weareremployment_link_id,
                   distributionpoint_link_id,
                   product_link_id,
                   sizedefinition_link_id,
                   stay_id,
                   status_id,
                   scanstation,
                   issuedate,
                   route_id,
                   reasoncode_id,
                   customerowned,
                   year,
                   week,
                   dayno,
                   qualitygrade_id,
                   systemuser_id,
                   timestamp,
                   prevstay_id,
                   transactiontype_id,
                   dayslate,
                   uniqueitem_link_id,
                   secondaryid,
                   batchnumber)
                values
                  (seq_scan.nextval,
                   businessunitid,
                   vlastscandatetime,
                   --21-09-2005
                   idcode,
                   customerid,
                   weareremploymentid,
                   distributionpointid,
                   productid,
                   sizeid,
                   stayid,
                   statusid,
                   workstationcode,
                   vissuedate,
                   lastinroute,
                   null,
                   vcustomerowned,
                   vyear,
                   vweek,
                   vdayno,
                   qualitygradeid,
                   systemuserid,
                   sysdate,
                   vpreviousstay,
                   transactiontp,
                   0,
                   uniqueitemid,
                   secondaryid,
                   fpbatchnumber)
                returning scan_id into vscanid;
                if debuglevel > 0 then
                  pack_sort.write_logging('ID code ' || idcode ||
                                          ' insert scan uniqueitemid ' ||
                                          uniqueitemid,
                                          debuglevel,
                                          'PROCESSINSCAN',
                                          plantid_param,
                                          1,
                                          1);
                end if;
              exception
                when others then
                  accept := 'N';
                  pack_sort.write_logging('!> ' || idcode || ' ' ||
                                          sqlerrm,
                                          debuglevel,
                                          'PROCESSINSCAN',
                                          plantid_param,
                                          3,
                                          1);
              end;
              --//decrease on site inventory if applicable
              select s.value
                into reconsiteinv
                from systemsetting s
               where s.plant_id = plantid_garment
                 and s.name = 'RECORDONSITEINVENTORY';
              -- td 9545: decrease of WearerInventory.QtyToBeReturnedDecreaseMax if > 0 and automatic flag 7
              -- (Return to stock because of decrease max inventory) not on the item
              if (pool = 2 and accept = 'Y') then
                begin
                  select a.wearerinventory_id, a.qtytobereturneddecreasemax
                    into wearerinventoryid, vqtytobereturneddecreasemax
                    from wearerinventory a
                   where a.weareremployment_id = weareremploymentid
                     and a.product_id = productid
                     and a.sizedefinition_id = sizeid
                     and a.finishingmethod_id = finishingmethodid
                     for update of a.qtytobereturneddecreasemax;
                exception
                  when no_data_found then
                    wearerinventoryid := null;
                end;
                if wearerinventoryid is not null then
                  if vqtytobereturneddecreasemax > 0 then
                    begin
                      select a.flag_id
                        into flagid
                        from automaticflag a
                       where a.automaticflag_id = 7;
                      flaginserted := pack_sort.create_uniqueitemflag('PACK_SORT.PROCESSINSCAN',
                                                                      debuglevel,
                                                                      systemuserid,
                                                                      uniqueitemid,
                                                                      flagid,
                                                                      sysdate,
                                                                      vscanid,
                                                                      null,
                                                                      null,
                                                                      plantid_param);
                      if flaginserted then
                        update wearerinventory w
                           set w.qtytobereturneddecreasemax = qtytobereturneddecreasemax - 1
                         where w.wearerinventory_id = wearerinventoryid;
                        if debuglevel > 0 then
                          pack_sort.write_logging('ID code ' || idcode ||
                                                  ' update wearerinventory ' ||
                                                  wearerinventoryid,
                                                  debuglevel,
                                                  'PROCESSINSCAN',
                                                  plantid_param,
                                                  1,
                                                  1);
                        end if;
                      end if;
                    exception
                      when others then
                        pack_sort.write_logging('!> ' || idcode || ' ' ||
                                                sqlerrm,
                                                debuglevel,
                                                'PROCESSINSCAN',
                                                plantid_param,
                                                3,
                                                1);
                    end;
                  end if; -- end if qtytobereturneddecrease
                end if; -- end if wearerinventory is not null
              end if; -- end if pool = 2
              -- end todo 9545
            exception
              when no_data_found then
                null;
            end;
            begin
              if reconsiteinv = 'Y' then
                if pool = 1 and lastdistributionpointlink is not null then
                  distributionpointid := lastdistributionpointlink;
                end if;
                if distributionpointid is not null then
                  begin
                    select p.productlistperdistribpoint_id
                      into prodlistid
                      from productlistperdistribpoint p
                     where p.distributionpoint_id = distributionpointid
                       and p.product_id = productid
                       and p.sizedefinition_id = sizeid
                       and p.finishingmethod_id = finishingmethodid;
                  exception
                    when no_data_found then
                      pack_sort.write_logging('!> ' || idcode || ' ' ||
                                              sqlerrm,
                                              debuglevel,
                                              'PROCESSINSCAN',
                                              plantid_param,
                                              2,
                                              1);
                      --should be accept:='N'?????
                  end;
                  begin
                    begin
                      update onsiteinventoryadjustment o
                         set o.quantity      = o.quantity - 1,
                             o.systemuser_id = systemuserid,
                             o.timestamp     = sysdate
                       where o.productlistperdistribpoint_id = prodlistid
                         and trunc(o.inventorydate) = trunc(vlastscandate)
                         and o.origin = 5
                         and o.reference is null;
                      if sql%rowcount = 0 then
                        begin
                          insert into onsiteinventoryadjustment
                            (onsiteinventoryadjustment_id,
                             productlistperdistribpoint_id,
                             origin,
                             inventorydate,
                             quantity,
                             reference,
                             systemuser_id,
                             timestamp)
                          values
                            (seq_onsiteinventoryadjustment.nextval,
                             prodlistid,
                             5,
                             trunc(vlastscandate),
                             -1,
                             null,
                             systemuserid,
                             sysdate);
                          if debuglevel > 0 then
                            pack_sort.write_logging('ID code ' || idcode ||
                                                    ' insert onsiteinventory ' ||
                                                    prodlistid,
                                                    debuglevel,
                                                    'PROCESSINSCAN',
                                                    plantid_param,
                                                    1,
                                                    1);
                          end if;
                        end;
                      else
                        if debuglevel > 0 then
                          pack_sort.write_logging('ID code ' || idcode ||
                                                  ' update onsiteinventory ' ||
                                                  prodlistid,
                                                  debuglevel,
                                                  'PROCESSINSCAN',
                                                  plantid_param,
                                                  1,
                                                  1);
                        end if;
                      end if;
                    exception
                      when others then
                        null; --should be accept:='N'?????
                    end;
                  end;
                end if;
              end if;
            end;
          end if; --if fpRetransferYN = 'N' then
        end; --for accept='Y'
        -- MBA td 9345 - insert also scanflag if flag1/2/3/4 is provided
        if (vscanid > 0 and (flagcode1 is not null or flagcode2 is not null or
           flagcode3 is not null or flagcode4 is not null)) then
          createscanflag(vscanid,
                         systemuserid,
                         debuglevel,
                         flagcode1,
                         flagcode2,
                         flagcode3,
                         flagcode4,
                         plantid_param);
        end if;
        if (vscanid > 0) then
          add_scanflag(vscanid,
                       uniqueitemid,
                       'InScan',
                       plantid_garment,
                       systemuserid);
        end if;
        -- end td 9345
      end if; --for accept='Y'
    end if; ---If scaninterval = 'Y' then
  end processinscan;
  --create or replace
  function getinternalbusinessunit(customerid               customer.customer_id%type,
                                   productid                product.product_id%type,
                                   processingbusinessunitid businessunit.businessunit_id%type)
    return number is
    internalbusinessunitid businessunit.businessunit_id%type;
  begin
    begin
      internalbusinessunitid := null;
      if (processingbusinessunitid is not null and
         processingbusinessunitid > 0) then
        for vcursor in (select ca.internalprocessingbu_id
                          from product            p,
                               productgroup       pg,
                               customeractivities ca
                         where p.productgroup_id = pg.productgroup_id
                           and pg.activity_id = ca.activity_id
                           and ca.customer_id = customerid
                           and p.product_id = productid
                           and ca.processbusinessunit_id =
                               processingbusinessunitid) loop
          begin
            internalbusinessunitid := vcursor.internalprocessingbu_id;
            exit when internalbusinessunitid is not null and internalbusinessunitid > 0;
          end;
        end loop;
      else
        for vcursor in (select ca.internalprocessingbu_id
                          from product            p,
                               productgroup       pg,
                               customeractivities ca
                         where p.productgroup_id = pg.productgroup_id
                           and pg.activity_id = ca.activity_id
                           and ca.customer_id = customerid
                           and p.product_id = productid) loop
          begin
            internalbusinessunitid := vcursor.internalprocessingbu_id;
            exit when internalbusinessunitid is not null and internalbusinessunitid > 0;
          end;
        end loop;
      end if;
    exception
      when no_data_found then
        internalbusinessunitid := null;
    end;
    return internalbusinessunitid;
  end getinternalbusinessunit;
  procedure processoutscan(transactiontp in sortingimportdefinition.transactiontype%type,
                           idcode        in uniqueitem.primaryid%type,
                           --pool              in   integer,
                           secondaryid     in secondaryuniqueitem.secondaryid%type,
                           plantid_garment in plant.plant_id%type,
                           plantid_param   in plant.plant_id%type,
                           businessunitid  in businessunit.businessunit_id%type,
                           uniqueitemid    in uniqueitem.uniqueitem_id%type,
                           workstationid   in workstation.workstation_id%type,
                           workstationcode in workstation.code%type,
                           datep           in number,
                           timep           in varchar2, --number,
                           countwashesat   in varchar2,
                           scanbyroute     in varchar2,
                           systemuserid    in systemuser.systemuser_id%type,
                           debuglevel      in integer,
                           accept          out varchar2,
                           scaninterval    out varchar2,
                           packingnoteid   in integer,
                           statusout       out integer,
                           flagcode1       in sortaddressperflag.sortaddress%type default null,
                           flagcode2       in sortaddressperflag.sortaddress%type default null,
                           flagcode3       in sortaddressperflag.sortaddress%type default null,
                           flagcode4       in sortaddressperflag.sortaddress%type default null,
                           m_deliveryscan  in varchar2 default 'Y',
                           fpbatchnumber   in scan.batchnumber%type default null) is
    stayid               stay.stay_id%type;
    vpreviousstay        stay.stay_id%type;
    stayoutscan          stay.stay_id%type;
    statusid             status.status_id%type;
    vpreviousstatus      status.status_id%type;
    assigned             status.status_id%type;
    incirc               status.status_id%type;
    productid            product.product_id%type;
    sizeid               sizedefinition.sizedefinition_id%type;
    finishingmethodid    finishingmethod.finishingmethod_id%type;
    vplanneddeliverydate date;
    vplannedoutdate      date;
    vlastscandate        date;
    vlastindate          date;
    routedate            date;
    vlastscandatetime    timestamp(0);
    vlastoutscandate     date;
    weareremploymentid   weareremployment.weareremployment_id%type;
    customerid           customer.customer_id%type;
    distributionpointid  distributionpoint.distributionpoint_id%type;
    outscaninterv        integer;
    lockerid             locker.locker_id%type;
    garmentdispenserid   garmentdispenser.garmentdispenser_id%type;
    deliverypointid      deliverypoint.deliverypoint_id%type;
    vlastoutroute        route.route_id%type;
    vmaxwashes           integer;
    productmaxwashes     integer;
    vwashestotal         integer;
    vwashesthisissue     integer;
    vyear                integer;
    vweek                integer;
    vdayno               integer;
    vcustomerowned       varchar2(1);
    typeofmerch          product.typeofmerchandise%type;
    plpcid               productlistpercustomer.productlistpercustomer_id%type;
    deliverymethod       productlistpercustomer.delayedevenexchange%type;
    flagid               flag.flag_id%type;
    qualitygradeid       qualitygrade.qualitygrade_id%type;
    vlastissuedate       date;
    routestopid          routestop.routestop_id%type;
    routestopin          routestop.routestop_id%type;
    lastinroute          route.route_id%type;
    routecontrolid       routecontrol.routecontrol_id%type;
    plantdep             plantdepartment.plantdepartment_id%type;
    vdayslate            integer;
    deedeliveryschemeid  deliveryscheme.deliveryscheme_id%type;
    outscandif           number(28);
    plpcfinishingcode    productlistpercustomer.finishingcode_id%type;
    --501857
    productoptimafactor     product.optimafactor%type;
    optimafigure            number(28, 3);
    customercode            databasesettings.code%type;
    minplantdep             varchar2(1);
    countoptimahistory      integer;
    plpcustomcode           productlistpercustomer.customcode%type;
    plpcustomdescription    productlistpercustomer.customdescription%type;
    pchargewashesonlyforcog varchar2(1);
    pbillingmethod          integer;
    minpackingnotelineid    packingnoteline.packingnoteline_id%type;
    chargewashcogchg        varchar2(1);
    --502489
    pnumberwashesspecialtreatment productlistpercustomer.numberwashesspecialtreatment%type;
    lvcountwashesat               systemsetting.value%type;
    --todo8492
    lvplannedoutrouteid       uniqueitemroute.plannedoutroute_id%type;
    lvplannedoutdate          uniqueitemroute.plannedoutdate%type;
    vscanid                   scan.scan_id%type; -- MBA td 9345
    lv_treatmentcheckschemeid treatmentcheckscheme.treatmentcheckscheme_id%type;
    lv_use_treatmentcheck     systemsetting.value%type;
    lv_fromstock            uniqueitem.deliveryfromstock%type;
    lv_reasoncodeid         uniqueitemfixedinfo.reasoncode_id%type;
    lv_chargewashfirstissue customer.chargewashfirstissue%type;
    lv_chargewashing        deliveryscan.chargewashing%type;
    --TD-20013349.20
    internalbusinessunitid businessunit.businessunit_id%type;
    flaginserted           boolean;
    -- Order 20014102
    deliverydetermination    integer;
    outroutecontrol_id       number;
    stopid                   number;
    department_id            number := null;
    lv_log                   varchar2(1) := 'N';
    vplannedoutstop          number;
    lv_poolitem              number;
    lv_pn_statuscode         status.code%type;
    v_QtyWithflagDecreaseMax integer;
    lvcounter                integer := 0;
    lv_dummyforpool          varchar2(1);
    wearerinventoryid        wearerinventory.wearerinventory_id%type;
    lv_outofseasoncode       season.code%type;
    lv_deliverynotenr        number;
  begin
	processfakeinscanforgarments(plantid_garment, businessunitid, idcode, uniqueitemid,  secondaryid, scanbyroute, systemuserid);
    select a.code into customercode from databasesettings a;
    lv_pn_statuscode  := '0';
    statusout         := 0;
    accept            := 'Y';
    vlastscandate     := to_date(to_char(datep), 'YYYYMMDD'); --21-09-2005
    vlastscandatetime := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vyear             := getyearofweek(vlastscandate); --to_number(to_char(vlastscandate, 'IYYY'));
    vweek             := getisoweek(vlastscandate); --to_char(vlastscandate, 'IW');
    vdayno            := getabsdaynumber(vlastscandate);
    begin
      select s.value
        into outscaninterv
        from systemsetting s
       where s.name = 'OUTSCANALLOWHOURINTERVAL'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        outscaninterv := 0;
    end;
    begin
      -- USETREATMENTCHECK
      select s.value
        into lv_use_treatmentcheck
        from systemsetting s
       where s.name = 'USETREATMENTCHECK'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        lv_use_treatmentcheck := '0';
    end;
    --502489
    begin
      select s.value
        into lvcountwashesat
        from systemsetting s
       where s.name = 'COUNTWASHESAT'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        lvcountwashesat := ' ';
    end;
    -- Order 20014102
    begin
      select s.value
        into deliverydetermination
        from systemsetting s
       where s.plant_id = plantid_garment
         and s.name = 'DELIVERYDETERMINATION';
    exception
      when others then
        null;
    end;
    select u.planneddeliverydate,
           u.product_id,
           u.sizedefinition_id,
           u.finishingmethod_id,
           u.stay_id,
           u.status_id,
           u.washestotal,
           u.customerowned,
           u.lastoutscandate,
           f.qualitygrade_id,
           f.lastissuedate,
           n.weareremployment_id,
           n.washesthisissue,
           e.distributionpoint_id,
           w.customer_id,
           e.locker_id,
           e.garmentdispenser_id,
           e.deliverypoint_id,
           --todo8492
           ur.plannedoutroute_id,
           ur.plannedoutdate,
           u.deliveryfromstock,
           f.reasoncode_id,
           u.poolitem,
           nvl(w.dummyforpool, 'N')
      into vplanneddeliverydate,
           productid,
           sizeid,
           finishingmethodid,
           stayid,
           statusid,
           vwashestotal,
           vcustomerowned,
           vlastoutscandate,
           qualitygradeid,
           vlastissuedate,
           weareremploymentid,
           vwashesthisissue,
           distributionpointid,
           customerid,
           lockerid,
           garmentdispenserid,
           deliverypointid,
           --todo8492
           lvplannedoutrouteid,
           lvplannedoutdate,
           lv_fromstock,
           lv_reasoncodeid,
           lv_poolitem,
           lv_dummyforpool
      from uniqueitem u
      left outer join uniqueitemroute ur
        on (ur.uniqueitem_id = u.uniqueitem_id)
      join uniqueitemfixedinfo f
        on (f.uniqueitem_id = u.uniqueitem_id)
      left outer join(uniqueitemnonpool n
      join weareremployment e
        on e.weareremployment_id = n.weareremployment_id
      join wearer w
        on w.wearer_id = e.wearer_id) on (n.uniqueitem_id = u.uniqueitem_id)
     where u.uniqueitem_id = uniqueitemid;
    if lv_fromstock <> 'Y' then
      lv_reasoncodeid := null;
    end if;
    --501875
    if packingnoteid is not null then
      begin
        if debuglevel > 0 then
          pack_sort.write_logging('ID code ' || idcode ||
                                  ' Passed PackingnoteID to ProcessOutscan: ' ||
                                  packingnoteid,
                                  debuglevel,
                                  'PROCESSOUTSCAN',
                                  plantid_param,
                                  1,
                                  1);
        end if;
        select min(p.packingnoteline_id)
          into minpackingnotelineid
          from packingnoteline p
         where p.packingnote_id = packingnoteid
           and p.product_id = productid
           and p.sizedefinition_id = sizeid
           and p.finishingmethod_id = finishingmethodid; --?????????????
        if minpackingnotelineid is null then
          statusout := 4;
          pack_sort.write_logging('ID code ' || idcode ||
                                  ' Not found Packingnoteline for product with PN ID:' ||
                                  packingnoteid,
                                  debuglevel,
                                  'PROCESSOUTSCAN',
                                  plantid_param,
                                  3,
                                  1);
        end if;
      end;
    end if;
    if statusout = 0 then
      --501875
      --stay,status
      vpreviousstatus := statusid;
      vpreviousstay   := stayid;
      select s.status_id
        into assigned
        from status s
       where s.statustype = 'UI'
         and s.code = '30';
      select s.status_id
        into incirc
        from status s
       where s.statustype = 'UI'
         and s.code = '20';
      if statusid not in (assigned, incirc) then
        accept := 'N';
      end if;
      select stay.stay_id
        into stayoutscan
        from stay
       where stay.staytype = 1
         and stay.staynr = 20; --outscan/at customer
      outscandif := outscaninterv -
                    to_number(to_date(to_char(vlastscandatetime,
                                              'YYYYMMDDHH24'),
                                      'YYYYMMDDHH24') -
                              to_date(to_char(vlastoutscandate,
                                              'YYYYMMDDHH24'),
                                      'YYYYMMDDHH24')) * 24;
      if accept = 'Y' and vlastoutscandate is not null and
         stayid = stayoutscan and outscaninterv > 0 and outscandif > 0 then
        --21-09-2005
        scaninterval := 'N';
        pack_sort.write_logging('!> ID code ' || idcode ||
                                ' was scanned less then ' || outscaninterv ||
                                ' before',
                                debuglevel,
                                'PROCESSOUTSCAN',
                                plantid_param,
                                3,
                                1);
      else
        scaninterval := 'Y';
      end if;
      if scaninterval = 'Y' then
        --for scaninterval
        --deliverypoint
        begin
          if deliverypointid is null then
            if lockerid is not null then
              select l.deliverypoint_id
                into deliverypointid
                from locker l
               where l.locker_id = lockerid;
            elsif garmentdispenserid is not null then
              select g.deliverypoint_id
                into deliverypointid
                from garmentdispenser g
               where g.garmentdispenser_id = garmentdispenserid;
            end if;
          end if;
          --exception
          --when no_data_found then
          if deliverypointid is null then
            if packingnoteid is not null then
              select pk.deliverypoint_id,
                     dp.customer_id,
                     pk.distributionpoint_id,
                     st.code
                into deliverypointid,
                     customerid,
                     distributionpointid,
                     lv_pn_statuscode
                from packingnote pk
                join status st
                  on st.status_id = pk.status_id
                join deliverypoint dp
                  on dp.deliverypoint_id = pk.deliverypoint_id
               where pk.packingnote_id = packingnoteid;
            else
              begin
                select d.deliverypoint_id
                  into deliverypointid
                  from distributionpoint d
                 where d.distributionpoint_id = distributionpointid;
              exception
                when no_data_found then
                  begin
                    deliverypointid := null;
                  end;
              end;
            end if;
          end if;
        end;
        --put flags and update wearerinventory
        if accept = 'Y' then
          --plpc
          pack_sort.findplpcinfo(customerid,
                                 productid,
                                 sizeid,
                                 finishingmethodid,
                                 deliverymethod,
                                 deedeliveryschemeid,
                                 plpcid,
                                 vmaxwashes,
                                 plpcfinishingcode,
                                 plpcustomcode,
                                 plpcustomdescription,
                                 pchargewashesonlyforcog,
                                 pbillingmethod,
                                 lv_treatmentcheckschemeid);
          --max washes
          select product.maxwashes,
                 product.typeofmerchandise,
                 product.optimafactor
            into productmaxwashes, typeofmerch, productoptimafactor --501857
            from product
           where product_id = productid;
          if vmaxwashes = 0 or vmaxwashes is null then
            --should be uncommented for 7.26
            vmaxwashes := productmaxwashes;
          end if;
          --todo3602
          if countwashesat = 'O' or
             (countwashesat = 'I' and to_number(outscaninterv) > 0 and
             stayoutscan = stayid) then
            begin
              vwashestotal     := vwashestotal + 1;
              vwashesthisissue := vwashesthisissue + 1;
              --update unique item non pool
              update uniqueitemnonpool u
                 set u.washesthisissue = vwashesthisissue,
                     u.systemuser_id   = systemuserid,
                     u.timestamp       = sysdate
               where u.uniqueitem_id = uniqueitemid;
              if debuglevel > 0 then
                pack_sort.write_logging('ID code ' || idcode ||
                                        ' update uniqueitemnonpool ' ||
                                        uniqueitemid,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        1,
                                        1);
              end if;
            exception
              when others then
                accept := 'N';
                -- if debuglevel>0 then
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        3,
                                        1);
                -- end if;
            end;
          end if; --washes total
          if lv_use_treatmentcheck = '0' then
            begin
              if vmaxwashes = vwashestotal and vmaxwashes != 0 then
                select flag_id
                  into flagid
                  from automaticflag a
                 where a.automaticflag_id = 1;
                if accept = 'Y' then
                  begin
                    flaginserted := pack_sort.create_uniqueitemflag('PACK_SORT.PROCESSOUTSCAN',
                                                                    debuglevel,
                                                                    systemuserid,
                                                                    uniqueitemid,
                                                                    flagid,
                                                                    vlastscandate,
                                                                    null,
                                                                    null,
                                                                    null,
                                                                    plantid_param);
                  end;
                end if;
              end if; --maxwashes
            end;
          end if; --lv_use_treatmentcheck
          --AUTOMATICFLAG_RETURNTOSTOCK_DECREASE_MAX_INV
          begin
            if lv_poolitem = 2 then
            select a.qtytobereturneddecreasemax,
                   (select ss.code --show season when NOT in the season!!
                     from   season ss
                     where  ss.season_id = a.season_id
                     and    not exists (select 1
                             from   seasonweek sw
                             where  sw.season_id = ss.season_id
                             and    sw.weeknumber = getisoweek(vlastscandatetime))
                     and    exists
                      (select 1 from seasonweek sw where sw.season_id = ss.season_id)) outofseasoncode,
                      a.wearerinventory_id
            into   v_qtywithflagdecreasemax, lv_outofseasoncode, wearerinventoryid
            from   wearerinventory a
            join   uniqueitemnonpool un
            on     un.wearerinventory_id = a.wearerinventory_id
            where  un.uniqueitem_id = uniqueitemid;
            select flag_id
            into   flagid
            from   automaticflag a
             where a.automaticflag_id = AUTOMATICFLAG_DECREASE_MAX_INV;
            else
              v_QtyWithflagDecreaseMax := 0;
              flagid := -1;
              lv_outofseasoncode := null;
              wearerinventoryid := null;
            end if;
            if (v_QtyWithflagDecreaseMax > 0) then
              flaginserted := create_uniqueitemflag('PACK_SORT.CREATE_UNIQUEITEMFLAG Insert uniqueitemflag for uniqueitemid ',
                                        debuglevel,
                                        systemuserid,
                                        uniqueitemid,
                                        flagid,
                                        vlastscandate,
                                        vscanid,
                                        to_char(vwashestotal) ||
                                        'Return to stock!');
                       if flaginserted then
                             update wearerinventory w
                             set    w.qtytobereturneddecreasemax = qtytobereturneddecreasemax - 1
                             where  w.wearerinventory_id = wearerinventoryid;
                          if debuglevel > 0 then
                             pack_sort.write_logging('ID code ' || idcode ||
                                                  ' update wearerinventory ' || wearerinventoryid,
                                                  debuglevel, 'PROCESSOUTSCAN', plantid_param, 1, 1);
                          end if;
                          if customercode <> 'AMM' then
                             lvcounter := 1;
                          else
                             lvcounter := 0;
                          end if;
                       end if;
            else
              select count(u.flag_id)
                into lvcounter
                from uniqueitemflag u
               where u.uniqueitem_id = uniqueitemid
                 and u.flag_id = flagid;
            end if;
            if (lvcounter > 0) then
              accept := 'N';
              if debuglevel > 0 then
                pack_sort.write_logging(' AUTOMATICFLAG_RETURNTOSTOCK_DECREASE_MAX_INV ' ||
                                        uniqueitemid,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        1,
                                        1);
              end if;
            end if;
          exception
            when others then
              -- ASD-16383 CLO: Missing deliveries, do accept when weird error, but report error
              -- if debuglevel>0 then
              lv_outofseasoncode := null;
              pack_sort.write_logging(' error doing check AUTOMATICFLAG_RETURNTOSTOCK_DECREASE_MAX_INV ' ||
                                      uniqueitemid || ' ' || sqlerrm,
                                      debuglevel,
                                      'PROCESSOUTSCAN',
                                      plantid_param,
                                      1,
                                      1);
              -- end if;
          end;
          --scanbyroute
          if scanbyroute = 'Y' then
            --begin
            begin
              select u.plannedoutdate, u.plannedoutstop_id
                into vplannedoutdate, vplannedoutstop
                from uniqueitemroute u
               where u.uniqueitem_id = uniqueitemid;
            exception
              when no_data_found then
                vplannedoutdate := null;
              when others then
                null;
            end;
            -- Order 20014102
            if deliverydetermination = 1 then
			  vlastscandate :=  coalesce(vplannedoutdate, vlastscandate);
              pack_deliverybasics.determinedeldaterouteclean(plantid_garment,
                                                             customerid,
                                                             deliverypointid,
                                                             department_id,
                                                             typeofmerch,
                                                             vlastscandate,
                                                             plpcid,
                                                             distributionpointid,
                                                             lv_log,
                                                             routestopid,
                                                             vlastoutroute,
                                                             stopid,
                                                             outroutecontrol_id,
                                                             routedate);
            end if;
            --todo8492, added if then else
            if (lvplannedoutdate >= trunc(sysdate) and
               lvplannedoutdate is not null) and
               (lvplannedoutrouteid is not null) and
               (vplannedoutstop is not null) then
              begin
                vlastoutroute := lvplannedoutrouteid;
                routedate     := lvplannedoutdate;
                if routestopid is null then
                  routestopid := 1; --dummy route stop so route record is made
                end if;
                stopid := vplannedoutstop;
              end;
            else
              begin
                if deliverydetermination <> 1 then
                  --start added for order501026
                  pack_sort.getlastinroute_debug(customerid,
                                                 vlastscandate,
                                                 deliverypointid,
                                                 typeofmerch,
                                                 plantid_garment,
                                                 lastinroute,
                                                 routestopin,
                                                 vlastindate);
                  pack_sort.fillplannedoutroute(plantid_garment,
                                                vlastscandate,
                                                typeofmerch,
                                                deliverymethod,
                                                deedeliveryschemeid,
                                                plpcid,
                                                customerid,
                                                deliverypointid,
                                                lastinroute,
                                                vlastindate,
                                                routestopin,
                                                routestopid,
                                                vlastoutroute,
                                                routedate,
                                                scanbyroute);
                end if;
              end;
            end if;
            if routestopid is not null and lv_outofseasoncode is null then
              --begin
              vlastoutscandate := vlastscandate;
              if accept = 'Y' then
                begin
                  insert into uniqueitemroute --21-09-2005 - put insert before update
                    (uniqueitem_id,
                     lastinroute_id,
                     lastoutroute_id,
                     plannedoutroute_id,
                     lastindate,
                     lastoutdate,
                     plannedoutdate,
                     plannedoutstop_id,
                     systemuser_id,
                     timestamp,
                     lastoutstop_id)
                  values
                    (uniqueitemid,
                     null,
                     vlastoutroute,
                     null,
                     null,
                     routedate,
                     null,
                     null,
                     systemuserid,
                     sysdate,
                     stopid);
                  if debuglevel > 0 then
                    pack_sort.write_logging('ID code ' || idcode ||
                                            ' insert uniqueitemroute ' ||
                                            uniqueitemid,
                                            debuglevel,
                                            'PROCESSOUTSCAN',
                                            plantid_param,
                                            1,
                                            1);
                  end if;
                exception
                  when dup_val_on_index then
                    update uniqueitemroute u --21-09-2005
                       set u.lastoutroute_id = vlastoutroute,
                           u.lastoutdate     = routedate,
                           ---here should be routedate not lastscandate?
                           u.plannedoutroute_id = null,
                           u.plannedoutdate     = null,
                           u.plannedoutstop_id  = null,
                           u.systemuser_id      = systemuserid,
                           u.timestamp          = sysdate,
                           lastoutstop_id       = stopid
                     where u.uniqueitem_id = uniqueitemid;
                    if debuglevel > 0 then
                      pack_sort.write_logging('ID code ' || idcode ||
                                              ' update uniqueitemroute ' ||
                                              uniqueitemid,
                                              debuglevel,
                                              'PROCESSOUTSCAN',
                                              plantid_param,
                                              1,
                                              1);
                    end if;
                  when others then
                    accept := 'N';
                    pack_sort.write_logging('!> ' || idcode || ' ' ||
                                            sqlerrm,
                                            debuglevel,
                                            'PROCESSOUTSCAN',
                                            plantid_param,
                                            3,
                                            1);
                end;
              end if; --accept='Y'
              --routecontrolid
              routecontrolid := createroutecontrol(vlastoutroute,
                                                   routedate,
                                                   plantid_garment,
                                                   systemuserid,
                                                   debuglevel,
                                                   idcode);
              --20014102
              if (vlastoutroute > 0 and routedate is not null and
                 routedate <> to_date('31-12-2099', 'dd/mm/yyyy') and
                 (stopid is null or stopid = 0) and
                 (outroutecontrol_id is null or outroutecontrol_id = 0)) then
                begin
                  select s.stop_id
                    into stopid
                    from stop s
                   where s.customer_link_id = customerid
                     and s.routecontrol_id = routecontrolid
                     and s.routestop_id = routestopid;

                exception
                  when no_data_found then
                    null;
                end;
                begin
                  update uniqueitemroute u
                     set u.lastoutroute_id = vlastoutroute,
                         u.lastoutdate     = routedate,
                         u.lastoutstop_id  = stopid,
                         u.timestamp       = sysdate
                   where u.uniqueitem_id = uniqueitemid;

                  if debuglevel > 0 then
                    pack_sort.write_logging('ID code ' || idcode ||
                                            ' update uniqueitemroute ' ||
                                            uniqueitemid,
                                            debuglevel,
                                            'PROCESSOUTSCAN',
                                            plantid_param,
                                            1,
                                            1);
                  end if;
                end;
              end if; -- end order 20014102
            end if; --routestopid is not null
          end if; --scan by route
          --plantdepartmentid
          begin
            select w.plantdepartment_id
              into plantdep
              from workstation w
             where w.workstation_id = workstationid
               and w.plant_id = plantid_param;
            minplantdep := 'N';
          exception
            when no_data_found then
              select min(x.plantdepartment_id)
                into plantdep
                from plantdepartment x
               where x.plant_id = plantid_param;
              minplantdep := 'Y';
          end;
          --501875
          --delivery scan
          if (accept = 'Y' and nvl(m_deliveryscan, 'Y') <> 'N' and lv_outofseasoncode is null) then
            begin
              internalbusinessunitid := getinternalbusinessunit(customerid,
                                                                productid,
                                                                businessunitid);
              select c.chargewashfirstissue
                into lv_chargewashfirstissue
                from customer c
               where c.customer_id = customerid;
              if ((lv_fromstock = 'Y' and lv_chargewashfirstissue = 'N') or
                 (m_deliveryscan = 'F' and lv_dummyforpool = 'Y')) then
                lv_chargewashing := 'N';
              else
                lv_chargewashing := 'Y';
              end if;
              insert into deliveryscan
                (businessunit_id,
                 uniqueitem_link_id,
                 scantimestamp,
                 customer_link_id,
                 weareremployment_link_id,
                 distributionpoint_link_id,
                 deliverypoint_link_id,
                 product_link_id,
                 sizedefinition_link_id,
                 finishingmethod_id,
                 routecontrol_id,
                 packingnote_id,
                 fromstock,
                 previousstay_id,
                 systemuser_id,
                 timestamp,
                 reasoncode_id,
                 plantdepartment_id,
                 chargewashing,
                 locker_id,
                 internalprocessingbu_id,
                 scanstation,
                 planneddeliverydate,
                 pool_packingnote_id)
              values
                (businessunitid,
                 uniqueitemid,
                 vlastscandatetime,
                 customerid,
                 weareremploymentid,
                 distributionpointid,
                 deliverypointid,
                 productid,
                 sizeid,
                 finishingmethodid,
                 routecontrolid,
                 case when (lv_pn_statuscode in ('30', '40')) then null else
                 packingnoteid end,
                 lv_fromstock,
                 vpreviousstay,
                 systemuserid,
                 sysdate,
                 lv_reasoncodeid,
                 plantdep,
                 lv_chargewashing,
                 lockerid,
                 internalbusinessunitid,
                 workstationcode,
                 coalesce(routedate, vplanneddeliverydate),
                 null);
              if debuglevel > 0 then
                pack_sort.write_logging('ID code ' || idcode ||
                                        ' insert deliveryscan ' ||
                                        uniqueitemid || ' PackingnoteID:' ||
                                        packingnoteid,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        1,
                                        1);
              end if;
            exception
              when others then
                accept := 'N';
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        3,
                                        1);
            end;
          end if;
          if accept = 'Y' then
            begin
              select s.value
                into chargewashcogchg
                from systemsetting s
               where s.plant_id = plantid_param
                 and s.name = 'CHARGEWASHCOGCHG/WEEK';
            exception
              when others then
                chargewashcogchg := 'N';
            end;
            if vcustomerowned = 'Y' and pchargewashesonlyforcog = 'Y' and
               ((pbillingmethod = 1 and chargewashcogchg = 'Y') or
               (pbillingmethod = 3) or
               (pbillingmethod = 4 and typeofmerch in (1, 2)) or
               (pbillingmethod = 5)) then
              update packingnoteline p
                 set p.deliveredamount = nvl(p.scannedqty, 0) + 1,
                     p.deliveredcogqty = p.deliveredcogqty + 1,
                     p.scannedqty = nvl(p.scannedqty, 0) + 1
               where p.packingnoteline_id = minpackingnotelineid;
            else
              update packingnoteline p
                 set p.deliveredamount = nvl(p.scannedqty, 0) + 1,
                     p.scannedqty = nvl(p.scannedqty, 0) + 1
               where p.packingnoteline_id = minpackingnotelineid;
            end if;
          end if;
          if accept = 'Y' then
            begin
              if lv_poolitem = 1 then
                 update uniqueitem u
                   set u.lastoutscandate               = vlastscandatetime,
                       u.lastscandate                  = vlastscandatetime,
                       u.washestotal                   = vwashestotal,
                       u.status_id                     = statusid,
                       u.prevstatus_id                 = vpreviousstatus,
                       u.prevstay_id                   = vpreviousstay,
                       u.stay_id                       = stayoutscan,
                       u.staychangedate                = vlastscandatetime,
                       u.systemuser_id                 = systemuserid,
                       u.timestamp                     = sysdate,
                       u.planneddeliverydate           = null,
                       u.deliveryfromstock             = 'N',
                       u.distributionpoint_id          = distributionpointid,
                       u.lastdistributionpoint_link_id = u.distributionpoint_id
                 where u.uniqueitem_id = uniqueitemid;
              else
                update uniqueitem u
                   set u.lastoutscandate     = case when lv_outofseasoncode is null
                                                    then vlastscandatetime
                                                    else u.lastoutscandate end,
                       u.lastscandate        = vlastscandatetime,
                       u.washestotal         = vwashestotal,
                       u.status_id           = statusid,
                       u.prevstatus_id       = vpreviousstatus,
                       u.prevstay_id         = case when lv_outofseasoncode is null
                                                    then vpreviousstay
                                                    else u.prevstay_id end,
                       u.stay_id             = case when lv_outofseasoncode is null
                                                    then stayoutscan
                                                    else u.stay_id end,
                       u.staychangedate      = case when lv_outofseasoncode is null
                                                    then vlastscandatetime
                                                    else u.staychangedate end,
                       u.systemuser_id       = systemuserid,
                       u.timestamp           = sysdate,
                       u.planneddeliverydate = null,
                       u.deliveryfromstock   = 'N'
                where  u.uniqueitem_id = uniqueitemid;
              end if;
              if debuglevel > 0 then
                pack_sort.write_logging('ID code ' || idcode ||
                                        ' update uniqueitem ' ||
                                        uniqueitemid,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        1,
                                        1);
              end if;
            exception
              when others then
                accept := 'N';
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        3,
                                        1);
            end;
          end if;
          if accept = 'Y' then
            begin
              --scan record
              vdayslate := 0;
              if scanbyroute = 'Y' and vplannedoutdate is not null then
                if vplannedoutdate - vlastoutscandate < 0 then
                  vdayslate := trunc(vlastoutscandate) -
                               trunc(vplannedoutdate);
                end if;
              end if;
              if scanbyroute = 'N' and vplanneddeliverydate is not null then
                if vplanneddeliverydate - vlastscandate < 0 then
                  vdayslate := trunc(vlastscandate) -
                               trunc(vplanneddeliverydate);
                end if;
              end if;
              if packingnoteid is not null then
                select pn.notenumber
                  into lv_deliverynotenr
                  from packingnote pn
                 where pn.packingnote_id = packingnoteid;
              end if;
              insert into scan
                (scan_id,
                 businessunit_id,
                 scantimestamp,
                 primaryid,
                 customer_link_id,
                 weareremployment_link_id,
                 distributionpoint_link_id,
                 product_link_id,
                 sizedefinition_link_id,
                 stay_id,
                 status_id,
                 scanstation,
                 issuedate,
                 route_id,
                 reasoncode_id,
                 customerowned,
                 year,
                 week,
                 dayno,
                 qualitygrade_id,
                 systemuser_id,
                 timestamp,
                 prevstay_id,
                 transactiontype_id,
                 dayslate,
                 uniqueitem_link_id,
                 secondaryid,
                 batchnumber,
                 deliverynotenumber)
              values
                (seq_scan.nextval,
                 businessunitid,
                 vlastscandatetime,
                 idcode,
                 customerid,
                 weareremploymentid,
                 distributionpointid,
                 productid,
                 sizeid,
                 stayoutscan,
                 statusid,
                 workstationcode,
                 vlastissuedate,
                 vlastoutroute,
                 lv_reasoncodeid,
                 vcustomerowned,
                 vyear,
                 vweek,
                 vdayno,
                 qualitygradeid,
                 systemuserid,
                 sysdate,
                 vpreviousstay,
                 case when lv_outofseasoncode is null
                   then transactiontp
                   else 56 end, --Season Scan
                 vdayslate,
                 uniqueitemid,
                 secondaryid,
                 fpbatchnumber,
                 lv_deliverynotenr)
              returning scan_id into vscanid;
              if debuglevel > 0 then
                pack_sort.write_logging('ID code ' || idcode ||
                                        ' insert outscan uniqueitem ' ||
                                        uniqueitemid,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        1,
                                        1);
              end if;
              -- MBA - td 9357
              if lv_use_treatmentcheck = '0' then
                begin
                  --begin 502489
                  select p.numberwashesspecialtreatment
                    into pnumberwashesspecialtreatment
                    from productlistpercustomer p
                   where p.productlistpercustomer_id = plpcid;
                  if lvcountwashesat = 'O' and
                     pnumberwashesspecialtreatment <> 0 then
                    begin
                      if mod(vwashestotal, pnumberwashesspecialtreatment) = 0 then
                        begin
                          select flag_id
                            into flagid
                            from automaticflag a
                           where a.automaticflag_id = 6;
                          flaginserted := create_uniqueitemflag('PACK_SORT.PROCESSOUTSCAN',
                                                                debuglevel,
                                                                systemuserid,
                                                                uniqueitemid,
                                                                flagid,
                                                                vlastscandate,
                                                                vscanid,
                                                                to_char(vwashestotal) ||
                                                                ' washes reached',
                                                                null,
                                                                plantid_param);
                        end;
                      end if;
                    end;
                  end if; --end 502489
                exception
                  when no_data_found then
                    null;
                end;
              else
                add_treatmentcheck_flags(debuglevel,
                                         systemuserid,
                                         uniqueitemid,
                                         vlastscandate,
                                         vscanid,
                                         null,
                                         lv_treatmentcheckschemeid,
                                         vwashestotal,
                                         plantid_param,
                                         productid,
                                         plpcid);
              end if;
              -- end MBA td 9357
            exception
              when others then
                accept := 'N';
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PROCESSOUTSCAN',
                                        plantid_param,
                                        3,
                                        1);
            end;
            -- MBA td 9345 - insert also scanflag if flag1/2/3/4 is provided
            if (vscanid > 0 and
               (flagcode1 is not null or flagcode2 is not null or
               flagcode3 is not null or flagcode4 is not null)) then
              createscanflag(vscanid,
                             systemuserid,
                             debuglevel,
                             flagcode1,
                             flagcode2,
                             flagcode3,
                             flagcode4,
                             plantid_param);
            end if;
            if (vscanid > 0) then
              add_scanflag(vscanid,
                           uniqueitemid,
                           'OutScan',
                           plantid_garment,
                           systemuserid);
            end if;
            -- end td 9345
          end if; --accept='Y'
        end if; --accept='Y'
        --order 501857
        begin
          if customercode = 'BNL' then
            if minplantdep = 'N' then
              if productoptimafactor = 0 then
                optimafigure := 0;
              else
                optimafigure := 1 / productoptimafactor;
              end if;
              select count(*)
                into countoptimahistory
                from optimahistory o
               where o.workstation_id = workstationid
                 and o.plantdepartment_id = plantdep
                 and o.deliverydate = trunc(sysdate);
              if countoptimahistory > 0 then
                update optimahistory o
                   set o.quantity      = o.quantity + optimafigure,
                       o.systemuser_id = systemuserid,
                       o.timestamp     = sysdate
                 where o.workstation_id = workstationid
                   and o.plantdepartment_id = plantdep
                   and o.deliverydate = trunc(sysdate);
              else
                insert into optimahistory
                  (plantdepartment_id,
                   deliverydate,
                   workstation_id,
                   quantity,
                   systemuser_id,
                   timestamp)
                values
                  (plantdep,
                   trunc(sysdate),
                   workstationid,
                   optimafigure,
                   systemuserid,
                   sysdate);
              end if;
            else
              pack_sort.write_logging('!> Optima history is not created/updated for unique item' ||
                                      idcode ||
                                      ' plantdepartmentID is not filled in workstation ' ||
                                      workstationcode,
                                      debuglevel,
                                      'PROCESSOUTSCAN',
                                      plantid_param,
                                      2,
                                      1);
            end if;
          end if;
        exception
          when others then
            pack_sort.write_logging('!> For unique item' || idcode ||
                                    ' optima history is not created/updated ',
                                    debuglevel,
                                    'PROCESSOUTSCAN',
                                    plantid_param,
                                    3,
                                    1);
        end;

      end if; ----If scaninterval = 'Y' then
    end if; --501875
  end processoutscan;
  ---create or replace
  procedure processrepairscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                              idcode          in uniqueitem.primaryid%type,
                              pool            in integer,
                              secondaryid     in secondaryuniqueitem.secondaryid%type,
                              businessunitid  in businessunit.businessunit_id%type,
                              uniqueitemid    in uniqueitem.uniqueitem_id%type,
                              workstationcode in workstation.code%type,
                              datep           in number,
                              timep           in varchar2, --number,
                              repairsdone     in varchar2,
                              systemuserid    in systemuser.systemuser_id%type,
                              debuglevel      in integer,
                              accept          out varchar2,
                              flagcode1       in sortaddressperflag.sortaddress%type default null,
                              flagcode2       in sortaddressperflag.sortaddress%type default null,
                              flagcode3       in sortaddressperflag.sortaddress%type default null,
                              flagcode4       in sortaddressperflag.sortaddress%type default null) is
    statusid              status.status_id%type;
    assigned              status.status_id%type;
    incirc                status.status_id%type;
    stayid                stay.stay_id%type;
    vpreviousstay         stay.stay_id%type;
    stayrepair            stay.stay_id%type;
    productid             product.product_id%type;
    sizeid                sizedefinition.sizedefinition_id%type;
    finishingmethodid     finishingmethod.finishingmethod_id%type;
    vlastscandate         date;
    vlastscandatetime     timestamp;
    weareremploymentid    weareremployment.weareremployment_id%type;
    customerid            customer.customer_id%type;
    distributionpointid   distributionpoint.distributionpoint_id%type;
    lastdistribpointid    distributionpoint_link.distributionpoint_link_id%type;
    vrepairstotal         integer;
    vrepairsthisissue     integer;
    vyear                 integer;
    vweek                 integer;
    vdayno                integer;
    auxstring             varchar2(7);
    repairstring          varchar2(7);
    vchargerepairs        customer.chargerepairs%type;
    repairtypeid          repairtype.repairtype_id%type;
    vdefaulttime          repairtype.defaulttime%type;
    cnt                   integer;
    i                     integer;
    vcustomerowned        varchar2(1);
    qualitygradeid        qualitygrade.qualitygrade_id%type;
    vlastissuedate        date;
    lastinroute           route.route_id%type;
    vdayslate             integer;
    primaryid             uniqueitem.primaryid%type;
    vpool                 repairhistory.pool%type;
    invoicebusinessunitid businessunit.businessunit_id%type;
    deliverypointid       deliverypoint.deliverypoint_id%type;
    lockerid              locker.locker_id%type;
    garmentdispenserid    garmentdispenser.garmentdispenser_id%type;
    vtypeofmerch          product.typeofmerchandise%type;
    routestopin           routestop.routestop_id%type;
    lastdatein            date;
    --begin 502317
    lvsdbcode        databasesettings.code%type;
    lvnrepairlength  number := 1;
    vchargerepaircog customer.chargerepaircog%type;
    vscanid          scanflag.scan_id%type; -- MBA td 9345
    lvplantid        plant.plant_id%type;
    -- Order 20014102
    deliverydetermination     integer;
    inroutecontrol_id         number;
    instop_id                 number := null;
    outroutecontrol_id        number;
    stopid                    number := null;
    scanbyroute               varchar2(1);
    plantid                   plant.plant_id%type;
    routeid                   route.route_id%type;
    plannedrouteid            route.route_id%type;
    planneddate               date;
    plannedroute              route.route_id%type;
    deliverymethod            integer;
    deedeliveryschemeid       deliveryscheme.deliveryscheme_id%type;
    plpcid                    productlistpercustomer.productlistpercustomer_id%type;
    routestopid               routestop.routestop_id%type;
    vmaxwashes                integer;
    plpcfinishingcode         productlistpercustomer.finishingcode_id%type;
    plpcustomcode             productlistpercustomer.customcode%type;
    plpcustomdescription      productlistpercustomer.customdescription%type;
    pchargewashesonlyforcog   varchar2(1);
    pbillingmethod            integer;
    lv_treatmentcheckschemeid treatmentcheckscheme.treatmentcheckscheme_id%type;
    department_id             number := null;
    lv_log                    varchar2(1) := 'N';
    lv_lastoutdate            date;
    lv_lastoutstopid          number;
    lv_lastoutrouteid         number;
    -- end Order 20014102

  begin
    select b.plant_id
      into lvplantid
      from businessunit b
     where b.businessunit_id = businessunitid;

    select code into lvsdbcode from databasesettings;
    if lvsdbcode = 'VEN' then
      lvnrepairlength := 2;
    end if;
    --end 502317
    accept            := 'Y';
    vlastscandate     := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vlastscandatetime := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vyear             := getyearofweek(vlastscandate);
    vweek             := getisoweek(vlastscandate);
    vdayno            := getabsdaynumber(vlastscandate);
    vscanid           := 0;
    -- Order 20014102
    begin
      select s.value, p.plant_id
        into scanbyroute, plantid
        from systemsetting s, uniqueitem u, plant p, businessunit bu
       where s.name = 'SCANBYROUTE'
         and s.plant_id = bu.plant_id
         and bu.plant_id = p.plant_id
         and bu.businessunit_id = u.businessunit_id
         and u.uniqueitem_id = uniqueitemid;
    exception
      when others then
        null;
    end;
    begin
      select s.value
        into deliverydetermination
        from systemsetting s
       where s.plant_id = plantid
         and s.name = 'DELIVERYDETERMINATION';
    exception
      when others then
        null;
    end;
    -- end Order 20014102
    if pool = 2 then
      --nonpool
      begin
        vpool := 'N';
        select u.primaryid,
               u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               n.weareremployment_id,
               w.customer_id,
               u.stay_id,
               u.status_id,
               e.distributionpoint_id,
               f.lastissuedate,
               u.repairstotal,
               u.customerowned,
               f.qualitygrade_id,
               n.repairsthisissue,
               e.deliverypoint_id,
               e.garmentdispenser_id,
               e.locker_id
          into primaryid,
               productid,
               sizeid,
               finishingmethodid,
               weareremploymentid,
               customerid,
               stayid,
               statusid,
               distributionpointid,
               vlastissuedate,
               vrepairstotal,
               vcustomerowned,
               qualitygradeid,
               vrepairsthisissue,
               deliverypointid,
               garmentdispenserid,
               lockerid
          from uniqueitem          u,
               uniqueitemnonpool   n,
               uniqueitemfixedinfo f,
               weareremployment    e,
               wearer              w
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = n.uniqueitem_id
           and n.weareremployment_id = e.weareremployment_id
           and e.wearer_id = w.wearer_id
           and u.uniqueitem_id = f.uniqueitem_id;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                  debuglevel,
                                  'PROCESSREPAIRSCAN',
                                  lvplantid,
                                  3,
                                  1);
      end;
    else
      --pool
      begin
        vpool := 'Y';
        select u.primaryid,
               u.relatedcustomer_id,
               u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               u.distributionpoint_id,
               u.lastdistributionpoint_link_id,
               u.stay_id,
               u.status_id,
               u.repairstotal,
               u.customerowned,
               f.qualitygrade_id,
               f.lastissuedate
          into primaryid,
               customerid,
               productid,
               sizeid,
               finishingmethodid,
               distributionpointid,
               lastdistribpointid,
               stayid,
               statusid,
               vrepairstotal,
               vcustomerowned,
               qualitygradeid,
               vlastissuedate
          from uniqueitem u, uniqueitemfixedinfo f
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = f.uniqueitem_id;
        if customerid is null then
          if distributionpointid is not null then
            select e.customer_id
              into customerid
              from distributionpoint d, department e
             where distributionpointid = d.distributionpoint_id
               and d.department_id = e.department_id;
          elsif lastdistribpointid is not null then
            select e.customer_link_id
              into customerid
              from distributionpoint_link d, department_link e
             where lastdistribpointid = d.distributionpoint_id
               and d.department_link_id = e.department_link_id;
          end if;
        end if;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                  debuglevel,
                                  'PROCESSREPAIRSCAN',
                                  lvplantid,
                                  3,
                                  1);
      end;
    end if;
    -- Order 20014102 - scan record
    routeid := -1;
    begin
      select u.plannedoutroute_id,
             u.plannedoutdate,
             u.lastoutdate,
             u.lastoutstop_id,
             u.lastoutroute_id
        into plannedrouteid,
             planneddate,
             lv_lastoutdate,
             lv_lastoutstopid,
             lv_lastoutrouteid
        from uniqueitemroute u
       where u.uniqueitem_id = uniqueitemid;
    exception
      when no_data_found then
        routeid        := null;
        plannedrouteid := null;
    end;
    --stay,status
    vpreviousstay := stayid;
    select s.status_id
      into assigned
      from status s
     where s.statustype = 'UI'
       and s.code = '30';
    select s.status_id
      into incirc
      from status s
     where s.statustype = 'UI'
       and s.code = '20';
    if statusid not in (assigned, incirc) then
      accept := 'N';
      pack_sort.write_logging('!> ' || idcode ||
                              ' status not assigned or incirc',
                              debuglevel,
                              'PROCESSREPAIRSCAN',
                              lvplantid,
                              3,
                              1);
    end if;
    select stay.stay_id
      into stayrepair
      from stay
     where stay.staytype = 1
       and stay.staynr = 32; --repair stay
    -- HVH order 502317 also look at charge repaircog
    if accept = 'Y' then
      begin
        if customerid is not null then
          select customer.chargerepairs, customer.chargerepaircog
            into vchargerepairs, vchargerepaircog
            from customer
           where customer.customer_id = customerid;
        else
          begin
            vchargerepairs   := 0;
            vchargerepaircog := 0;
          end;
        end if;
        if vcustomerowned = 'Y' then
          begin
            if vchargerepaircog = 0 or vchargerepaircog = 1 then
              vchargerepairs := 1; --freeofcharge for field Status in RepairHistory table
            else
              vchargerepairs := 0; --charge field Status In RepairHistory;
            end if;
          end;
        else
          begin
            if vchargerepairs = 0 or vchargerepairs = 1 then
              vchargerepairs := 1; --freeofcharge for field Status in RepairHistory table
            else
              vchargerepairs := 0; --charge field Status In RepairHistory;
            end if;
          end;
        end if;
        -- HVH order 502317 also look at charge repaircog - end of change
        if customerid is not null then
          begin
            select customeractivities.invoicebusinessunit_id
              into invoicebusinessunitid
              from customeractivities, productgroup, product
             where customeractivities.customer_id = customerid
               and customeractivities.activity_id =
                   productgroup.activity_id
               and product.productgroup_id = productgroup.productgroup_id
               and product.product_id = productid;
          exception
            when others then
              null;
          end;
        end if;
        if repairsdone is null or repairsdone = ' ' then
          cnt := 0;
        else
          --502317 used lvnrepairlength
          cnt := round(length(repairsdone) / lvnrepairlength);
        end if;
        if (cnt * lvnrepairlength) > 7 then
          repairstring := substr(repairsdone, 1, 7);
          --502317 used lvnrepairlength
          cnt := trunc(7 / lvnrepairlength);
        else
          repairstring := repairsdone;
        end if;
        if cnt > 0 then
          for i in 1 .. cnt loop
            --502317 used lvnrepairlength
            auxstring := substr(repairstring,
                                (i * lvnrepairlength) -
                                (lvnrepairlength - 1),
                                lvnrepairlength);
            /*
            (i * lvnrepairlength) - (lvnrepairlength - 1)
            For length 2
                        (1 * 2) - (2-1)=1
                        (2 * 2) - (2-1)=3
                        (3 * 2) - (2-1)=5
            For length 1
                        (1 * 1) - (1-1)=1
                        (2 * 1) - (1-1)=2
                        (3 * 1) - (1-1)=3
            */
            if auxstring <> ' ' and auxstring <> '0' then
              begin
                vrepairstotal := vrepairstotal + 1;
                if pool = 2 then
                  vrepairsthisissue := vrepairsthisissue + 1;
                end if;
                --502317 new if then else
                if lvsdbcode = 'VEN' then
                  select r.repairtype_id, r.defaulttime
                    into repairtypeid, vdefaulttime
                    from repairtype r
                   where r.code = trim(auxstring);
                else
                  select r.repairtype_id, r.defaulttime
                    into repairtypeid, vdefaulttime
                    from repairtype r
                   where r.defaultfor = auxstring;
                end if;
                insert into repairhistory
                  (repairhistory_id,
                   supplier_id,
                   currency_id,
                   product_link_id,
                   distributionpoint_link_id,
                   weareremployment_link_id,
                   customer_link_id,
                   repairtype_id,
                   uniqueitem_link_id,
                   businessunit_id,
                   repairdate,
                   minutes,
                   year,
                   week,
                   day,
                   pool,
                   unitprice,
                   priceperminute,
                   systemuser_id,
                   timestamp,
                   status,
                   invoicebusinessunit_id,
                   invoiceheader_id,
                   primaryid,
                   amount)
                values
                  (seq_repairhistory.nextval,
                   null,
                   null,
                   productid,
                   distributionpointid,
                   weareremploymentid,
                   customerid,
                   repairtypeid,
                   uniqueitemid,
                   businessunitid,
                   vlastscandate,
                   vdefaulttime,
                   vyear,
                   vweek,
                   vdayno,
                   vpool,
                   null,
                   null,
                   systemuserid,
                   sysdate,
                   vchargerepairs,
                   invoicebusinessunitid,
                   null,
                   primaryid,
                   0);
              exception
                when no_data_found then
                  null;
                when others then
                  accept := 'N';
                  pack_sort.write_logging('!> ' || idcode || ' ' ||
                                          sqlerrm,
                                          debuglevel,
                                          'PROCESSREPAIRSCAN',
                                          lvplantid,
                                          3,
                                          1);
              end;
            end if;
          end loop;
        end if;
        -- RVI ToDo 21124 Also look at defined repairtypes for business unit, BEGIN
        if (lvsdbcode = 'NAF') then
          begin
            --only starting with 7.26 - according with order 874
            if cnt = 0 and accept = 'Y' then
              for vcursor in (select a.repairtype_id, a.defaulttime
                                from repairtype a, repairtypesperbu rb
                               where rb.repairtype_id = a.repairtype_id
                                 and rb.businessunit_id = businessunitid
                                 and a.autoaddonrepairscan = 'Y'
                                 and a.active = 'Y') loop
                begin
                  vrepairstotal := vrepairstotal + 1;
                  if pool = 2 then
                    vrepairsthisissue := vrepairsthisissue + 1;
                  end if; ---comment here end if
                  insert into repairhistory
                    (repairhistory_id,
                     supplier_id,
                     currency_id,
                     product_link_id,
                     distributionpoint_link_id,
                     weareremployment_link_id,
                     customer_link_id,
                     repairtype_id,
                     uniqueitem_link_id,
                     businessunit_id,
                     repairdate,
                     minutes,
                     year,
                     week,
                     day,
                     pool,
                     unitprice,
                     priceperminute,
                     systemuser_id,
                     timestamp,
                     status,
                     invoicebusinessunit_id,
                     invoiceheader_id,
                     primaryid,
                     amount)
                  values
                    (seq_repairhistory.nextval,
                     null,
                     null,
                     productid,
                     distributionpointid,
                     weareremploymentid,
                     customerid,
                     vcursor.repairtype_id,
                     uniqueitemid,
                     businessunitid,
                     vlastscandate,
                     vcursor.defaulttime,
                     vyear,
                     vweek,
                     vdayno,
                     vpool,
                     null,
                     null,
                     systemuserid,
                     sysdate,
                     vchargerepairs,
                     invoicebusinessunitid,
                     null,
                     primaryid,
                     0);
                exception
                  when others then
                    accept := 'N';
                    pack_sort.write_logging('!> ' || idcode || ' ' ||
                                            sqlerrm,
                                            debuglevel,
                                            'PROCESSREPAIRSCAN',
                                            lvplantid,
                                            3,
                                            1);
                    ---- end if;-
                end;
              end loop;
            end if;
          end;
        else
          begin
            -- RVI ToDo 21124 Also look at defined repairtypes for business unit, END
            --only starting with 7.26 - according with order 874
            if cnt = 0 and accept = 'Y' then
              for vcursor in (select a.repairtype_id, a.defaulttime
                                from repairtype a
                               where a.autoaddonrepairscan = 'Y'
                                 and a.active = 'Y') loop
                begin
                  vrepairstotal := vrepairstotal + 1;
                  if pool = 2 then
                    vrepairsthisissue := vrepairsthisissue + 1;
                  end if; ---comment here end if
                  insert into repairhistory
                    (repairhistory_id,
                     supplier_id,
                     currency_id,
                     product_link_id,
                     distributionpoint_link_id,
                     weareremployment_link_id,
                     customer_link_id,
                     repairtype_id,
                     uniqueitem_link_id,
                     businessunit_id,
                     repairdate,
                     minutes,
                     year,
                     week,
                     day,
                     pool,
                     unitprice,
                     priceperminute,
                     systemuser_id,
                     timestamp,
                     status,
                     invoicebusinessunit_id,
                     invoiceheader_id,
                     primaryid,
                     amount)
                  values
                    (seq_repairhistory.nextval,
                     null,
                     null,
                     productid,
                     distributionpointid,
                     weareremploymentid,
                     customerid,
                     vcursor.repairtype_id,
                     uniqueitemid,
                     businessunitid,
                     vlastscandate,
                     vcursor.defaulttime,
                     vyear,
                     vweek,
                     vdayno,
                     vpool,
                     null,
                     null,
                     systemuserid,
                     sysdate,
                     vchargerepairs,
                     invoicebusinessunitid,
                     null,
                     primaryid,
                     0);
                exception
                  when others then
                    accept := 'N';
                    pack_sort.write_logging('!> ' || idcode || ' ' ||
                                            sqlerrm,
                                            debuglevel,
                                            'PROCESSREPAIRSCAN',
                                            lvplantid,
                                            3,
                                            1);
                    ---- end if;-
                end;
              end loop;
            end if;
            -- RVI ToDo 21124 Also look at defined repairtypes for business unit, BEGIN
          end;
        end if;
        -- RVI ToDo 21124 Also look at defined repairtypes for business unit, END
        --update uniqueitem
        if accept = 'Y' then
          begin
            update uniqueitem u
               set u.lastscandate   = vlastscandatetime,
                   u.repairstotal   = vrepairstotal,
                   u.prevstay_id    = vpreviousstay,
                   u.stay_id        = stayrepair,
                   u.staychangedate = vlastscandatetime,
                   u.systemuser_id  = systemuserid,
                   u.timestamp      = sysdate
             where u.uniqueitem_id = uniqueitemid;
            if debuglevel > 0 then
              pack_sort.write_logging('Id code ' || idcode ||
                                      ' update uniqueitem ' ||
                                      uniqueitemid || ' Repairstotal' ||
                                      vrepairstotal,
                                      debuglevel,
                                      'PROCESSREPAIRSCAN',
                                      lvplantid,
                                      1,
                                      1);
            end if;
          exception
            when others then
              begin
                accept := 'N';
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PROCESSREPAIRSCAN',
                                        lvplantid,
                                        3,
                                        1);
              end;
          end;
        end if;
        --update uniqueitemnonpool
        if pool = 2 and accept = 'Y' then
          begin
            update uniqueitemnonpool n
               set n.repairsthisissue = vrepairsthisissue
             where n.uniqueitem_id = uniqueitemid;
            if debuglevel > 0 then
              pack_sort.write_logging('Id code ' || idcode ||
                                      ' update uniqueitemnonpool ' ||
                                      uniqueitemid ||
                                      ' Repairs this issue' ||
                                      vrepairsthisissue,
                                      debuglevel,
                                      'PROCESSREPAIRSCAN',
                                      lvplantid,
                                      1,
                                      1);
            end if;
          exception
            when others then
              accept := 'N';
              pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                      debuglevel,
                                      'PROCESSREPAIRSCAN',
                                      lvplantid,
                                      3,
                                      1);
          end;
        end if;
        ----scan record
        if accept = 'Y' then
          vdayslate := 0;
          if deliverypointid is null and pool = 2 then
            if lockerid is not null then
              select l.deliverypoint_id
                into deliverypointid
                from locker l
               where l.locker_id = lockerid;
            elsif garmentdispenserid is not null then
              select g.deliverypoint_id
                into deliverypointid
                from garmentdispenser g
               where g.garmentdispenser_id = garmentdispenserid;
            end if;
          end if;
          select p.typeofmerchandise
            into vtypeofmerch
            from product p
           where p.product_id = productid;
          if customerid is not null and pool = 2 then
            pack_sort.getlastinroute_debug(customerid,
                                           vlastscandate,
                                           deliverypointid,
                                           vtypeofmerch,
                                           plantid,
                                           lastinroute,
                                           routestopin,
                                           lastdatein);
          end if;
          begin
            insert into scan
              (scan_id,
               businessunit_id,
               scantimestamp,
               primaryid,
               customer_link_id,
               weareremployment_link_id,
               distributionpoint_link_id,
               product_link_id,
               sizedefinition_link_id,
               stay_id,
               status_id,
               scanstation,
               issuedate,
               route_id,
               reasoncode_id,
               customerowned,
               year,
               week,
               dayno,
               qualitygrade_id,
               systemuser_id,
               timestamp,
               prevstay_id,
               transactiontype_id,
               dayslate,
               uniqueitem_link_id,
               secondaryid)
            values
              (seq_scan.nextval,
               businessunitid,
               vlastscandate,
               idcode,
               customerid,
               weareremploymentid,
               distributionpointid,
               productid,
               sizeid,
               stayrepair,
               statusid,
               workstationcode,
               vlastissuedate,
               lastinroute,
               null,
               vcustomerowned,
               vyear,
               vweek,
               vdayno,
               qualitygradeid,
               systemuserid,
               sysdate,
               vpreviousstay,
               transactiontp,
               vdayslate,
               uniqueitemid,
               secondaryid)
            returning scan_id into vscanid;
            if debuglevel > 0 then
              pack_sort.write_logging('Id code ' || idcode ||
                                      'insert scan for uniqueitemid ' ||
                                      uniqueitemid,
                                      debuglevel,
                                      'PROCESSREPAIRSCAN',
                                      lvplantid,
                                      1,
                                      1);
            end if;
            -- MBA td 9345
          exception
            when others then
              begin
                accept := 'N';
                pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                        debuglevel,
                                        'PROCESSREPAIRSCAN',
                                        lvplantid,
                                        3,
                                        1);
              end;
          end;

          -- Order 20014102
          if scanbyroute = 'Y' then
            begin
              ------------
              pack_sort.findplpcinfo(customerid,
                                     productid,
                                     sizeid,
                                     finishingmethodid,
                                     deliverymethod,
                                     deedeliveryschemeid,
                                     plpcid,
                                     vmaxwashes,
                                     plpcfinishingcode,
                                     plpcustomcode,
                                     plpcustomdescription,
                                     pchargewashesonlyforcog,
                                     pbillingmethod,
                                     lv_treatmentcheckschemeid);
              if plpcid is null then
                if pool = 2 then
                  deliverymethod := 1;
                else
                  deliverymethod := 0;
                end if;
              end if;
              --deliverypoint
              begin
                if deliverypointid is null and pool = 2 then
                  if lockerid is not null then
                    select l.deliverypoint_id
                      into deliverypointid
                      from locker l
                     where l.locker_id = lockerid;
                  elsif garmentdispenserid is not null then
                    select g.deliverypoint_id
                      into deliverypointid
                      from garmentdispenser g
                     where g.garmentdispenser_id = garmentdispenserid;
                  end if;
                end if;
                if pool = 1 then
                  begin
                    select d.deliverypoint_id
                      into deliverypointid
                      from distributionpoint d
                     where d.distributionpoint_id = distributionpointid;
                  exception
                    when no_data_found then
                      null;
                  end;
                end if;
              end;
              ------------
              -----
              if deliverydetermination <> 1 then
                if customerid is not null then
                  select p.typeofmerchandise
                    into vtypeofmerch
                    from product p
                   where p.product_id = productid;
                  pack_sort.getlastinroute_debug(customerid,
                                           vlastscandate,
                                           deliverypointid,
                                           vtypeofmerch,
                                           plantid,
                                           lastinroute,
                                           routestopin,
                                           lastdatein);
                end if;

                if pool = 1 then
                  plannedroute := null;
                  planneddate  := null;
                elsif pool = 2 then
                  pack_sort.fillplannedoutroute(plantid,
                                                vlastscandate,
                                                vtypeofmerch,
                                                deliverymethod,
                                                deedeliveryschemeid,
                                                plpcid,
                                                customerid,
                                                deliverypointid,
                                                lastinroute,
                                                lastdatein,
                                                routestopin,
                                                routestopid,
                                                plannedroute,
                                                planneddate,
                                                scanbyroute);
                end if;
              end if;
              ------------------------------
              if routeid is null and deliverydetermination <> 1 then
                insert into uniqueitemroute
                  (uniqueitem_id,
                   lastinroute_id,
                   lastoutroute_id,
                   plannedoutroute_id,
                   lastindate,
                   lastoutdate,
                   plannedoutdate,
                   systemuser_id,
                   timestamp)
                values
                  (uniqueitemid,
                   lastinroute,
                   null,
                   plannedroute,
                   lastdatein,
                   null,
                   planneddate,
                   systemuserid,
                   sysdate);
                if debuglevel > 0 then
                  pack_sort.write_logging('Id code ' || idcode ||
                                          'insert uniqueitemroute for uniqueitemid ' ||
                                          uniqueitemid,
                                          debuglevel,
                                          'PROCESSREPAIRSCAN',
                                          lvplantid,
                                          1,
                                          1);
                end if;
              elsif plannedrouteid is null and deliverydetermination <> 1 then
                update uniqueitemroute u
                   set u.lastinroute_id     = lastinroute,
                       u.plannedoutroute_id = plannedroute,
                       u.lastindate         = to_date(lastdatein),
                       u.plannedoutdate     = to_date(planneddate),
                       u.systemuser_id      = systemuserid,
                       u.timestamp          = sysdate
                 where u.uniqueitem_id = uniqueitemid;
                if debuglevel > 0 then
                  pack_sort.write_logging('Id code ' || idcode ||
                                          'update uniqueitemroute for uniqueitemid ' ||
                                          uniqueitemid,
                                          debuglevel,
                                          'PROCESSREPAIRSCAN',
                                          lvplantid,
                                          1,
                                          1);
                end if;
                -- order 20014102
              elsif planneddate is null and deliverydetermination = 1 then
                if (lv_lastoutdate is not null and
                   lv_lastoutdate >= trunc(sysdate)) and
                   (lv_lastoutrouteid is not null and
                   lv_lastoutstopid is not null) then
                  select uir.lastindate,
                         uir.lastinroute_id,
                         uir.lastinstop_id,
                         uir.lastoutdate,
                         uir.lastoutroute_id,
                         uir.lastoutstop_id
                    into lastdatein,
                         lastinroute,
                         instop_id,
                         planneddate,
                         plannedroute,
                         stopid
                    from uniqueitemroute uir
                   where uir.uniqueitem_id = uniqueitemid;
                  ---
                  update uniqueitem ui
                     set ui.planneddeliverydate = planneddate
                   where ui.uniqueitem_id = uniqueitemid;
                else
                  pack_deliverybasics.determinedeldateroutesoil(plantid,
                                                                customerid,
                                                                deliverypointid,
                                                                department_id,
                                                                vtypeofmerch,
                                                                vlastscandate,
                                                                plpcid,
                                                                distributionpointid,
                                                                lv_log,
                                                                lastinroute,
                                                                routestopin,
                                                                inroutecontrol_id,
                                                                instop_id,
                                                                lastdatein,
                                                                plannedroute,
                                                                routestopid,
                                                                outroutecontrol_id,
                                                                stopid,
                                                                planneddate);
                end if;

                update uniqueitemroute u
                   set u.lastinroute_id     = lastinroute,
                       u.plannedoutroute_id = plannedroute,
                       u.lastindate         = to_date(lastdatein),
                       u.plannedoutdate     = to_date(planneddate),
                       u.systemuser_id      = systemuserid,
                       u.timestamp          = sysdate,
                       lastinstop_id        = instop_id,
                       plannedoutstop_id    = stopid
                 where u.uniqueitem_id = uniqueitemid;
                if debuglevel > 0 then
                  pack_sort.write_logging('Id code ' || idcode ||
                                          'update uniqueitemroute for uniqueitemid ' ||
                                          uniqueitemid,
                                          debuglevel,
                                          'PROCESSREPAIRSCAN',
                                          lvplantid,
                                          1,
                                          1);

                end if;
              elsif planneddate < trunc(sysdate) and
                    deliverydetermination = 1 then
                pack_deliverybasics.determinedeldaterouteclean(plantid,
                                                               customerid,
                                                               deliverypointid,
                                                               department_id,
                                                               vtypeofmerch,
                                                               vlastscandate,
                                                               plpcid,
                                                               distributionpointid,
                                                               lv_log,
                                                               routestopid,
                                                               plannedroute,
                                                               stopid,
                                                               outroutecontrol_id,
                                                               planneddate);
                update uniqueitemroute u
                   set u.plannedoutroute_id = plannedroute,
                       u.plannedoutdate     = to_date(planneddate),
                       u.systemuser_id      = systemuserid,
                       u.timestamp          = sysdate,
                       plannedoutstop_id    = stopid
                 where u.uniqueitem_id = uniqueitemid;
                if debuglevel > 0 then
                  pack_sort.write_logging('Id code ' || idcode ||
                                          'update uniqueitemroute for uniqueitemid ' ||
                                          uniqueitemid,
                                          debuglevel,
                                          'PROCESSREPAIRSCAN',
                                          lvplantid,
                                          1,
                                          1);
                end if;
                -- end order 20014102
              end if;
            end;
          end if; --end scanbyroute='Y'
          -- end Order 20014102
          -- MBA td 9345 - insert also scanflag if flag1/2/3/4 is provided
          if (vscanid > 0 and
             (flagcode1 is not null or flagcode2 is not null or
             flagcode3 is not null or flagcode4 is not null)) then
            createscanflag(vscanid,
                           systemuserid,
                           debuglevel,
                           flagcode1,
                           flagcode2,
                           flagcode3,
                           flagcode4,
                           lvplantid);
          end if;
          if (vscanid > 0) then
            add_scanflag(vscanid,
                         uniqueitemid,
                         'RepairScan',
                         lvplantid,
                         systemuserid);
          end if;
          -- end td 9345

          addmaxrepairflag(uniqueitemid,
                           systemuserid,
                           debuglevel,
                           businessunitid,
                           pool,
                           vlastscandate,
                           vrepairstotal,
                           productid,
                           sizeid,
                           finishingmethodid,
                           distributionpointid);

        end if;
      end;
    end if;
  end processrepairscan;

  procedure addmaxrepairflag(uniqueitemid        in uniqueitem.uniqueitem_id%type,
                             systemuserid        in systemuser.systemuser_id%type,
                             debuglevel          in integer,
                             businessunitid      in businessunit.businessunit_id%type,
                             pool                in integer,
                             vlastscandate       in date,
                             repairstotal        in integer,
                             productid           in product.product_id%type,
                             sizeid              in sizedefinition.sizedefinition_id%type,
                             finishingmethodid   in finishingmethod.finishingmethod_id%type,
                             distributionpointid in distributionpoint.distributionpoint_id%type) is

    maxrepairsproduct  number;
    maxrepairsplpc     number;
    maxrepflagattached number;
    maxrepairsflagid   number;
    plantid            plant.plant_id%type;

  begin

    select b.plant_id
      into plantid
      from businessunit b
     where b.businessunit_id = businessunitid;

    select af.flag_id
      into maxrepairsflagid
      from automaticflag af
     where af.event = 'Maximum Number of Repairs';

    select count(*)
      into maxrepflagattached
      from uniqueitemflag uif
     where uif.uniqueitem_id = uniqueitemid
       and uif.flag_id = maxrepairsflagid;

    if (maxrepflagattached = 0 and maxrepairsflagid is not null) then

      if (pool = 2) then
        select nvl(max(plpc.maximumnumberofrepairs), 0),
               nvl(max(p.maximumnumberofrepairs), 0)
          into maxrepairsplpc, maxrepairsproduct
          from productlistpercustomer plpc,
               uniqueitemnonpool      uinp,
               wearerinventory        wi,
               weareremployment       we,
               wearer                 w,
               product                p
         where plpc.product_id = productid
           and (plpc.sizedefinition_id = sizeid or
               plpc.sizedefinition_id =
               (select sd.sizedefinition_id
                   from sizedefinition sd
                  where sd.code = '*'))
           and plpc.finishingmethod_id = finishingmethodid
           and uinp.uniqueitem_id = uniqueitemid
           and uinp.wearerinventory_id = wi.wearerinventory_id
           and wi.weareremployment_id = we.weareremployment_id
           and we.wearer_id = w.wearer_id
           and w.customer_id = plpc.customer_id
           and plpc.product_id = p.product_id
           and plpc.dateactive < vlastscandate
           and plpc.dateinactive > vlastscandate;

        if (maxrepairsplpc > 0 and repairstotal > maxrepairsplpc) or
           (maxrepairsproduct > 0 and repairstotal > maxrepairsproduct and
           maxrepairsplpc = 0) then

          insert into uniqueitemflag
            (uniqueitem_id, flag_id, startdate, systemuser_id, timestamp)
          values
            (uniqueitemid,
             maxrepairsflagid,
             sysdate,
             systemuserid,
             sysdate);
          commit;

        end if;

      else
        select nvl(max(plpc.maximumnumberofrepairs), 0),
               nvl(max(p.maximumnumberofrepairs), 0)
          into maxrepairsplpc, maxrepairsproduct
          from productlistpercustomer plpc,
               distributionpoint      dp,
               department             d,
               product                p
         where plpc.product_id = productid
           and (plpc.sizedefinition_id = sizeid or
               plpc.sizedefinition_id =
               (select sd.sizedefinition_id
                   from sizedefinition sd
                  where sd.code = '*'))
           and plpc.finishingmethod_id = finishingmethodid
           and dp.distributionpoint_id = distributionpointid
           and dp.department_id = d.department_id
           and d.customer_id = plpc.customer_id
           and plpc.product_id = p.product_id
           and plpc.dateactive < vlastscandate
           and plpc.dateinactive > vlastscandate;

        if (maxrepairsplpc > 0 and repairstotal > maxrepairsplpc) or
           (maxrepairsproduct > 0 and repairstotal > maxrepairsproduct and
           maxrepairsplpc = 0) then
          insert into uniqueitemflag
            (uniqueitem_id, flag_id, startdate, systemuser_id, timestamp)
          values
            (uniqueitemid,
             maxrepairsflagid,
             sysdate,
             systemuserid,
             sysdate);
          commit;
        end if;

      end if;

    end if;
  exception
    when others then
      begin
        pack_sort.write_logging('!> ' || uniqueitemid || ' ' || sqlerrm,
                                debuglevel,
                                'addmaxrepairflag',
                                plantid,
                                3,
                                1);
      end;

  end addmaxrepairflag;

  procedure processrewash(transactiontp   in sortingimportdefinition.transactiontype%type,
                          idcode          in uniqueitem.primaryid%type,
                          pool            in integer,
                          secondaryid     in secondaryuniqueitem.secondaryid%type,
                          plantid_garment in plant.plant_id%type,
                          plantid_param   in plant.plant_id%type,
                          businessunitid  in businessunit.businessunit_id%type,
                          uniqueitemid    in uniqueitem.uniqueitem_id%type,
                          workstationcode in workstation.code%type,
                          datep           in number,
                          timep           in varchar2,
                          scanbyroute     in varchar2,
                          systemuserid    in systemuser.systemuser_id%type,
                          debuglevel      in integer,
                          accept          out varchar2,
                          flagcode1       in sortaddressperflag.sortaddress%type default null,
                          flagcode2       in sortaddressperflag.sortaddress%type default null,
                          flagcode3       in sortaddressperflag.sortaddress%type default null,
                          flagcode4       in sortaddressperflag.sortaddress%type default null) is
    stayid                    stay.stay_id%type;
    statusid                  status.status_id%type;
    assigned                  status.status_id%type;
    incirc                    status.status_id%type;
    productid                 product.product_id%type;
    sizeid                    sizedefinition.sizedefinition_id%type;
    weareremploymentid        weareremployment.weareremployment_id%type;
    customerid                customer.customer_id%type;
    vissuedate                date;
    finishingmethodid         finishingmethod.finishingmethod_id%type;
    distributionpointid       distributionpoint.distributionpoint_id%type;
    lastdistribpointid        distributionpoint_link.distributionpoint_link_id%type;
    vlastscandate             date;
    vlastscandatetime         timestamp;
    vpreviousstay             stay.stay_id%type;
    vmaxwashes                integer;
    productmaxwashes          integer;
    vwashestotal              integer;
    vwashesthisissue          integer;
    vrewashthisissue          integer;
    vyear                     integer;
    vweek                     integer;
    vdayno                    integer;
    cnt                       integer;
    vcustomerowned            varchar2(1);
    flagid                    flag.flag_id%type;
    qualitygradeid            qualitygrade.qualitygrade_id%type;
    vrewashtotal              integer;
    lastinroute               route.route_id%type;
    deliverypointid           deliverypoint.deliverypoint_id%type;
    lockerid                  locker.locker_id%type;
    garmentdispenserid        garmentdispenser.garmentdispenser_id%type;
    vtypeofmerch              product.typeofmerchandise%type;
    routestopin               routestop.routestop_id%type;
    routestopid               routestop.routestop_id%type;
    lastdatein                date;
    plannedroute              route.route_id%type;
    planneddate               date;
    plpcid                    productlistpercustomer.productlistpercustomer_id%type;
    deliverymethod            integer;
    discardcompletecheck      varchar2(1);
    deedeliveryschemeid       deliveryscheme.deliveryscheme_id%type;
    plpcfinishingcode         productlistpercustomer.finishingcode_id%type;
    plpcustomcode             productlistpercustomer.customcode%type;
    plpcustomdescription      productlistpercustomer.customdescription%type;
    pchargewashesonlyforcog   varchar2(1);
    pbillingmethod            integer;
    vscanid                   scanflag.scan_id%type; -- MBA td 9345
    lv_treatmentcheckschemeid treatmentcheckscheme.treatmentcheckscheme_id%type;
    lv_use_treatmentcheck     systemsetting.value%type;
    flaginserted              boolean;
    -- Order 20014102
    deliverydetermination integer;
    inroutecontrol_id     number;
    instop_id             number;
    outroutecontrol_id    number := null;
    stopid                number := null;
    department_id         number := null;
    lv_log                varchar2(1) := 'N';
    lv_lastoutdate        date;
    lv_lastoutrouteid     number;
    lv_lastoutstopid      number;
  begin
    accept            := 'Y';
    vlastscandate     := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vlastscandatetime := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vyear             := getyearofweek(vlastscandate);
    vweek             := getisoweek(vlastscandate);
    vdayno            := getabsdaynumber(vlastscandate);
    vscanid           := 0;
    begin
      -- USETREATMENTCHECK
      select s.value
        into lv_use_treatmentcheck
        from systemsetting s
       where s.name = 'USETREATMENTCHECK'
         and s.plant_id = plantid_param;
    exception
      when no_data_found then
        lv_use_treatmentcheck := '0';
    end;
    -- Order 20014102
    begin
      select s.value
        into deliverydetermination
        from systemsetting s
       where s.plant_id = plantid_garment
         and s.name = 'DELIVERYDETERMINATION';
    exception
      when others then
        null;
    end;
    if pool = 2 then
      --nonpool
      begin
        select u.rewashtotal,
               u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               n.weareremployment_id,
               w.customer_id,
               f.lastissuedate,
               u.stay_id,
               u.status_id,
               u.washestotal,
               u.customerowned,
               f.qualitygrade_id,
               e.locker_id,
               e.garmentdispenser_id,
               n.washesthisissue,
               n.rewashthisissue,
               e.distributionpoint_id,
               e.deliverypoint_id,
               u.planneddeliverydate
          into vrewashtotal,
               productid,
               sizeid,
               finishingmethodid,
               weareremploymentid,
               customerid,
               vissuedate,
               stayid,
               statusid,
               vwashestotal,
               vcustomerowned,
               qualitygradeid,
               lockerid,
               garmentdispenserid,
               vwashesthisissue,
               vrewashthisissue,
               distributionpointid,
               deliverypointid,
               planneddate
          from uniqueitem          u,
               uniqueitemnonpool   n,
               uniqueitemfixedinfo f,
               weareremployment    e,
               wearer              w
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = n.uniqueitem_id
           and n.weareremployment_id = e.weareremployment_id
           and e.wearer_id = w.wearer_id
           and u.uniqueitem_id = f.uniqueitem_id;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                  debuglevel,
                                  'PROCESSREWASSCAN',
                                  plantid_param,
                                  3,
                                  1);
      end;
    else
      --pool
      begin
        select u.relatedcustomer_id,
               u.rewashtotal,
               u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               f.lastissuedate,
               u.distributionpoint_id,
               u.lastdistributionpoint_link_id,
               u.stay_id,
               u.status_id,
               u.washestotal,
               u.customerowned,
               f.qualitygrade_id
          into customerid,
               vrewashtotal,
               productid,
               sizeid,
               finishingmethodid,
               vissuedate,
               distributionpointid,
               lastdistribpointid,
               stayid,
               statusid,
               vwashestotal,
               vcustomerowned,
               qualitygradeid
          from uniqueitem u, uniqueitemfixedinfo f
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = f.uniqueitem_id;
        if customerid is null then
          if distributionpointid is not null then
            select e.customer_id
              into customerid
              from distributionpoint d, department e
             where distributionpointid = d.distributionpoint_id
               and d.department_id = e.department_id;
          elsif lastdistribpointid is not null then
            select e.customer_link_id
              into customerid
              from distributionpoint_link d, department_link e
             where lastdistribpointid = d.distributionpoint_id
               and d.department_link_id = e.department_link_id;
          end if;
        end if;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                  debuglevel,
                                  'PROCESSREWASSCAN',
                                  plantid_param,
                                  3,
                                  1);
      end;
    end if;
    --stay, status
    vpreviousstay := stayid;
    select stay_id
      into stayid
      from stay
     where stay.staytype = 1
       and stay.staynr = 31; --rewash
    select status_id
      into assigned
      from status
     where status.statustype = 'UI'
       and status.code = '30'; --assigned
    select status_id
      into incirc
      from status
     where status.statustype = 'UI'
       and status.code = '20'; --in circulation
    --if status is not incirc or assigned then doesn't scan
    if statusid not in (assigned, incirc) then
      accept := 'N';
      pack_sort.write_logging('!> ' || idcode ||
                              ' not in circulation or assigned',
                              debuglevel,
                              'PROCESSREWASSCAN',
                              plantid_param,
                              3,
                              1);
    end if;
    if accept = 'Y' then
      begin
        vwashestotal := vwashestotal + 1;
        vrewashtotal := vrewashtotal + 1;
        if pool = 2 then
          vwashesthisissue := vwashesthisissue + 1;
          vrewashthisissue := vrewashthisissue + 1;
        end if;
        --plpc
        pack_sort.findplpcinfo(customerid,
                               productid,
                               sizeid,
                               finishingmethodid,
                               deliverymethod,
                               deedeliveryschemeid,
                               plpcid,
                               vmaxwashes,
                               plpcfinishingcode,
                               plpcustomcode,
                               plpcustomdescription,
                               pchargewashesonlyforcog,
                               pbillingmethod,
                               lv_treatmentcheckschemeid);
        --deliverypoint
        begin
          if deliverypointid is null and pool = 2 then
            if lockerid is not null then
              select l.deliverypoint_id
                into deliverypointid
                from locker l
               where l.locker_id = lockerid;
            elsif garmentdispenserid is not null then
              select g.deliverypoint_id
                into deliverypointid
                from garmentdispenser g
               where g.garmentdispenser_id = garmentdispenserid;
            end if;
          end if;
          if pool = 1 then
            begin
              select d.deliverypoint_id
                into deliverypointid
                from distributionpoint d
               where d.distributionpoint_id = distributionpointid;
            exception
              when no_data_found then
                null;
            end;
          end if;
        end;
        --  planned out date, planned out route
        -- HVH From here starts my change
        if pool = 1 then
          plannedroute := null;
          planneddate  := null;
        end if;
        if pool = 2 then
          if scanbyroute = 'Y' then
            -- only if planneddate was not determined yet then determine here
            discardcompletecheck := 'N';
            for vcursor in (select f.includeincompletnesscheck
                              from uniqueitemflag u, flag f
                             where u.uniqueitem_id = uniqueitemid
                               and u.flag_id = f.flag_id) loop
              if vcursor.includeincompletnesscheck = 'N' then
                begin
                  discardcompletecheck := 'Y';
                  exit;
                end;
              end if;
            end loop;
            if discardcompletecheck = 'N' then
              --uniqueitemroute
              select count(u.uniqueitem_id),
                     max(u.lastoutdate),
                     max(u.lastoutstop_id),
                     max(u.lastoutroute_id)
                into cnt,
                     lv_lastoutdate,
                     lv_lastoutstopid,
                     lv_lastoutrouteid
                from uniqueitemroute u
               where u.uniqueitem_id = uniqueitemid;
              if cnt > 0 and customerid is not null then
                -- SO 20014102
                ---maxwashes
                select p.typeofmerchandise
                  into vtypeofmerch
                  from product p
                 where p.product_id = productid;

                select uir.lastindate,
                       uir.lastinroute_id,
                       uir.lastinstop_id,
                       uir.lastoutdate,
                       uir.lastoutroute_id,
                       uir.lastoutstop_id
                  into lastdatein,
                       lastinroute,
                       instop_id,
                       planneddate,
                       plannedroute,
                       stopid
                  from uniqueitemroute uir
                 where uir.uniqueitem_id = uniqueitemid;

                if planneddate is null then
                  if deliverydetermination = 1 then
                    if (lv_lastoutdate is not null and
                       lv_lastoutdate >= trunc(sysdate)) and
                       (lv_lastoutstopid is not null) and
                       (lv_lastoutrouteid is not null) then

                      update uniqueitem ui
                         set ui.planneddeliverydate = planneddate
                       where ui.uniqueitem_id = uniqueitemid;

                    else
                      pack_deliverybasics.determinedeldateroutesoil(plantid_garment,
                                                                    customerid,
                                                                    deliverypointid,
                                                                    department_id,
                                                                    vtypeofmerch,
                                                                    vlastscandate,
                                                                    plpcid,
                                                                    distributionpointid,
                                                                    lv_log,
                                                                    lastinroute,
                                                                    routestopin,
                                                                    inroutecontrol_id,
                                                                    instop_id,
                                                                    lastdatein,
                                                                    plannedroute,
                                                                    routestopid,
                                                                    outroutecontrol_id,
                                                                    stopid,
                                                                    planneddate);
                    end if;
                  else
                    --get last in route
                    pack_sort.getlastinroute_debug(customerid,
                                             vlastscandate,
                                             deliverypointid,
                                             vtypeofmerch,
                                             plantid_garment,
                                             lastinroute,
                                             routestopin,
                                             lastdatein);
                    --planned out route
                    pack_sort.fillplannedoutroute(plantid_garment,
                                                  vlastscandate,
                                                  vtypeofmerch,
                                                  deliverymethod,
                                                  deedeliveryschemeid,
                                                  plpcid,
                                                  customerid,
                                                  deliverypointid,
                                                  lastinroute,
                                                  lastdatein,
                                                  routestopin,
                                                  routestopid,
                                                  plannedroute,
                                                  planneddate,
                                                  scanbyroute);
                  end if;
                elsif planneddate < trunc(sysdate) then
                  if deliverydetermination = 1 then
                    pack_deliverybasics.determinedeldaterouteclean(plantid_garment,
                                                                   customerid,
                                                                   deliverypointid,
                                                                   department_id,
                                                                   vtypeofmerch,
                                                                   vlastscandate,
                                                                   plpcid,
                                                                   distributionpointid,
                                                                   lv_log,
                                                                   routestopid,
                                                                   plannedroute,
                                                                   stopid,
                                                                   outroutecontrol_id,
                                                                   planneddate);

                  else
                    --planned out route
                    pack_sort.fillplannedoutroute(plantid_garment,
                                                  vlastscandate,
                                                  vtypeofmerch,
                                                  deliverymethod,
                                                  deedeliveryschemeid,
                                                  plpcid,
                                                  customerid,
                                                  deliverypointid,
                                                  lastinroute,
                                                  lastdatein,
                                                  routestopin,
                                                  routestopid,
                                                  plannedroute,
                                                  planneddate,
                                                  scanbyroute);
                  end if;
                end if;
                begin
                  insert into uniqueitemroute
                    (uniqueitem_id,
                     lastinroute_id,
                     lastoutroute_id,
                     plannedoutroute_id,
                     lastindate,
                     lastoutdate,
                     plannedoutdate,
                     systemuser_id,
                     timestamp,
                     lastinstop_id,
                     plannedoutstop_id)
                  values
                    (uniqueitemid,
                     lastinroute,
                     null,
                     plannedroute,
                     lastdatein,
                     null,
                     planneddate,
                     systemuserid,
                     sysdate,
                     instop_id,
                     stopid);
                  if debuglevel > 0 then
                    pack_sort.write_logging('IDCode ' || idcode ||
                                            ' insert into uniqueitem route uniqueitemid ' ||
                                            uniqueitemid,
                                            debuglevel,
                                            'PROCESSREWASSCAN',
                                            plantid_param,
                                            3,
                                            1);
                  end if;
                exception
                  when dup_val_on_index then
                    begin
                      update uniqueitemroute u
                         set u.lastinroute_id     = lastinroute,
                             u.plannedoutroute_id = plannedroute,
                             u.lastindate         = lastdatein,
                             u.plannedoutdate     = planneddate,
                             u.systemuser_id      = systemuserid,
                             u.timestamp          = sysdate,
                             lastinstop_id        = instop_id,
                             plannedoutstop_id    = stopid
                       where u.uniqueitem_id = uniqueitemid;
                      if debuglevel > 0 then
                        pack_sort.write_logging('IDCode ' || idcode ||
                                                ' update uniqueitem route uniqueitemid ' ||
                                                uniqueitemid,
                                                debuglevel,
                                                'PROCESSREWASSCAN',
                                                plantid_param,
                                                3,
                                                1);
                      end if;
                    end;
                end;
              end if; -- if scanbyroute=Y
            end if; -- if discardcompletecheck
          end if; -- if planneddate=null
        end if; -- if pool=2
        -- HVH End change
        --uniqueitem
        begin
          update uniqueitem u
             set u.lastscandate   = vlastscandatetime,
                 u.washestotal    = vwashestotal,
                 u.rewashtotal    = vrewashtotal,
                 u.prevstay_id    = vpreviousstay,
                 u.stay_id        = stayid,
                 u.staychangedate = vlastscandatetime,
                 u.systemuser_id  = systemuserid,
                 u.timestamp      = sysdate
           where u.uniqueitem_id = uniqueitemid;
          if debuglevel > 0 then
            pack_sort.write_logging('IDCode ' || idcode ||
                                    ' update uniqueitem uniqueitemid ' ||
                                    uniqueitemid,
                                    debuglevel,
                                    'PROCESSREWASSCAN',
                                    plantid_param,
                                    3,
                                    1);
          end if;
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSREWASSCAN',
                                    plantid_param,
                                    3,
                                    1);
        end;
        --update uniqueitem non pool
        begin
          update uniqueitemnonpool u
             set u.washesthisissue = vwashesthisissue,
                 u.rewashthisissue = vrewashthisissue,
                 u.systemuser_id   = systemuserid,
                 u.timestamp       = sysdate
           where u.uniqueitem_id = uniqueitemid;
          if debuglevel > 0 then
            pack_sort.write_logging('IDCode ' || idcode ||
                                    ' update uniqueitem nonpool uniqueitemid ' ||
                                    uniqueitemid,
                                    debuglevel,
                                    'PROCESSREWASSCAN',
                                    plantid_param,
                                    3,
                                    1);
          end if;
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSREWASSCAN',
                                    plantid_param,
                                    3,
                                    1);
        end;
        --scan record
        begin
          insert into scan
            (scan_id,
             businessunit_id,
             scantimestamp,
             primaryid,
             customer_link_id,
             weareremployment_link_id,
             distributionpoint_link_id,
             product_link_id,
             sizedefinition_link_id,
             stay_id,
             status_id,
             scanstation,
             issuedate,
             route_id,
             reasoncode_id,
             customerowned,
             year,
             week,
             dayno,
             qualitygrade_id,
             systemuser_id,
             timestamp,
             prevstay_id,
             transactiontype_id,
             dayslate,
             uniqueitem_link_id,
             secondaryid)
          values
            (seq_scan.nextval,
             businessunitid,
             vlastscandate,
             idcode,
             customerid,
             weareremploymentid,
             distributionpointid,
             productid,
             sizeid,
             stayid,
             statusid,
             workstationcode,
             vissuedate,
             lastinroute,
             null,
             vcustomerowned,
             vyear,
             vweek,
             vdayno,
             qualitygradeid,
             systemuserid,
             sysdate,
             vpreviousstay,
             transactiontp,
             0,
             uniqueitemid,
             secondaryid)
          returning scan_id into vscanid;
          if debuglevel > 0 then
            pack_sort.write_logging('IDCode ' || idcode ||
                                    ' insert scan for uniqueitemid ' ||
                                    uniqueitemid,
                                    debuglevel,
                                    'PROCESSREWASSCAN',
                                    plantid_param,
                                    3,
                                    1);
          end if;
          if lv_use_treatmentcheck = '0' then
            begin
              ---maxwashes
              select p.maxwashes, p.typeofmerchandise
                into productmaxwashes, vtypeofmerch
                from product p
               where p.product_id = productid;
              if vmaxwashes = 0 then
                vmaxwashes := productmaxwashes;
              end if;
              select flag_id
                into flagid
                from automaticflag a
               where a.automaticflag_id = 1;
              if vmaxwashes <= vwashestotal and vmaxwashes != 0 then
                flaginserted := pack_sort.create_uniqueitemflag('PACK_SORT.PROCESSREWASH',
                                                                debuglevel,
                                                                systemuserid,
                                                                uniqueitemid,
                                                                flagid,
                                                                vlastscandate,
                                                                null,
                                                                null,
                                                                null,
                                                                plantid_param);
              end if;
            end;
          else
            add_treatmentcheck_flags(debuglevel,
                                     systemuserid,
                                     uniqueitemid,
                                     vlastscandate,
                                     vscanid,
                                     null,
                                     lv_treatmentcheckschemeid,
                                     vwashestotal,
                                     plantid_param,
                                     productid,
                                     plpcid);
          end if;
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSREWASSCAN',
                                    plantid_param,
                                    3,
                                    1);
        end;
        -- MBA td 9345 - insert also scanflag if flag1/2/3/4 is provided
        if (vscanid > 0 and (flagcode1 is not null or flagcode2 is not null or
           flagcode3 is not null or flagcode4 is not null)) then
          createscanflag(vscanid,
                         systemuserid,
                         debuglevel,
                         flagcode1,
                         flagcode2,
                         flagcode3,
                         flagcode4,
                         plantid_param);
        end if;
        if (vscanid > 0) then
          add_scanflag(vscanid,
                       uniqueitemid,
                       'RewashScan',
                       plantid_garment,
                       systemuserid);
        end if;
        -- end td 9345
      end; --for accept='Y'
    end if; --for accept='Y'
  end processrewash;
  procedure processsortscan(transactiontp   in sortingimportdefinition.transactiontype%type,
                            idcode          in uniqueitem.primaryid%type,
                            pool            in integer,
                            secondaryid     in secondaryuniqueitem.secondaryid%type,
                            businessunitid  in businessunit.businessunit_id%type,
                            uniqueitemid    in uniqueitem.uniqueitem_id%type,
                            workstationcode in workstation.code%type,
                            datep           in number,
                            timep           in varchar2,
                            systemuserid    in systemuser.systemuser_id%type,
                            debuglevel      in integer,
                            accept          out varchar2,
                            flagcode1       in sortaddressperflag.sortaddress%type default null,
                            flagcode2       in sortaddressperflag.sortaddress%type default null,
                            flagcode3       in sortaddressperflag.sortaddress%type default null,
                            flagcode4       in sortaddressperflag.sortaddress%type default null,
                            fpbatchnumber   in scan.batchnumber%type default null) is
    stayid              stay.stay_id%type;
    statusid            status.status_id%type;
    assigned            status.status_id%type;
    incirc              status.status_id%type;
    productid           product.product_id%type;
    sizeid              sizedefinition.sizedefinition_id%type;
    weareremploymentid  weareremployment.weareremployment_id%type;
    customerid          customer.customer_id%type;
    vissuedate          date;
    finishingmethodid   finishingmethod.finishingmethod_id%type;
    distributionpointid distributionpoint.distributionpoint_id%type;
    lastdistribpointid  distributionpoint_link.distributionpoint_link_id%type;
    vlastscandate       date;
    vlastscandatetime   timestamp;
    vpreviousstay       stay.stay_id%type;
    vwashestotal        integer;
    vyear               integer;
    vweek               integer;
    vdayno              integer;
    vcustomerowned      varchar2(1);
    routeid             route.route_id%type;
    vscanid             scanflag.scan_id%type; -- MBA td 9345
    lvplantid           plant.plant_id%type;
  begin
    select b.plant_id
      into lvplantid
      from businessunit b
     where b.businessunit_id = businessunitid;

    accept            := 'Y';
    vlastscandate     := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vlastscandatetime := to_timestamp(to_char(datep) || to_char(timep),
                                      'YYYYMMDDHH24MISS');
    vyear             := getyearofweek(vlastscandate);
    vweek             := getisoweek(vlastscandate);
    vdayno            := getabsdaynumber(vlastscandate);
    vscanid           := 0;
    if pool = 2 then
      --nonpool
      begin
        select u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               n.weareremployment_id,
               w.customer_id,
               f.lastissuedate,
               u.stay_id,
               u.status_id,
               u.washestotal,
               u.customerowned,
               e.distributionpoint_id
          into productid,
               sizeid,
               finishingmethodid,
               weareremploymentid,
               customerid,
               vissuedate,
               stayid,
               statusid,
               vwashestotal,
               vcustomerowned,
               distributionpointid
          from uniqueitem          u,
               uniqueitemnonpool   n,
               uniqueitemfixedinfo f,
               weareremployment    e,
               wearer              w
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = n.uniqueitem_id
           and n.weareremployment_id = e.weareremployment_id
           and e.wearer_id = w.wearer_id
           and u.uniqueitem_id = f.uniqueitem_id;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                  debuglevel,
                                  'PROCESSSORTSCAN',
                                  null,
                                  3,
                                  1);
      end;
    else
      --pool
      begin
        select u.relatedcustomer_id,
               u.product_id,
               u.sizedefinition_id,
               u.finishingmethod_id,
               f.lastissuedate,
               u.distributionpoint_id,
               u.stay_id,
               u.status_id,
               u.washestotal,
               u.customerowned
          into customerid,
               productid,
               sizeid,
               finishingmethodid,
               vissuedate,
               distributionpointid,
               stayid,
               statusid,
               vwashestotal,
               vcustomerowned
          from uniqueitem u, uniqueitemfixedinfo f
         where u.uniqueitem_id = uniqueitemid
           and u.uniqueitem_id = f.uniqueitem_id;
        if customerid is null then
          if distributionpointid is not null then
            select e.customer_id
              into customerid
              from distributionpoint d, department e
             where distributionpointid = d.distributionpoint_id
               and d.department_id = e.department_id;
          elsif lastdistribpointid is not null then
            select e.customer_link_id
              into customerid
              from distributionpoint_link d, department_link e
             where lastdistribpointid = d.distributionpoint_id
               and d.department_link_id = e.department_link_id;
          end if;
        end if;
      exception
        when no_data_found then
          accept := 'N';
          pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                  debuglevel,
                                  'PROCESSSORTSCAN',
                                  lvplantid,
                                  3,
                                  1);
      end;
    end if;
    --stay, status
    vpreviousstay := stayid;
    select stay_id
      into stayid
      from stay
     where stay.staytype = 1
       and stay.staynr = 34; --Sorted
    select status_id
      into assigned
      from status
     where status.statustype = 'UI'
       and status.code = '30'; --assigned
    select status_id
      into incirc
      from status
     where status.statustype = 'UI'
       and status.code = '20'; --in circulation
    --if status is not incirc or assigned then doesn't scan
    if statusid not in (assigned, incirc) then
      accept := 'N';
      pack_sort.write_logging('!> ' || idcode || ' ' ||
                              ' Status not in circulation or assigned for IDcode ',
                              debuglevel,
                              'PROCESSSORTSCAN',
                              lvplantid,
                              3,
                              1);
    end if;
    if accept = 'Y' then
      begin
        begin
          update uniqueitem u
             set u.lastscandate   = vlastscandatetime,
                 u.prevstay_id    = vpreviousstay,
                 u.stay_id        = stayid,
                 u.staychangedate = vlastscandatetime,
                 u.systemuser_id  = systemuserid,
                 u.timestamp      = sysdate
           where u.uniqueitem_id = uniqueitemid;
          if debuglevel > 0 then
            pack_sort.write_logging('ID code ' || idcode ||
                                    ' update uniqueitem ' || uniqueitemid,
                                    debuglevel,
                                    'PROCESSSORTSCAN',
                                    lvplantid,
                                    1,
                                    1);
          end if;
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSSORTSCAN',
                                    lvplantid,
                                    3,
                                    1);
        end;
        --scan record
        begin
          select nvl(u.plannedoutroute_id,u.lastoutroute_id)
            into routeid
            from uniqueitemroute u
           where u.uniqueitem_id = uniqueitemid;
        exception
          when no_data_found then
            routeid := null;
        end;
        begin
          insert into scan
            (scan_id,
             businessunit_id,
             scantimestamp,
             primaryid,
             customer_link_id,
             weareremployment_link_id,
             distributionpoint_link_id,
             product_link_id,
             sizedefinition_link_id,
             stay_id,
             status_id,
             scanstation,
             issuedate,
             route_id,
             reasoncode_id,
             customerowned,
             year,
             week,
             dayno,
             qualitygrade_id,
             systemuser_id,
             timestamp,
             prevstay_id,
             transactiontype_id,
             dayslate,
             uniqueitem_link_id,
             secondaryid,
             batchnumber)
          values
            (seq_scan.nextval,
             businessunitid,
             vlastscandate,
             idcode,
             customerid,
             weareremploymentid,
             distributionpointid,
             productid,
             sizeid,
             stayid,
             statusid,
             workstationcode,
             vissuedate,
             routeid,
             null,
             vcustomerowned,
             vyear,
             vweek,
             vdayno,
             null,
             systemuserid,
             sysdate,
             vpreviousstay,
             transactiontp,
             0,
             uniqueitemid,
             secondaryid,
             fpbatchnumber)
          returning scan_id into vscanid;
          if debuglevel > 0 then
            pack_sort.write_logging('ID code ' || idcode ||
                                    ' insert scan uniqueitem ' ||
                                    uniqueitemid,
                                    debuglevel,
                                    'PROCESSSORTSCAN',
                                    lvplantid,
                                    1,
                                    1);
          end if;
          -- MBA td 9345
        exception
          when others then
            accept := 'N';
            pack_sort.write_logging('!> ' || idcode || ' ' || sqlerrm,
                                    debuglevel,
                                    'PROCESSSORTSCAN',
                                    lvplantid,
                                    3,
                                    1);
        end;
        -- MBA td 9345 - insert also scanflag if flag1/2/3/4 is provided
        if (vscanid > 0 and (flagcode1 is not null or flagcode2 is not null or
           flagcode3 is not null or flagcode4 is not null)) then
          createscanflag(vscanid,
                         systemuserid,
                         debuglevel,
                         flagcode1,
                         flagcode2,
                         flagcode3,
                         flagcode4,
                         lvplantid);
        end if;
        if (vscanid > 0) then
          add_scanflag(vscanid,
                       uniqueitemid,
                       'CheckPointScan',
                       lvplantid,
                       systemuserid);
        end if;
        -- end td 9345
      end; --for accept='Y'
    end if; --for accept='Y'
  end processsortscan;
  function iscustomeractive(customerid   customer.customer_id%type,
                            specificdate date) return boolean is
    activ customer.active%type;
  begin
    select c.active
      into activ
      from customer c
     where c.customer_id = customerid
       and c.active = 'Y'
       and c.dateactive <= specificdate;
    --and    c.dateinactive >= specificdate; TD 25261
    return true;
  exception
    when others then
      return false;
  end iscustomeractive;
  function getstopstatus(customerid   customer.customer_id%type,
                         specificdate date) return number is
    status number;
  begin
    status := -1;
    select decode((c.dateinactive - specificdate) -
                  abs(c.dateinactive - specificdate),
                  0,
                  0,
                  4)
      into status
      from customer c
     where c.customer_id = customerid
       and c.active = 'Y'
       and c.dateactive <= specificdate;
    return status;
  exception
    when others then
      return - 1;
  end getstopstatus;
  procedure importsoilscan(fpnplantid      plant.plant_id%type,
                           fpsreadfilename varchar2) is
    lvnsystemuserid       systemuser.systemuser_id%type;
    lvsplantcode          plant.code%type;
    lvsworkstationcode    workstation.code%type;
    lvninscanhourinterval number;
    lvslogdir             systemsetting.value%type;
    lvsreaddir            systemsetting.value%type;
    lvhreadfile           utl_file.file_type;
    lvsreadline           varchar2(4000);
    lvnposition           number;
    lvserror              varchar2(155);
    lvsbarcode            uniqueitem.primaryid%type;
    lvnuniqueid           uniqueitem.uniqueitem_id%type;
    lvnsecondaryid        secondaryuniqueitem.uniqueitem_id%type;
    lvnbusinessunitid     businessunit.businessunit_id%type;
    lvdtpickupdate        date;
    lvdtscandate          date;
    lvdtlastscandate      uniqueitem.lastscandate%type;
    lvdtlastinscandate    uniqueitem.lastinscandate%type;
    lvsstatuscode         status.code%type;
    lvnstaynr             stay.staynr%type;
    lvsaccept             varchar2(1);
    lvndebuglevel         integer := 0;
    lvsscaninterval       varchar2(1);
    lvsscanbyroute        varchar2(1) := 'Y';
    lvscountwashesat      varchar2(1) := 'Y';
    lvuserexception exception;
  begin
    --get systemuser
    lvserror := 'Error getting the sytem user';
    begin
      select s.systemuser_id
        into lvnsystemuserid
        from systemuser s
       where s.username = 'SORT';
    exception
      when no_data_found then
        select min(systemuser_id) into lvnsystemuserid from systemuser;
    end;
    --get plant id
    lvserror := 'Plant id ' || fpnplantid;
    select p.code
      into lvsplantcode
      from plant p
     where p.plant_id = fpnplantid;
    --get workstation
    lvserror := 'Error getting the inscan workstation for plant ' ||
                lvsplantcode;
    select min(w.code)
      into lvsworkstationcode
      from sortingimportdefinition s, workstation w
     where s.plant_id = fpnplantid
       and s.transactiontype = 1
       and s.workstation_id = w.workstation_id;
    --get inscan hour interval for plant
    lvserror := 'INSCANALLOWHOURINTERVAL for plant ' || lvsplantcode;
    select to_number(trim(s.value))
      into lvninscanhourinterval
      from systemsetting s
     where s.name = 'INSCANALLOWHOURINTERVAL'
       and s.plant_id = fpnplantid;
    --get log file
    lvserror := 'Getting DATABASELOGDIR for plant ' || lvsplantcode;
    select s.value
      into lvslogdir
      from systemsetting s
     where s.name = 'DATABASELOGDIR'
       and s.plant_id = fpnplantid;
    --get soil scan file
    lvserror := 'opening processimportsoilscans.log in directory ' ||
                lvslogdir || ' for plant ' || lvsplantcode;
    lvserror := 'Getting IMPDIRSOILSCANORACLE for plant ' || lvsplantcode;
    select s.value
      into lvsreaddir
      from systemsetting s
     where s.name = 'IMPDIRSOILSCANORACLE'
       and s.plant_id = fpnplantid;
    lvserror    := 'opening ' || fpsreadfilename ||
                   ' for reading in directory ' || lvsreaddir ||
                   ' for plant ' || lvsplantcode;
    lvhreadfile := utl_file.fopen(lvsreaddir, fpsreadfilename, 'r');
    --getting system settings
    lvserror := 'Getting system settings for plant ' || lvsplantcode;
    begin
      select substr(trim(s.value), 1, 1)
        into lvscountwashesat
        from systemsetting s
       where s.name = 'COUNTWASHESAT'
         and s.plant_id = fpnplantid;
    exception
      when no_data_found then
        lvscountwashesat := 'N';
    end;
    begin
      select substr(trim(s.value), 1, 1)
        into lvsscanbyroute
        from systemsetting s
       where s.plant_id = fpnplantid
         and s.name = 'SCANBYROUTE';
    exception
      when no_data_found then
        lvsscanbyroute := 'Y';
    end;
    --process fpsreadfilename file
    lvserror := 'reading ' || fpsreadfilename || ' reading in directory ' ||
                lvsreaddir || ' for plant ' || lvsplantcode;
    loop
      begin
        begin
          -- get line from file.
          utl_file.get_line(lvhreadfile, lvsreadline);
        exception
          when no_data_found then
            exit;
        end;
        --get barcode
        lvnposition := instr(lvsreadline, '''') - 1;
        lvsbarcode  := substr(lvsreadline, 1, lvnposition);
        lvserror    := 'None pool chipcode ' || lvsbarcode || ' for plant ' ||
                       lvsplantcode;
        select u.uniqueitem_id,
               u.businessunit_id,
               st.code,
               sy.staynr,
               u.lastscandate,
               u.lastinscandate
          into lvnuniqueid,
               lvnbusinessunitid,
               lvsstatuscode,
               lvnstaynr,
               lvdtlastscandate,
               lvdtlastinscandate
          from uniqueitem u, businessunit bu, status st, stay sy
         where u.primaryid = lvsbarcode
           and u.poolitem = 2
           and u.businessunit_id = bu.businessunit_id
           and bu.plant_id = fpnplantid
           and u.status_id = st.status_id
           and u.stay_id = sy.stay_id;
        --secondaryID
        begin
          select s.secondaryid
            into lvnsecondaryid
            from secondaryuniqueitem s
           where s.uniqueitem_id = lvnuniqueid;
        exception
          when no_data_found then
            null;
        end;
        --get pickup date
        lvserror       := 'invalid pickupdate for chipcode ' || lvsbarcode;
        lvdtpickupdate := to_date(substr(lvsreadline, lvnposition + 4, 10),
                                  'yyyy-mm-dd');
        --get scan date
        lvserror     := 'invalid scandate/time for chipcode ' || lvsbarcode;
        lvdtscandate := to_date(substr(lvsreadline, lvnposition + 17, 10) ||
                                substr(lvsreadline, lvnposition + 30, 8),
                                'yyyy-mm-dd hh24:mi:ss');
        --check barcode status
        if lvsstatuscode not in ('20', '30') then
          begin
            lvserror := 'Chipcode ' || lvsbarcode || ' has wrong status ' ||
                        lvsstatuscode;
            raise lvuserexception;
          end;
        end if;
        --check barcode last scandate with lastscandate
        if lvdtlastscandate > lvdtscandate then
          begin
            lvserror := 'Chipcode ' || lvsbarcode ||
                        ' has been scanned already';
            raise lvuserexception;
          end;
        end if;
        --check inscan hour interval
        if lvninscanhourinterval > 0 and lvdtlastinscandate is not null and
           lvnstaynr = 30 and (lvdtlastinscandate +
           (lvninscanhourinterval / 24)) > lvdtscandate then
          begin
            lvserror := 'Chipcode ' || lvsbarcode ||
                        ' has been scanned in less then ' ||
                        lvninscanhourinterval || ' hours before';
            raise lvuserexception;
          end;
        end if;
        --barcode is ok to be processed
        lvserror := 'Error during pack_sort.processinscan for barcode ' ||
                    lvsbarcode;
        pack_sort.processinscan(1,
                                lvsbarcode,
                                2,
                                lvnsecondaryid,
                                fpnplantid,
                                fpnplantid,
                                lvnbusinessunitid,
                                lvnuniqueid,
                                lvsworkstationcode,
                                to_number(to_char(lvdtscandate, 'YYYYMMDD')),
                                to_char(lvdtscandate, 'HH24MISS'),
                                lvscountwashesat,
                                lvsscanbyroute,
                                lvnsystemuserid,
                                lvndebuglevel,
                                lvsaccept,
                                lvsscaninterval,
                                lvdtpickupdate);
        commit;
      exception
        when lvuserexception then
          begin
            rollback;
            dbms_output.put_line(lvserror);
          end;
        when no_data_found then
          begin
            rollback;
            lvserror := lvserror || ' does not exist.';
            dbms_output.put_line(lvserror);
          end;
        when others then
          begin
            rollback;
            lvserror := lvserror || ' ' || substr(sqlerrm, 1, 200);
            dbms_output.put_line(lvserror);
          end;
      end;
    end loop;
  exception
    when utl_file.invalid_path then
      begin
        lvserror := lvserror || ' Invalid Path';
        dbms_output.put_line(lvserror);
      end;
    when utl_file.invalid_mode then
      begin
        lvserror := lvserror || ' Invalid Mode';
        dbms_output.put_line(lvserror);
      end;
    when utl_file.invalid_operation then
      begin
        lvserror := lvserror || ' Invalid Operation';
        dbms_output.put_line(lvserror);
      end;
    when utl_file.invalid_filehandle then
      begin
        lvserror := lvserror || ' Invalid Filehandle';
        dbms_output.put_line(lvserror);
      end;
    when utl_file.write_error then
      begin
        lvserror := lvserror || ' Write Error';
        dbms_output.put_line(lvserror);
      end;
    when utl_file.read_error then
      begin
        lvserror := lvserror || ' Read Error';
        dbms_output.put_line(lvserror);
      end;
    when utl_file.internal_error then
      begin
        lvserror := lvserror || ' Internal Error';
        dbms_output.put_line(lvserror);
      end;
    when no_data_found then
      begin
        rollback;
        lvserror := lvserror || ' does not exist.';
        dbms_output.put_line(lvserror);
      end;
    when others then
      begin
        rollback;
        lvserror := lvserror || ' ' || substr(sqlerrm, 1, 200);
        dbms_output.put_line(lvserror);
      end;
  end importsoilscan;
  function getsortstringsupport(plantid      in plant.plant_id%type,
                                customerid   in customer.customer_id%type,
                                routestopid  in routestop.routestop_id%type,
                                uniqueitemid in uniqueitem.uniqueitem_id%type)
    return varchar2 is
    sortstring           varchar2(255);
    productcode          product.code%type;
    sizecode             sizedefinition.code%type;
    customernumber       customer.customernumber%type;
    wearernumber         wearer.wearernumber%type;
    wearername           wearer.searchname%type;
    banklocker           varchar2(12);
    departmentnumber     department.departmentnumber%type;
    customeremployee#    wearer.customeremployeenumber%type;
    gender               wearer.sex%type;
    garmentdispensercode garmentdispenser.code%type;
    deliverypointcode    deliverypoint.code%type;
    lockerid             locker.locker_id%type;
    garmentdispenserid   garmentdispenser.garmentdispenser_id%type;
    deliverypointid      deliverypoint.deliverypoint_id%type;
    stopnumber           routestop.stopnumber%type;
    routenumber          route.routenumber%type;
    packingsequence      product.packingsequence%type;
    vcustomerowned       varchar2(1);
    settingsortroutestop varchar2(1);
  begin
    sortstring := '';
    begin
      begin
        select p.code,
               s.code,
               c.customernumber,
               w.wearernumber,
               w.searchname,
               w.customeremployeenumber,
               w.sex,
               d.departmentnumber,
               e.deliverypoint_id,
               e.locker_id,
               e.garmentdispenser_id,
               p.packingsequence,
               u.customerowned
          into productcode,
               sizecode,
               customernumber,
               wearernumber,
               wearername,
               customeremployee#,
               gender,
               departmentnumber,
               deliverypointid,
               lockerid,
               garmentdispenserid,
               packingsequence,
               vcustomerowned
          from uniqueitem        u,
               uniqueitemnonpool n,
               weareremployment  e,
               wearer            w,
               customer          c,
               department        d,
               distributionpoint di,
               product           p,
               sizedefinition    s
         where u.uniqueitem_id = uniqueitemid
           and u.product_id = p.product_id
           and u.sizedefinition_id = s.sizedefinition_id
           and u.uniqueitem_id = n.uniqueitem_id
           and n.weareremployment_id = e.weareremployment_id
           and e.wearer_id = w.wearer_id
           and w.customer_id = c.customer_id
           and c.customer_id = customerid
           and e.distributionpoint_id = di.distributionpoint_id
           and di.department_id = d.department_id;
      exception
        when no_data_found then
          sortstring := '01';
      end;
      if sortstring is null then
        pack_sort.getgarmentlocation(lockerid,
                                     garmentdispenserid,
                                     deliverypointid,
                                     banklocker,
                                     garmentdispensercode,
                                     deliverypointcode);
        begin
          select rs.stopnumber, r.routenumber
            into stopnumber, routenumber
            from routestop rs, route r
           where rs.routestop_id = routestopid
             and r.route_id = rs.route_id;
        exception
          when no_data_found then
            sortstring := '02';
        end;
      end if;
      --read systemsettings
      if sortstring is null then
        begin
          select s.value
            into settingsortroutestop
            from systemsetting s
           where s.plant_id = plantid
             and s.name = 'SORTROUTESTOP';
          if settingsortroutestop = 'A' then
            sortstring := lpad(to_char(routenumber), 6, 0) ||
                          lpad(to_char(stopnumber), 4, 0);
          elsif settingsortroutestop = 'Z' then
            sortstring := lpad(to_char(stopnumber), 4, 0);
          elsif settingsortroutestop = 'D' then
            sortstring := lpad(to_char(routenumber), 6, 0) ||
                          lpad(to_char(9999 - stopnumber), 6, 0);
          end if;
        end;
      end if;
      sortstring := sortstring || lpad(customernumber, 12, 0);

      if banklocker is null then
        sortstring := sortstring || '            ';
      else
        sortstring := sortstring || banklocker;
      end if;

      sortstring := sortstring || lpad(to_char(wearernumber), 12, 0);

    exception
      when others then
        sortstring := '0';
    end;
    return(sortstring);
  end getsortstringsupport;

  procedure getnextdeliverydatewithstop(currentdate     in date,
                                        plantid         in plant.plant_id%type,
                                        customerid      in customer.customer_id%type,
                                        typeofmerch     in product.typeofmerchandise%type,
                                        deliverypointid in deliverypoint.deliverypoint_id%type,
                                        retvisitdate    out date,
                                        retroute        out route.route_id%type) is
    visitdate   date;
    routestopid number;
  begin

    for vcursor in (select c.day_id, d.deliveryscheme_id, x.frequency
                      from customerdeliveryday    c,
                           customerdeliveryscheme d,
                           deliveryscheme         x
                     where c.customer_id = customerid
                       and c.customer_id = d.customer_id
                       and c.day_id = d.day_id
                       and c.typeofmerchadise = typeofmerch
                       and c.deliverytype in ('B', 'D')
                       and d.deliveryscheme_id = x.deliveryscheme_id
                       and d.active = 'Y') loop
      begin
        visitdate   := pack_sort.getvisitdate(vcursor.deliveryscheme_id,
                                              vcursor.day_id,
                                              currentdate);
        routestopid := pack_sort.getroutestopforcustomer(plantid,
                                                         visitdate,
                                                         customerid,
                                                         deliverypointid);
        if visitdate is not null and routestopid is not null then
          begin
            retvisitdate := visitdate;
            select rs.route_id
              into retroute
              from routestop rs
             where rs.routestop_id = routestopid;
            EXIT;
          end;
        end if;
      end;
    end loop;

  end getnextdeliverydatewithstop;


  procedure processfakeinscanforgarments(
                              plantid_garment    in plant.plant_id%type,
                              businessunitid     in businessunit.businessunit_id%type,
                              idcode             in uniqueitem.primaryid%type,
                              uniqueitemid       in uniqueitem.uniqueitem_id%type,
                              secondaryid        in secondaryuniqueitem.secondaryid%type,
                              scanbyroute        in varchar2,
                              systemuserid       in systemuser.systemuser_id%type) is
    inscandate                  date;
    simulateinscan              systemsetting.value%type;
    doinscansimulation          integer := 0;
    wscodeforsimulateinscan     workstation.code%type;
    inroute                     route.route_id%type;
    stayid                      stay.stay_id%type;
    statusid                    status.status_id%type;
    productid                   product.product_id%type;
    sizeid                      sizedefinition.sizedefinition_id%type;
    finishingmethodid           finishingmethod.finishingmethod_id%type;
    lastoutscandate             date;
    weareremploymentid          weareremployment.weareremployment_id%type;
    customerid                  customer.customer_id%type;
    distributionpointid         distributionpoint.distributionpoint_id%type;
    vyear                       integer;
    vweek                       integer;
    vdayno                      integer;
    customerowned               varchar2(1);
    qualitygradeid              qualitygrade.qualitygrade_id%type;
    lastissuedate               date;
    inscanday                   integer;
    stayinscan                  integer;
    currentday                  integer;

    function change_date_if_saturday_or_sunday(inscandate in scan.scantimestamp%type)
      return scan.scantimestamp%type is
      inscanday day.daynumber%type;
    begin
      inscanday := getabsdaynumber(inscandate);
      if inscanday = 6 then
        return inscandate - 1;
      elsif inscanday = 7 then
        return inscandate - 2;
      else
        return inscandate;
      end if;
    end change_date_if_saturday_or_sunday;

  begin
   begin
      select s.value
        into simulateinscan
        from systemsetting s
       where s.plant_id = plantid_garment
         and s.name = 'SIMULATEINSCAN';
     exception
      when others then
        simulateinscan := 0;
    end;

   if simulateinscan > 0 then
      begin
        select 1
          into doinscansimulation
          from uniqueitemnonpool uin
         where uin.uniqueitem_id = uniqueitemid;
      exception
        when no_data_found then
          doinscansimulation := 0;
      end;
    end if;

    if doinscansimulation > 0 then
      begin
           select w.code
             into wscodeforsimulateinscan
             from workstation w join  workstationextrainfo wei
                  on w.workstation_id = wei.workstation_id
             where w.plant_id = plantid_garment
             and wei.simulateinscangarments = 'Y'
             and rownum < 2;
      exception
        when no_data_found then
          wscodeforsimulateinscan := null;
      end;
    end if;

   if wscodeforsimulateinscan is not null then
      begin
        with outscaninfo as
         (select case
                 when max(s.scantimestamp)is null then
                   sysdate - 14
                  else max(s.scantimestamp)
                    end  outscantimestamp
            from scan s
           where s.primaryid = idcode
             and s.transactiontype_id = 2
             and s.uniqueitem_link_id = uniqueitemid
             and trunc(s.scantimestamp) < trunc(sysdate))
        select nvl(max(0), 1)
          into doinscansimulation
          from scan s1, outscaninfo
         where s1.primaryid = idcode
           and s1.transactiontype_id = 1
           and s1.uniqueitem_link_id = uniqueitemid
           and s1.scantimestamp >= outscaninfo.outscantimestamp;
      exception
        when no_data_found then
          null;
      end;
    end if;

    if doinscansimulation = 1 and wscodeforsimulateinscan is not null then
      begin
        select
           u.product_id,
           u.sizedefinition_id,
           u.finishingmethod_id,
           u.status_id,
           u.customerowned,
           u.lastoutscandate,
           u.stay_id,
           f.qualitygrade_id,
           f.lastissuedate,
           n.weareremployment_id,
           e.distributionpoint_id,
           w.customer_id
        into
           productid,
           sizeid,
           finishingmethodid,
           statusid,
           customerowned,
           lastoutscandate,
           stayid,
           qualitygradeid,
           lastissuedate,
           weareremploymentid,
           distributionpointid,
           customerid
        from uniqueitem u
        join uniqueitemfixedinfo f
          on (f.uniqueitem_id = u.uniqueitem_id)
        join (uniqueitemnonpool n
        join weareremployment e
          on e.weareremployment_id = n.weareremployment_id
        join wearer w
          on w.wearer_id = e.wearer_id) on (n.uniqueitem_id = u.uniqueitem_id)
       where u.uniqueitem_id = uniqueitemid
         and u.deliveryfromstock = 'N';
      exception
        when no_data_found then
             doinscansimulation := 0;
      end;
    end if;

   if doinscansimulation = 1 and wscodeforsimulateinscan is not null then
    currentday  := getabsdaynumber(sysdate);
    select max(c.day_id) into inscanday
                        from customerdeliveryday c
                       where c.customer_id = customerid
                         and c.typeofmerchadise = 2
                         and c.day_id < currentday;
     if inscanday is not null then
        inscandate := trunc(sysdate) - (currentday - inscanday);
     else
        select max(c.day_id) into inscanday
                        from customerdeliveryday c
                       where c.customer_id = customerid
                         and c.typeofmerchadise = 2
                         and c.day_id > currentday;
        if inscanday is not null then
           inscandate := trunc(sysdate) - 7 - currentday + inscanday;
         else
          inscandate := trunc(sysdate) - 7;
         end if;
     end if;

     inscandate := change_date_if_saturday_or_sunday(inscandate);
     if lastoutscandate is not null and trunc(inscandate) < trunc(lastoutscandate) then
        inscandate := change_date_if_saturday_or_sunday(sysdate);
     end if;

    vyear             := getyearofweek(inscandate);
    vweek             := getisoweek(inscandate);
    vdayno            := getabsdaynumber(inscandate);

    with calculateinscandate as
     (select to_date( to_char( trunc(inscandate), ' MM/DD/YYYY') || '07:30:00', 'MM/DD/YYYY HH24:mi:SS') min_date,
             CASE
               WHEN trunc(inscandate) = trunc(sysdate) THEN
                 sysdate
               ELSE
                 to_date( to_char( trunc(inscandate), ' MM/DD/YYYY') || '16:30:00', 'MM/DD/YYYY HH24:mi:SS')
             END AS max_date
       from dual
     )
    select min_date + dbms_random.value(low => 0, high => max_date - min_date) into inscandate
    from calculateinscandate;

    select st.stay_id into stayinscan from stay st where st.staytype = 1 and st.staynr = 30;

    begin
        update uniqueitem ui
        set ui.prevstay_id = ui.stay_id
          , ui.stay_id = stayinscan
          , ui.staychangedate = inscandate
          , ui.lastinscandate = inscandate
          , ui.lastscandate = inscandate
          , ui.planneddeliverydate = getnextdeliverydate(sysdate, customerid, 2)
        where ui.uniqueitem_id = uniqueitemid;
      exception
      when others then
        null;
      end;
      begin
          select rc.route_id into inroute from routecontrol rc, stop s
             where s.routecontrol_id = rc.routecontrol_id
              and rc.drivingdate = inscandate
              and s.customer_link_id = customerid;
       exception
       when no_data_found then
         null;
       end;

      begin
      if scanbyroute = 'Y' then
        update uniqueitemroute uir
        set uir.lastinroute_id = inroute, uir.lastindate = inscandate
        where uir.uniqueitem_id = uniqueitemid;
      end if;
      exception
        when others then
          null;
      end;
     begin
      insert into scan
                      (scan_id,
                       businessunit_id,
                       scantimestamp,
                       primaryid,
                       customer_link_id,
                       weareremployment_link_id,
                       distributionpoint_link_id,
                       product_link_id,
                       sizedefinition_link_id,
                       stay_id,
                       status_id,
                       scanstation,
                       issuedate,
                       route_id,
                       reasoncode_id,
                       customerowned,
                       year,
                       week,
                       dayno,
                       qualitygrade_id,
                       systemuser_id,
                       timestamp,
                       prevstay_id,
                       transactiontype_id,
                       dayslate,
                       uniqueitem_link_id,
                       secondaryid)
                    values
                      (seq_scan.nextval,
                       businessunitid,
                       inscandate,
                       idcode,
                       customerid,
                       weareremploymentid,
                       distributionpointid,
                       productid,
                       sizeid,
                       stayinscan,
                       statusid,
                       wscodeforsimulateinscan,
                       lastissuedate,
                       inroute,
                       null,
                       customerowned,
                       vyear,
                       vweek,
                       vdayno,
                       qualitygradeid,
                       systemuserid,
                       sysdate,
                       stayid,
                       1,
                       0,
                       uniqueitemid,
                       secondaryid);
       exception
         when dup_val_on_index then
           null;
        end;
    end if;
  end processfakeinscanforgarments;
  procedure processonsiteinvetoryscan(transactiontp       in sortingimportdefinition.transactiontype%type,
                                      idcode              in uniqueitem.primaryid%type,
                                      businessunitid      in businessunit.businessunit_id%type,
                                      plantid             in plant.plant_id%type default null,
                                      uniqueitemid        in uniqueitem.uniqueitem_id%type,
                                      workstationcode     in workstation.code%type,
                                      gv_lastscandatetime in varchar2,
                                      systemuserid        in systemuser.systemuser_id%type,
                                      debuglevel          in integer,
                                      accept              out varchar2) is
    lv_stayatcustomer stay.stay_id%type;
    lv_uniqueitem     uniqueitem%rowtype;
    lv_uniquenonpool  uniqueitemnonpool%rowtype;
    lv_secondaryid    secondaryuniqueitem.secondaryid%type;
    lv_week           number;
    lv_day            number;
    lv_customer       number;
    m_message         varchar2(1000);
  begin
    accept := 'Y';
    begin
      --update uniqueitem
      m_message := 'Get stay nr 1 / 20 at customer';
      select st.stay_id
        into lv_stayatcustomer
        from stay st
       where st.staytype = 1
         and st.staynr = 27;
    end;
    m_message := 'update uniqueitem';
    update uniqueitem ui
       set ui.lastscandate = gv_lastscandatetime, ui.prevstay_id = ui.stay_id, ui.stay_id = lv_stayatcustomer,
           ui.staychangedate = gv_lastscandatetime,
           ui.systemuser_id = systemuserid,
           ui.timestamp = sysdate
     where ui.uniqueitem_id = uniqueitemid;
    m_message := 'update uniqueitem';
    select *
      into lv_uniqueitem
      from uniqueitem ui
     where ui.uniqueitem_id = uniqueitemid;
    m_message := 'get uniqueitemnonpool info';
    select *
      into lv_uniquenonpool
      from uniqueitemnonpool up
     where up.uniqueitem_id = uniqueitemid;
    begin
      m_message := 'get secondaryid';
      select s.secondaryid
        into lv_secondaryid
        from secondaryuniqueitem s
       where s.uniqueitem_id = uniqueitemid;
    exception
      when no_data_found then
        lv_secondaryid := null;
    end;
    m_message := 'get customer_id';
    select dep.customer_id
      into lv_customer
      from department dep, distributionpoint dp, weareremployment w
     where dep.department_id = dp.department_id
       and w.distributionpoint_id = dp.distributionpoint_id
       and w.weareremployment_id = lv_uniquenonpool.weareremployment_id;
    m_message := 'get weekno';
    lv_week := getisoweek(gv_lastscandatetime);
    lv_day  := getabsdaynumber(gv_lastscandatetime);
  --create scan record
  m_message := 'create scan record for idcode ' || idcode || ' workstation ' || workstationcode;
  insert into scan
    (scan_id, businessunit_id, scantimestamp, primaryid, customer_link_id, weareremployment_link_id,
     distributionpoint_link_id, product_link_id, sizedefinition_link_id, stay_id, status_id, scanstation, issuedate,
     route_id, reasoncode_id, customerowned, year, week, dayno, qualitygrade_id, systemuser_id, timestamp, prevstay_id,
     transactiontype_id, dayslate, uniqueitem_link_id, secondaryid, batchnumber, scandateoffset, qualitytesttype_id,
     washingprocess_id, treatmenttype_id, deliverynotenumber)
  values
    (seq_scan.nextval, businessunitid, gv_lastscandatetime, lv_uniqueitem.primaryid, lv_customer,
     lv_uniquenonpool.weareremployment_id, lv_uniqueitem.distributionpoint_id, lv_uniqueitem.product_id,
     lv_uniqueitem.sizedefinition_id, lv_uniqueitem.stay_id, lv_uniqueitem.status_id, null, lv_uniqueitem.lastscandate,
     null, null, lv_uniqueitem.customerowned, year(gv_lastscandatetime), lv_week, lv_day, null, systemuserid, sysdate,
     lv_uniqueitem.prevstay_id, transactiontp, 0, lv_uniqueitem.uniqueitem_id, lv_secondaryid, null, 0, null, null,
     null, null);
  commit;
  if
    debuglevel > 0 then pack_sort.write_logging(' processonsiteinvetoryscan ' || m_message, debuglevel,
                                                        'PACK_SORT.processonsiteinvetoryscan', plantid, 1, 1);
  end if;
  exception
    when others then
      accept := 'N';
      pack_sort.write_logging(m_message || ' ' || sqlerrm, 1, 'PACK_SORT.processonsiteinvetoryscan', null, 3, 1);
  end processonsiteinvetoryscan;

begin
  i := 0;
  select s.sizedefinition_id
    into gv_specialsizeid
    from sizedefinition s
   where s.code = '*';
end pack_sort;
/
create or replace package pack_sort2 is
  /***************************************************************************\
  * -- Author  : ABS                                                          *
  * -- Version : 0.42                                                         *
  * -- Created : 21-7-2015                                                    *
  * -- Purpose : Update pack_sort version 2 sorting system interface          *
  *              for version 9.00 and higher                                  *
  * -- Updated                                                                *
  *    23-09-2015 return seasoncode only when its active this week            *
  *    14-10-2015 added sorting option 18 to the buildsortstring              *
  *    23-10-2015 Show season code when NOT in season!!                       *
  *    10-12-2015 Added the deliverypoint.description to the parameters       *
  *    03-05-2015 Added batchnumber as outputparameter for getgarmentinfo     *
  *    10-10-2016 Added sendtrackinfo (work in progress)                      *
  *    08-03-2018 ABS-61541, ABS-63376 added procedure getgarmentinfo_2       *
  *    02-07-2020 ABS-102309 reduce length sort string based on systemsettings*
  *               + fixed issues in descending sorting                        *
  *    11-02-2021 Made get_uniqueitem and get_uniqueitem global to be used    *
  *    28-02-2021 ABS-128944 Slow response from Inwatec interface             *
  *    21-02-2021 ABS-109871 prio of looking up washing process               *
  *    21-03-2023 ABS-148657 Outscan Multi Read on DN doesn't show already    *
  *                                            delivered quantities           *
  *    09-02-2024 ABS-157099 Add RSC ExtraInfo for virtual routes             *
  \***************************************************************************/
  --function get_plpcid_info returning plpc_id
  function get_plpcid_info(fp_customerid                in customer.customer_id%type,
                           fp_productid                 in product.product_id%type,
                           fp_sizeid                    in sizedefinition.sizedefinition_id%type,
                           fp_finishingmethodid         in finishingmethod.finishingmethod_id%type,
                           fp_date                      in date,
                           fp_maxwashes                 in out nocopy productlistpercustomer.maxwashes%type,
                           fp_billingmethod             out nocopy productlistpercustomer.billingmethod%type,
                           fp_chargewashesonlyforcog    out nocopy productlistpercustomer.chargewashesonlyforcog%type,
                           fp_numwashesspecialtreatment out nocopy productlistpercustomer.numberwashesspecialtreatment%type,
                           fp_plpc_washingprocessid     out nocopy productlistpercustomer.washingprocess_id%type,
                           fp_plpc_soilcountmethod      out nocopy productlistpercustomer.soilcountmethod%type)
    return number;

  --procedure get_uniqueitem
  procedure get_uniqueitem(fp_idcode         in uniqueitem.primaryid%type,
                           fp_plantcode      in plant.code%type,
                           fp_plantid        in plant.plant_id%type,
                           fp_rec_uniqueitem out nocopy uniqueitem%rowtype,
                           fp_secondaryid    out nocopy secondaryuniqueitem.secondaryid%type);

  --procedure get_uniqueitem_info
  procedure get_uniqueitem_info(fp_plantid_paramater          in plant.plant_id%type,
                                fp_rec_uniqueitem             in uniqueitem%rowtype,
                                fp_languageid                 in languages.language_id%type,
                                fp_outscanyn                  in varchar2 default 'N',
                                fp_businessunitcode           out nocopy businessunit.code%type,
                                fp_customernumber             out nocopy customer.customernumber%type,
                                fp_customerid                 out nocopy customer.customer_id%type,
                                fp_sortcustomerid             out nocopy customer.sortcustomer_id%type,
                                fp_customername               out nocopy customer.name%type,
                                fp_chargerepaircog            out nocopy customer.chargerepaircog%type,
                                fp_chargerepairs              out nocopy customer.chargerepairs%type,
                                fp_serviceteam_sortaddress    out nocopy serviceteam.sortaddress%type, --fp_checkpointselection
                                fp_departmentnumber           out nocopy department.departmentnumber%type,
                                fp_departmentdesc             out nocopy department.description%type,
                                fp_departmentid               out nocopy department.department_id%type,
                                fp_deliverypointcode          out nocopy deliverypoint.code%type,
                                fp_deliverypointdesc          out nocopy deliverypoint.description%type,
                                fp_deliverypointid            out nocopy deliverypoint.deliverypoint_id%type,
                                fp_deliverypoint_eut_id       out nocopy deliverypoint.deliverypoint_id%type,
                                fp_visitaddressid             out nocopy address.address_id%type,
                                fp_distributionpointnumber    out nocopy distributionpoint.distributionpointnumber%type,
                                fp_distributionpointid        out nocopy distributionpoint.distributionpoint_id%type,
                                fp_wearernumber               out nocopy wearer.wearernumber%type,
                                fp_wearerfullname             out nocopy wearer.fullname%type,
                                fp_wearersearchname           out nocopy wearer.searchname%type,
                                fp_wearerremark               out nocopy wearer.remark%type, /*infotext*/
                                fp_gender                     out nocopy wearer.sex%type,
                                fp_bank                       out nocopy varchar2,
                                fp_locker                     out nocopy varchar2,
                                fp_garmentdispensercode       out nocopy garmentdispenser.code%type,
                                fp_wearer_flagid              out nocopy wearer.flag_id%type,
                                fp_wearer_flagstartdate       out nocopy wearer.flagstartdate%type,
                                fp_employ_flagid              out nocopy weareremployment.flag_id%type,
                                fp_employ_flagstartdate       out nocopy weareremployment.flagstartdate%type,
                                fp_customeremployeenumber     out nocopy wearer.customeremployeenumber%type,
                                fp_productcode                out nocopy product.code%type,
                                fp_productdescription         out nocopy product_desc.description%type,
                                fp_legacyproductcode          out nocopy product.legacyproductcode%type,
                                fp_shortdescription           out nocopy product.shortdescription%type,
                                fp_productlongdescription     out nocopy product_desc.longdescription%type,
                                fp_product_washingprocessid   out nocopy product.washingprocess_id%type,
                                fp_productimagename           out nocopy image.imagename%type,
                                fp_finishingcodeid            out nocopy product.finishingcode_id%type,
                                fp_productsortgroup           out nocopy productsortgroup.code%type,
                                fp_productgroupcode           out nocopy productgroup.code%type,
                                fp_productgroupdescription    out nocopy productgroup_desc.description%type,
                                fp_packingsequence            out nocopy product.packingsequence%type,
                                fp_typeofmerchandise          out nocopy product.typeofmerchandise%type,
                                fp_theoreticalweight          out nocopy product.theoreticalweight%type,
                                fp_sizecode                   out nocopy sizedefinition.code%type,
                                fp_lockersortgroupnumber      out nocopy lockersortgroup.lockersortgroupnumber%type,
                                fp_alternatesorting           out nocopy customer.alternatesorting%type,
                                fp_destination                out nocopy sortaddressperfinishingmeth.sortaddress%type,
                                fp_foldprogram                out nocopy foldingprogramdefinition.foldingprogram%type,
                                fp_maxwashes                  out nocopy product.maxwashes%type,
                                fp_seasoncode                 out nocopy season.code%type,
                                fp_residualvalueamount        out nocopy residualvaluehistory.residualvalueamount%type,
                                fp_residualvaluepercentage    out nocopy residualvaluehistory.residualvaluepercentage%type,
                                fp_weareremploymentid         out nocopy weareremployment.weareremployment_id%type,
                                fp_lockerid                   out nocopy locker.locker_id%type,
                                fp_garmentdispenserid         out nocopy weareremployment.garmentdispenser_id%type,
                                fp_qtytobereturneddecreasemax out nocopy wearerinventory.qtytobereturneddecreasemax%type,
                                fp_fabriccode                 out nocopy fabric.code%type,
                                fp_fabricdescription          out nocopy fabric_desc.description%type,
                                fp_colorcode                  out nocopy color.code%type,
                                fp_colordescription           out nocopy color_desc.description%type,
                                fp_weighingcategoryid         out nocopy product.weighingcategory_id%type);

  --function buildsortstring
  function buildsortstring(fp_productcode          in product.code%type,
                           fp_sizecode             in sizedefinition.code%type,
                           fp_customernumber       in customer.customernumber%type,
                           fp_customerid           in customer.customer_id%type,
                           fp_wearernumber         in wearer.wearernumber%type,
                           fp_wearername           in wearer.searchname%type,
                           fp_bank                 in varchar2,
                           fp_locker               in varchar2,
                           fp_departmentnumber     in department.departmentnumber%type,
                           fp_customeremployee#    in wearer.customeremployeenumber%type,
                           fp_gender               in wearer.sex%type,
                           fp_garmentdispensercode in garmentdispenser.code%type,
                           fp_deliverypointcode    in deliverypoint.code%type,
                           fp_stopnumber           in routestop.stopnumber%type,
                           fp_plantid_param        in plant.plant_id%type,
                           fp_customerownedyn      in varchar2,
                           fp_ordernumber          in packingnote.notenumber%type,
                           fp_productsortgroupseq  in productsortgroupperplant.sequencenumber%type,
                           fp_lockersortgroup#     in lockersortgroup.lockersortgroupnumber%type,
                           fp_distributionpoint#   in distributionpoint.distributionpointnumber%type,
                           fp_sortcustomerid       in customer.sortcustomer_id%type default null,
                           fp_seasoncode           in season.code%type,
                           fp_stackchange          in sortingdefinition.stackchange%type default 'N',
                           fp_loglevel             in systemsetting.value%type) return varchar2;

  --procedure getgarmentinfo
  procedure getgarmentinfo(fp_idcode                  in uniqueitem.primaryid%type,
                           fp_plantcode               in plant.code%type,
                           fp_languagecode            in languages.code%type, /*optional parameter*/
                           fp_status                  out nocopy number, /*0=Ok otherwise error*/
                           fp_message                 out nocopy varchar2, /*(error) message*/
                           fp_businessunitcode        out nocopy businessunit.code%type,
                           fp_plantid_paramater       out nocopy plant.plant_id%type,
                           fp_secondaryid             out nocopy secondaryuniqueitem.secondaryid%type,
                           fp_checkpointselection     out nocopy varchar2,
                           fp_destination             out nocopy sortaddressperfinishingmeth.sortaddress%type,
                           fp_foldprogram             out nocopy varchar2,
                           fp_sortstring              out nocopy varchar2,
                           fp_alternatesortstring     out nocopy varchar2,
                           fp_stackchangeinfo         out nocopy varchar2,
                           fp_routenumber             out nocopy route.routenumber%type,
                           fp_routeday                out nocopy route.drivingday_id%type,
                           fp_stopnumber              out nocopy routestop.stopnumber%type,
                           fp_deliverydaymask         out nocopy varchar2,
                           fp_customernumber          out nocopy customer.customernumber%type,
                           fp_customername            out nocopy customer.name%type,
                           fp_customerowned           out nocopy uniqueitem.customerowned%type,
                           fp_chargerepaircog         out nocopy customer.chargerepaircog%type,
                           fp_chargerepairs           out nocopy customer.chargerepairs%type,
                           fp_departmentnumber        out nocopy department.departmentnumber%type,
                           fp_departmentdesc          out nocopy department.description%type,
                           fp_deliverypointcode       out nocopy deliverypoint.code%type,
                           fp_deliverypointdesc       out nocopy deliverypoint.description%type,
                           fp_street                  out nocopy varchar2,
                           fp_street2                 out nocopy varchar2,
                           fp_city                    out nocopy varchar2,
                           fp_zipcode                 out nocopy varchar2,
                           fp_distributionpointnumber out nocopy distributionpoint.distributionpointnumber%type,
                           fp_wearernumber            out nocopy wearer.wearernumber%type,
                           fp_wearerfullname          out nocopy wearer.fullname%type,
                           fp_wearersearchname        out nocopy wearer.searchname%type,
                           fp_wearerremark            out nocopy wearer.remark%type, /*infotext*/
                           fp_bank                    out nocopy varchar2,
                           fp_locker                  out nocopy varchar2,
                           fp_garmentdispensercode    out nocopy garmentdispenser.code%type,
                           fp_customeremployeenumber  out nocopy wearer.customeremployeenumber%type,
                           fp_productsortgroup        out nocopy productsortgroup.code%type,
                           fp_productcode             out nocopy product.code%type,
                           fp_packingsequence         out nocopy product.packingsequence%type,
                           fp_productdescription      out nocopy product_desc.description%type,
                           fp_productimagename        out nocopy image.imagename%type,
                           fp_finishingcodeid         out nocopy product.finishingcode_id%type,
                           fp_sizecode                out nocopy sizedefinition.code%type,
                           fp_flagcode1               out nocopy flag.code%type,
                           fp_flagcode2               out nocopy flag.code%type,
                           fp_flagcode3               out nocopy flag.code%type,
                           fp_flagcode4               out nocopy flag.code%type,
                           fp_flagsortaddress1        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagsortaddress2        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagsortaddress3        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagsortaddress4        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagdescription1        out nocopy varchar2,
                           fp_flagdescription2        out nocopy varchar2,
                           fp_flagdescription3        out nocopy varchar2,
                           fp_flagdescription4        out nocopy varchar2,
                           fp_flagfreetext1           out nocopy uniqueitemflag.freetextitem%type,
                           fp_flagfreetext2           out nocopy uniqueitemflag.freetextitem%type,
                           fp_flagfreetext3           out nocopy uniqueitemflag.freetextitem%type,
                           fp_flagfreetext4           out nocopy uniqueitemflag.freetextitem%type,
                           fp_lastinscandate          out nocopy date,
                           fp_lastoutscandate         out nocopy date,
                           fp_lastscandate            out nocopy date,
                           fp_washestotal             out nocopy uniqueitem.washestotal%type,
                           fp_repairstotal            out nocopy uniqueitem.repairstotal%type,
                           fp_rewashtotal             out nocopy uniqueitem.rewashtotal%type,
                           fp_maxwashes               out nocopy product.maxwashes%type,
                           fp_seasoncode              out nocopy season.code%type,
                           fp_residualvalueamount     out nocopy residualvaluehistory.residualvalueamount%type,
                           fp_residualvaluepercentage out nocopy residualvaluehistory.residualvaluepercentage%type,
                           fp_batchnumber             out nocopy uniqueitem.batchnumber%type);

  --procedure getgarmentinfo_2 copy of procedure getgarmentinfo with extra fields
  procedure getgarmentinfo_2(fp_idcode                    in uniqueitem.primaryid%type,
                             fp_plantcode                 in plant.code%type,
                             fp_languagecode              in languages.code%type, /*optional parameter*/
                             fp_status                    out nocopy number, /*0=Ok otherwise error*/
                             fp_message                   out nocopy varchar2, /*(error) message*/
                             fp_businessunitcode          out nocopy businessunit.code%type,
                             fp_plantid_paramater         out nocopy plant.plant_id%type,
                             fp_secondaryid               out nocopy secondaryuniqueitem.secondaryid%type,
                             fp_checkpointselection       out nocopy varchar2,
                             fp_destination               out nocopy sortaddressperfinishingmeth.sortaddress%type,
                             fp_foldprogram               out nocopy varchar2,
                             fp_sortstring                out nocopy varchar2,
                             fp_alternatesortstring       out nocopy varchar2,
                             fp_stackchangeinfo           out nocopy varchar2,
                             fp_routenumber               out nocopy route.routenumber%type,
                             fp_routeday                  out nocopy route.drivingday_id%type,
                             fp_stopnumber                out nocopy routestop.stopnumber%type,
                             fp_deliverydaymask           out nocopy varchar2,
                             fp_customernumber            out nocopy customer.customernumber%type,
                             fp_customername              out nocopy customer.name%type,
                             fp_customerowned             out nocopy uniqueitem.customerowned%type,
                             fp_chargerepaircog           out nocopy customer.chargerepaircog%type,
                             fp_chargerepairs             out nocopy customer.chargerepairs%type,
                             fp_departmentnumber          out nocopy department.departmentnumber%type,
                             fp_departmentdesc            out nocopy department.description%type,
                             fp_deliverypointcode         out nocopy deliverypoint.code%type,
                             fp_deliverypointdesc         out nocopy deliverypoint.description%type,
                             fp_street                    out nocopy varchar2,
                             fp_street2                   out nocopy varchar2,
                             fp_city                      out nocopy varchar2,
                             fp_zipcode                   out nocopy varchar2,
                             fp_distributionpointnumber   out nocopy distributionpoint.distributionpointnumber%type,
                             fp_wearernumber              out nocopy wearer.wearernumber%type,
                             fp_wearerfullname            out nocopy wearer.fullname%type,
                             fp_wearersearchname          out nocopy wearer.searchname%type,
                             fp_wearerremark              out nocopy wearer.remark%type, /*infotext*/
                             fp_bank                      out nocopy varchar2,
                             fp_locker                    out nocopy varchar2,
                             fp_garmentdispensercode      out nocopy garmentdispenser.code%type,
                             fp_customeremployeenumber    out nocopy wearer.customeremployeenumber%type,
                             fp_productsortgroup          out nocopy productsortgroup.code%type,
                             fp_productcode               out nocopy product.code%type,
                             fp_typeofmerchandise         out nocopy product.typeofmerchandise%type,
                             fp_packingsequence           out nocopy product.packingsequence%type,
                             fp_productdescription        out nocopy product_desc.description%type,
                             fp_productimagename          out nocopy image.imagename%type,
                             fp_finishingcodeid           out nocopy product.finishingcode_id%type,
                             fp_sizecode                  out nocopy sizedefinition.code%type,
                             fp_flagcode1                 out nocopy flag.code%type,
                             fp_flagcode2                 out nocopy flag.code%type,
                             fp_flagcode3                 out nocopy flag.code%type,
                             fp_flagcode4                 out nocopy flag.code%type,
                             fp_flagsortaddress1          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagsortaddress2          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagsortaddress3          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagsortaddress4          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagdescription1          out nocopy varchar2,
                             fp_flagdescription2          out nocopy varchar2,
                             fp_flagdescription3          out nocopy varchar2,
                             fp_flagdescription4          out nocopy varchar2,
                             fp_flagfreetext1             out nocopy uniqueitemflag.freetextitem%type,
                             fp_flagfreetext2             out nocopy uniqueitemflag.freetextitem%type,
                             fp_flagfreetext3             out nocopy uniqueitemflag.freetextitem%type,
                             fp_flagfreetext4             out nocopy uniqueitemflag.freetextitem%type,
                             fp_lastinscandate            out nocopy date,
                             fp_lastoutscandate           out nocopy date,
                             fp_lastscandate              out nocopy date,
                             fp_washestotal               out nocopy uniqueitem.washestotal%type,
                             fp_repairstotal              out nocopy uniqueitem.repairstotal%type,
                             fp_rewashtotal               out nocopy uniqueitem.rewashtotal%type,
                             fp_maxwashes                 out nocopy product.maxwashes%type,
                             fp_seasoncode                out nocopy season.code%type,
                             fp_residualvalueamount       out nocopy residualvaluehistory.residualvalueamount%type,
                             fp_residualvaluepercentage   out nocopy residualvaluehistory.residualvaluepercentage%type,
                             fp_batchnumber               out nocopy uniqueitem.batchnumber%type,
                             fp_legacyproductcode         out nocopy product.legacyproductcode%type,
                             fp_productlongdescription    out nocopy product_desc.longdescription%type,
                             fp_productgroupdescription   out nocopy productgroup_desc.description%type,
                             fp_productgroupcode          out nocopy productgroup.code%type,
                             fp_shortdescription          out nocopy product.shortdescription%type,
                             fp_fabriccode                out nocopy fabric.code%type,
                             fp_fabricdescription         out nocopy fabric_desc.description%type,
                             fp_colorcode                 out nocopy color.code%type,
                             fp_colordescription          out nocopy color_desc.description%type,
                             fp_theoreticalweight         out nocopy product.theoreticalweight%type,
                             fp_weighingcategoryid        out nocopy product.weighingcategory_id%type,
                             fp_plpc_soilcountmethod      out nocopy productlistpercustomer.soilcountmethod%type,
                             fp_ownership                 out nocopy varchar2,
                             fp_weighingcategorycode      out nocopy weighingcategory.code%type,
                             fp_weighingcategorydescrip   out nocopy weighingcategory_desc.description%type,
                             fp_washingprocesscode        out nocopy washingprocess.code%type,
                             fp_washingprocessdescription out nocopy washingprocess_desc.description%type,
                             fp_washingprocsortingadress  out nocopy washingprocess.sortcode%type);

  --procedure sendtrackinfo (work in progress)
  procedure sendtrackinfo(fp_idcode            in uniqueitem.primaryid%type,
                          fp_plantcode         in plant.code%type,
                          fp_languagecode      in languages.code%type default null, /*optional parameter*/
                          fp_datep             in number, /*Format YYYYMMDD*/
                          fp_timep             in number, /*Format HHMMSS*/
                          fp_locationcode      in varchar2,
                          fp_nextlocationcode  in varchar2 default null,
                          fp_notenumber        in number default null, --Packingnotenumber
                          fp_status            out nocopy number, /*0=Ok otherwise error*/
                          fp_message           out nocopy varchar2, /*(error) message*/
                          fp_flagcode1         in varchar2 default null,
                          fp_flagcode2         in varchar2 default null,
                          fp_flagcode3         in varchar2 default null,
                          fp_flagcode4         in varchar2 default null,
                          fp_sortbatchnumber   in number default null,
                          fp_productlegacycode in varchar2 default null,
                          fp_repairsdone       in varchar2 default null,
                          fp_pickupdate        in number default null,
                          fp_retransferyn      in varchar2 default 'N',
                          fp_metricon          in varchar2 default 'N');
end pack_sort2;
/
create or replace package body pack_sort2 is
  gv_user__exception exception;
  gv_message      abslog.message%type;
  gv_databasecode databasesettings.code%type;

  function get_loglevel(fp_plantid in plant.plant_id%type, fp_name systemsetting.name%type)
    return systemsetting.value%type is
    lv_value   systemsetting.value%type;
    lv_logdate date;
  begin
    select ss.value, trunc(ss.timestamp) logdate
    into   lv_value, lv_logdate
    from   systemsetting ss
    where  ss.plant_id = fp_plantid
    and    ss.name = fp_name;
    if fp_name in ('SORTLOGGETGARMENTDATA', 'SORTLOGSENDTRACKINFO') and lv_value <> '0' and
       lv_logdate < trunc(sysdate) then
      begin
        --turn of detailed logging
        update systemsetting ss
        set    ss.value = '0'
        where  ss.plant_id = fp_plantid
        and    ss.name = fp_name;
        lv_value := '0';
      end;
    end if;
    return lv_value;
  exception
    when no_data_found then
      return '0';
    when others then
      return '0';
  end get_loglevel;

  procedure write_logging(fp_message    in abslog.message%type,
                          fp_loglevel   in systemsetting.value%type,
                          fp_logname    in varchar2,
                          fp_plantid    in plant.plant_id%type default null,
                          fp_priority   in number default 1,
                          fp_detailinfo in number default 0) is ---0=no detail 1=detail
  begin
    --write_logging
    if fp_priority > 2 then
      begin
        abslogwrite.abslog_write(5, fp_logname, fp_plantid, fp_priority, fp_message);
      end;
    else
      case fp_loglevel
        when '0' then
          null; --no logging other then errors
        when '1' then
          if fp_detailinfo = 1 then
            --Log level 1 and detailinfo=1 write detail info
            abslogwrite.abslog_write(5, fp_logname, fp_plantid, fp_priority, fp_message);
          end if;
        when '2' then
          --write all logs
          abslogwrite.abslog_write(5, fp_logname, fp_plantid, fp_priority, fp_message);
        else
          null;
      end case;
    end if;
  end write_logging;

  function convertstringdesc(receivedstring varchar2) return varchar2 is
    aux          varchar2(1);
    newaux       varchar2(1);
    returnstring varchar2(100);
    lv_cnt       integer;
  begin
    returnstring := '';
    lv_cnt       := length(receivedstring);
    if lv_cnt > 0 then
      for i in 1 .. lv_cnt loop
        aux := substr(receivedstring, i, 1);
        if 32 <= ascii(aux) and ascii(aux) <= 126 then
          newaux := chr(126 - (ascii(aux) - 32));
        else
          newaux := aux;
        end if;
        returnstring := returnstring || newaux;
      end loop;
    end if;
    return returnstring;
  end convertstringdesc;

  procedure get_uniqueitem(fp_idcode         in uniqueitem.primaryid%type,
                           fp_plantcode      in plant.code%type,
                           fp_plantid        in plant.plant_id%type,
                           fp_rec_uniqueitem out nocopy uniqueitem%rowtype,
                           fp_secondaryid    out nocopy secondaryuniqueitem.secondaryid%type) is
    lv_overalluniquegarmentid databasesettings.overalluniquegarmentid%type;

    procedure get_secondaryid is
    begin
      --get secondary id, taking max when not found it becomes NULL
      select max(su.secondaryid)
      into   fp_secondaryid
      from   secondaryuniqueitem su
      where  su.uniqueitem_id = fp_rec_uniqueitem.uniqueitem_id;
    end get_secondaryid;
  begin
    --get_uniqueitem
    gv_message := 'get_uniqueitem';
    select max(code), nvl(max(overalluniquegarmentid), 'Y')
    into   gv_databasecode, lv_overalluniquegarmentid
    from   databasesettings;
    gv_message := case lv_overalluniquegarmentid
                    when 'Y' then
                     'Retrieving ID code ' || fp_idcode
                    else
                     'Retrieving ID code ' || fp_idcode || ' for plant ' || fp_plantcode
                  end;
    if lv_overalluniquegarmentid = 'Y' then
      begin
        --lookup primaryid
        select u.* into fp_rec_uniqueitem from uniqueitem u where u.primaryid = fp_idcode;
        --get secondary id
        get_secondaryid;
      exception
        when no_data_found then
          begin
            --not found, check secondaryuniqueitem
            select u.*
            into   fp_rec_uniqueitem
            from   secondaryuniqueitem su
            join   uniqueitem u
            on     u.uniqueitem_id = su.uniqueitem_id
            where  su.secondaryid = fp_idcode;
            --get secondary id
            fp_secondaryid := fp_idcode;
          end;
        when too_many_rows then
          begin
            --lookup primaryid with plant id
            select u.*
            into   fp_rec_uniqueitem
            from   uniqueitem u
            join   businessunit bu
            on     bu.businessunit_id = u.businessunit_id
            where  u.primaryid = fp_idcode
            and    bu.plant_id = fp_plantid;
            --get secondary id
            get_secondaryid;
          end;
      end;
    else
      begin
        --lookup primaryid with plant id
        select u.*
        into   fp_rec_uniqueitem
        from   uniqueitem u
        join   businessunit bu
        on     bu.businessunit_id = u.businessunit_id
        where  u.primaryid = fp_idcode
        and    bu.plant_id = fp_plantid;
        --get secondary id
        get_secondaryid;
      exception
        when no_data_found then
          begin
            --not found, check secondaryuniqueitem with plant id
            select u.*
            into   fp_rec_uniqueitem
            from   secondaryuniqueitem su
            join   uniqueitem u
            on     u.uniqueitem_id = su.uniqueitem_id
            join   businessunit bu
            on     bu.businessunit_id = u.businessunit_id
            where  su.secondaryid = fp_idcode
            and    bu.plant_id = fp_plantid;
            --get secondary id
            fp_secondaryid := fp_idcode;
          exception
            when no_data_found then
              begin
                --maybe its unique
                select u.* into fp_rec_uniqueitem from uniqueitem u where u.primaryid = fp_idcode;
                --get secondary id
                get_secondaryid;
              end;
          end;
        when too_many_rows then
          begin
            --lookup primaryid with plant id
            select u.*
            into   fp_rec_uniqueitem
            from   uniqueitem u
            join   businessunit bu
            on     bu.businessunit_id = u.businessunit_id
            where  u.primaryid = fp_idcode
            and    bu.plant_id = fp_plantid
            and    u.idcodesequencenumber = 1;
            --get secondary id
            get_secondaryid;
          end;
      end;
    end if;
  end get_uniqueitem;

  procedure get_uniqueitem_info(fp_plantid_paramater          in plant.plant_id%type,
                                fp_rec_uniqueitem             in uniqueitem%rowtype,
                                fp_languageid                 in languages.language_id%type,
                                fp_outscanyn                  in varchar2 default 'N',
                                fp_businessunitcode           out nocopy businessunit.code%type,
                                fp_customernumber             out nocopy customer.customernumber%type,
                                fp_customerid                 out nocopy customer.customer_id%type,
                                fp_sortcustomerid             out nocopy customer.sortcustomer_id%type,
                                fp_customername               out nocopy customer.name%type,
                                fp_chargerepaircog            out nocopy customer.chargerepaircog%type,
                                fp_chargerepairs              out nocopy customer.chargerepairs%type,
                                fp_serviceteam_sortaddress    out nocopy serviceteam.sortaddress%type, --fp_checkpointselection
                                fp_departmentnumber           out nocopy department.departmentnumber%type,
                                fp_departmentdesc             out nocopy department.description%type,
                                fp_departmentid               out nocopy department.department_id%type,
                                fp_deliverypointcode          out nocopy deliverypoint.code%type,
                                fp_deliverypointdesc          out nocopy deliverypoint.description%type,
                                fp_deliverypointid            out nocopy deliverypoint.deliverypoint_id%type,
                                fp_deliverypoint_eut_id       out nocopy deliverypoint.deliverypoint_id%type,
                                fp_visitaddressid             out nocopy address.address_id%type,
                                fp_distributionpointnumber    out nocopy distributionpoint.distributionpointnumber%type,
                                fp_distributionpointid        out nocopy distributionpoint.distributionpoint_id%type,
                                fp_wearernumber               out nocopy wearer.wearernumber%type,
                                fp_wearerfullname             out nocopy wearer.fullname%type,
                                fp_wearersearchname           out nocopy wearer.searchname%type,
                                fp_wearerremark               out nocopy wearer.remark%type, /*infotext*/
                                fp_gender                     out nocopy wearer.sex%type,
                                fp_bank                       out nocopy varchar2,
                                fp_locker                     out nocopy varchar2,
                                fp_garmentdispensercode       out nocopy garmentdispenser.code%type,
                                fp_wearer_flagid              out nocopy wearer.flag_id%type,
                                fp_wearer_flagstartdate       out nocopy wearer.flagstartdate%type,
                                fp_employ_flagid              out nocopy weareremployment.flag_id%type,
                                fp_employ_flagstartdate       out nocopy weareremployment.flagstartdate%type,
                                fp_customeremployeenumber     out nocopy wearer.customeremployeenumber%type,
                                fp_productcode                out nocopy product.code%type,
                                fp_productdescription         out nocopy product_desc.description%type,
                                fp_legacyproductcode          out nocopy product.legacyproductcode%type,
                                fp_shortdescription           out nocopy product.shortdescription%type,
                                fp_productlongdescription     out nocopy product_desc.longdescription%type,
                                fp_product_washingprocessid   out nocopy product.washingprocess_id%type,
                                fp_productimagename           out nocopy image.imagename%type,
                                fp_finishingcodeid            out nocopy product.finishingcode_id%type,
                                fp_productsortgroup           out nocopy productsortgroup.code%type,
                                fp_productgroupcode           out nocopy productgroup.code%type,
                                fp_productgroupdescription    out nocopy productgroup_desc.description%type,
                                fp_packingsequence            out nocopy product.packingsequence%type,
                                fp_typeofmerchandise          out nocopy product.typeofmerchandise%type,
                                fp_theoreticalweight          out nocopy product.theoreticalweight%type,
                                fp_sizecode                   out nocopy sizedefinition.code%type,
                                fp_lockersortgroupnumber      out nocopy lockersortgroup.lockersortgroupnumber%type,
                                fp_alternatesorting           out nocopy customer.alternatesorting%type,
                                fp_destination                out nocopy sortaddressperfinishingmeth.sortaddress%type,
                                fp_foldprogram                out nocopy foldingprogramdefinition.foldingprogram%type,
                                fp_maxwashes                  out nocopy product.maxwashes%type,
                                fp_seasoncode                 out nocopy season.code%type,
                                fp_residualvalueamount        out nocopy residualvaluehistory.residualvalueamount%type,
                                fp_residualvaluepercentage    out nocopy residualvaluehistory.residualvaluepercentage%type,
                                fp_weareremploymentid         out nocopy weareremployment.weareremployment_id%type,
                                fp_lockerid                   out nocopy locker.locker_id%type,
                                fp_garmentdispenserid         out nocopy weareremployment.garmentdispenser_id%type,
                                fp_qtytobereturneddecreasemax out nocopy wearerinventory.qtytobereturneddecreasemax%type,
                                fp_fabriccode                 out nocopy fabric.code%type,
                                fp_fabricdescription          out nocopy fabric_desc.description%type,
                                fp_colorcode                  out nocopy color.code%type,
                                fp_colordescription           out nocopy color_desc.description%type,
                                fp_weighingcategoryid         out nocopy product.weighingcategory_id%type) is

    procedure set_customernull is
    begin
      --set_customernull
      fp_customernumber          := null;
      fp_customername            := null;
      fp_departmentnumber        := null;
      fp_departmentdesc          := null;
      fp_deliverypointcode       := null;
      fp_deliverypointdesc       := null;
      fp_deliverypointid         := null;
      fp_customerid              := null;
      fp_sortcustomerid          := null;
      fp_alternatesorting        := null;
      fp_distributionpointid     := null;
      fp_distributionpointnumber := null;
      fp_serviceteam_sortaddress := null;
      fp_chargerepaircog         := null;
      fp_chargerepairs           := null;
    end set_customernull;

    procedure set_wearernull is
    begin
      --set_wearernull
      fp_wearernumber               := null;
      fp_wearerfullname             := null;
      fp_wearersearchname           := null;
      fp_wearer_flagid              := null;
      fp_wearer_flagstartdate       := null;
      fp_employ_flagid              := null;
      fp_employ_flagstartdate       := null;
      fp_gender                     := null;
      fp_lockersortgroupnumber      := null;
      fp_wearerremark               := null;
      fp_seasoncode                 := null;
      fp_weareremploymentid         := null;
      fp_lockerid                   := null;
      fp_garmentdispenserid         := null;
      fp_qtytobereturneddecreasemax := null;
    end set_wearernull;

  begin
    --get_uniqueitem_info
    gv_message := 'get_uniqueitem_info for uniqueitem_id ' ||
                  nvl(to_char(fp_rec_uniqueitem.uniqueitem_id), 'NULL');
    select bu.code, p.code, p.packingsequence, p.typeofmerchandise,
           case p.maxwashes
              when 0 then
               null
              else
               p.maxwashes
            end maxwashes, p.legacyproductcode, p.shortdescription,
           (select pd.description
             from   product_desc pd
             where  pd.product_id = p.product_id
             and    pd.language_id = fp_languageid),
           (select pd.longdescription
             from   product_desc pd
             where  pd.product_id = p.product_id
             and    pd.language_id = fp_languageid),
           (select psgp.sequencenumber
             from   productsortgroupperplant psgp
             where  psgp.productsortgroup_id = p.productsortgroup_id
             and    psgp.plant_id = fp_plantid_paramater), s.code,
           (select f.foldingprogram
             from   foldingprogramdefinition f
             where  f.product_id = p.product_id
             and    f.finishingmethod_id = fp_rec_uniqueitem.finishingmethod_id
             and    f.plant_id = fp_plantid_paramater),
           (select nvl(max(s.sortaddress), 0)
             from   sortaddressperfinishingmeth s
             where  s.finishingmethod_id = fp_rec_uniqueitem.finishingmethod_id
             and    s.plant_id = fp_plantid_paramater),
           (select ig.imagename from image ig where ig.image_id = p.image_id) imagename,
           p.finishingcode_id,
           (select pgd.description
             from   productgroup_desc pgd
             where  pgd.productgroup_id = p.productgroup_id
             and    pgd.language_id = fp_languageid), pg.code, fb.code,
           (select fbd.description
             from   fabric_desc fbd
             where  fbd.fabric_id = p.fabric_id
             and    fbd.language_id = fp_languageid), cl.code,
           (select cld.description
             from   color_desc cld
             where  cld.color_id = p.color_id
             and    cld.language_id = fp_languageid),
           nvl((select ps.theoreticalweight
                from   productsize ps
                where  ps.product_id = p.product_id
                and    ps.sizedefinition_id = s.sizedefinition_id), p.theoreticalweight),
           p.weighingcategory_id, p.washingprocess_id
    into   fp_businessunitcode, fp_productcode, fp_packingsequence, fp_typeofmerchandise,
           fp_maxwashes, fp_legacyproductcode, fp_shortdescription, fp_productdescription,
           fp_productlongdescription, fp_productsortgroup, fp_sizecode, fp_foldprogram,
           fp_destination, fp_productimagename, fp_finishingcodeid, fp_productgroupdescription,
           fp_productgroupcode, fp_fabriccode, fp_fabricdescription, fp_colorcode,
           fp_colordescription, fp_theoreticalweight, fp_weighingcategoryid,
           fp_product_washingprocessid
    from   businessunit bu
    cross  join product p
    join   productgroup pg
    on     pg.productgroup_id = p.productgroup_id
    join   color cl
    on     cl.color_id = p.color_id
    join   fabric fb
    on     fb.fabric_id = p.fabric_id
    cross  join sizedefinition s
    where  bu.businessunit_id = fp_rec_uniqueitem.businessunit_id
    and    p.product_id = fp_rec_uniqueitem.product_id
    and    s.sizedefinition_id = fp_rec_uniqueitem.sizedefinition_id;
    --get extra information such as customer information
    case fp_rec_uniqueitem.poolitem
      when 2 then
        begin
          --get wearer info
          select c.customernumber, c.customer_id, c.sortcustomer_id, c.name,
                 (select srt.sortaddress
                   from   serviceteam srt
                   where  srt.serviceteam_id = c.serviceteam_id), w.wearernumber, w.fullname,
                 w.searchname, w.remark, w.sex, w.customeremployeenumber, w.flag_id, w.flagstartdate,
                 we.flag_id, we.flagstartdate, t.departmentnumber, t.description, dt.code,
                 dt.description, dp.distributionpointnumber, dp.distributionpoint_id,
                 (select lsg.lockersortgroupnumber
                   from   lockersortgroup lsg
                   where  lsg.lockersortgroup_id = l.lockersortgroup_id) lockersortgroupnumber,
                 l.bank, l.locker, gd.code, c.alternatesorting,
                 coalesce(l.deliverypoint_id, gd.deliverypoint_id, we.deliverypoint_id),
                 t.department_id, coalesce(dt.deliveryaddress_id, c.visitaddress_id) visitaddress_id,
                 c.chargerepairs, c.chargerepaircog, un.weareremployment_id, we.locker_id,
                 we.garmentdispenser_id, wi.qtytobereturneddecreasemax,
                 (select ss.code --show season when NOT in the season!!
                   from   season ss
                   where  ss.season_id = wi.season_id
                   and    not exists (select 1
                           from   seasonweek sw
                           where  sw.season_id = ss.season_id
                           and    sw.weeknumber = getisoweek(sysdate))), dp.deliverypoint_id
          into   fp_customernumber, fp_customerid, fp_sortcustomerid, fp_customername,
                 fp_serviceteam_sortaddress, fp_wearernumber, fp_wearerfullname, fp_wearersearchname,
                 fp_wearerremark, fp_gender, fp_customeremployeenumber, fp_wearer_flagid,
                 fp_wearer_flagstartdate, fp_employ_flagid, fp_employ_flagstartdate,
                 fp_departmentnumber, fp_departmentdesc, fp_deliverypointcode, fp_deliverypointdesc,
                 fp_distributionpointnumber, fp_distributionpointid, fp_lockersortgroupnumber,
                 fp_bank, fp_locker, fp_garmentdispensercode, fp_alternatesorting,
                 fp_deliverypointid, fp_departmentid, fp_visitaddressid, fp_chargerepairs,
                 fp_chargerepaircog, fp_weareremploymentid, fp_lockerid, fp_garmentdispenserid,
                 fp_qtytobereturneddecreasemax, fp_seasoncode, fp_deliverypoint_eut_id
          from   uniqueitemnonpool un
          join   weareremployment we
          on     we.weareremployment_id = un.weareremployment_id
          join   wearerinventory wi
          on     wi.wearerinventory_id = un.wearerinventory_id
          join   wearer w
          on     w.wearer_id = we.wearer_id
          join   customer c
          on     c.customer_id = w.customer_id
          join   distributionpoint dp
          on     dp.distributionpoint_id = we.distributionpoint_id
          join   department t
          on     t.department_id = dp.department_id
          left   outer join locker l
          on     l.locker_id = we.locker_id
          left   outer join garmentdispenser gd
          on     gd.garmentdispenser_id = we.garmentdispenser_id
          join   deliverypoint dt
          on     dt.deliverypoint_id =
                 coalesce(l.deliverypoint_id, gd.deliverypoint_id, we.deliverypoint_id,
                          dp.deliverypoint_id)
          where  un.uniqueitem_id = fp_rec_uniqueitem.uniqueitem_id;
        end;
      when 1 then
        begin
          --no wearer linked
          set_wearernull;
          if fp_rec_uniqueitem.distributionpoint_id is not null and fp_outscanyn = 'N' then
            begin
              --get fp_rec_uniqueitem.distributionpoint_id related info
              select c.customernumber, c.customer_id, c.sortcustomer_id, c.name,
                     (select srt.sortaddress
                       from   serviceteam srt
                       where  srt.serviceteam_id = c.serviceteam_id), t.departmentnumber,
                     t.description, dt.code, dt.description, c.alternatesorting, dp.deliverypoint_id,
                     t.department_id,
                     coalesce(dt.deliveryaddress_id, c.visitaddress_id) visitaddress_id
              into   fp_customernumber, fp_customerid, fp_sortcustomerid, fp_customername,
                     fp_serviceteam_sortaddress, fp_departmentnumber, fp_departmentdesc,
                     fp_deliverypointcode, fp_deliverypointdesc, fp_alternatesorting,
                     fp_deliverypointid, fp_departmentid, fp_visitaddressid
              from   distributionpoint dp
              join   department t
              on     t.department_id = dp.department_id
              join   deliverypoint dt
              on     dt.deliverypoint_id = dp.deliverypoint_id
              join   customer c
              on     c.customer_id = t.customer_id
              where  dp.distributionpoint_id = fp_rec_uniqueitem.distributionpoint_id;
            end;
          elsif fp_rec_uniqueitem.relatedcustomer_id is not null then
            begin
              set_customernull;
              --get relatedcustomer_id info
              select c.customernumber, c.customer_id, c.sortcustomer_id, c.name,
                     (select srt.sortaddress
                       from   serviceteam srt
                       where  srt.serviceteam_id = c.serviceteam_id), c.alternatesorting
              into   fp_customernumber, fp_customerid, fp_sortcustomerid, fp_customername,
                     fp_serviceteam_sortaddress, fp_alternatesorting
              from   customer c
              where  c.customer_id = fp_rec_uniqueitem.relatedcustomer_id;
            end;
          else
            begin
              --no linked customer set values null
              set_customernull;
            end;
          end if;
        end;
      else
        begin
          --no linked customer set values null
          set_wearernull;
          set_customernull;
        end;
    end case;
    --get residualvalueamount and residualvaluepercentage
    select max(rvh.residualvalueamount), max(rvh.residualvaluepercentage)
    into   fp_residualvalueamount, fp_residualvaluepercentage
    from   residualvaluehistory rvh
    where  rvh.uniqueitem_link_id = fp_rec_uniqueitem.uniqueitem_id
    and    rvh.calculationdate = (select max(rvhx.calculationdate)
                                  from   residualvaluehistory rvhx
                                  where  rvhx.uniqueitem_link_id = rvh.uniqueitem_link_id
                                  and    rvhx.calculationdate <= sysdate);
  end get_uniqueitem_info;

  function buildsortstring(fp_productcode          in product.code%type,
                           fp_sizecode             in sizedefinition.code%type,
                           fp_customernumber       in customer.customernumber%type,
                           fp_customerid           in customer.customer_id%type,
                           fp_wearernumber         in wearer.wearernumber%type,
                           fp_wearername           in wearer.searchname%type,
                           fp_bank                 in varchar2,
                           fp_locker               in varchar2,
                           fp_departmentnumber     in department.departmentnumber%type,
                           fp_customeremployee#    in wearer.customeremployeenumber%type,
                           fp_gender               in wearer.sex%type,
                           fp_garmentdispensercode in garmentdispenser.code%type,
                           fp_deliverypointcode    in deliverypoint.code%type,
                           fp_stopnumber           in routestop.stopnumber%type,
                           fp_plantid_param        in plant.plant_id%type,
                           fp_customerownedyn      in varchar2,
                           fp_ordernumber          in packingnote.notenumber%type,
                           fp_productsortgroupseq  in productsortgroupperplant.sequencenumber%type,
                           fp_lockersortgroup#     in lockersortgroup.lockersortgroupnumber%type,
                           fp_distributionpoint#   in distributionpoint.distributionpointnumber%type,
                           fp_sortcustomerid       in customer.sortcustomer_id%type default null,
                           fp_seasoncode           in season.code%type,
                           fp_stackchange          in sortingdefinition.stackchange%type default 'N',
                           fp_loglevel             in systemsetting.value%type) return varchar2 is
    lv_sortroutestop    systemsetting.value%type;
    lv_sortstring       varchar2(255);
    lv_cnt              integer;
    lv_customernumber   customer.customernumber%type;
    lv_sortstringlength integer;
    lv_sequencenumber   productsize.sequencenumber%type;

    function get_sortroutestop(fp_plantid_param  in plant.plant_id%type,
                               fp_stopnumber     in stop.stopnumber%type,
                               fp_customernumber in customer.customernumber%type) return varchar2 is
      lv_sortstring            varchar2(255);
      lv_maxsortlengthstop     number;
      lv_maxsortlengthcustomer number;

    begin
      --Sort string --Stack change info
      begin
        select s.value
        into   lv_sortroutestop
        from   systemsetting s
        where  s.plant_id = fp_plantid_param
        and    s.name = 'SORTROUTESTOP';
      exception
        when others then
          lv_sortroutestop := 'A';
      end;
      begin
        select to_number(s.value)
        into   lv_maxsortlengthstop
        from   systemsetting s
        where  s.plant_id = fp_plantid_param
        and    s.name = 'MAXSORTLENGTHSTOP';
      exception
        when others then
          lv_maxsortlengthstop := 6;
      end;
      begin
        select to_number(s.value)
        into   lv_maxsortlengthcustomer
        from   systemsetting s
        where  s.plant_id = fp_plantid_param
        and    s.name = 'MAXSORTLENGTHCUSTOMER';
      exception
        when others then
          lv_maxsortlengthcustomer := 12;
      end;
      case lv_sortroutestop
        when 'A' then
          --default is 'A' ascending
          lv_sortstring := substr(lpad(to_char(fp_stopnumber), 6, 0), lv_maxsortlengthstop * -1,
                                  lv_maxsortlengthstop) ||
                           substr(lpad(fp_customernumber, 12, 0), lv_maxsortlengthcustomer * -1,
                                  lv_maxsortlengthcustomer);
        when 'D' then
          --other option 'D' descending
          lv_sortstring := substr(lpad(to_char(999999 - fp_stopnumber), 6, 0),
                                  lv_maxsortlengthstop * -1, lv_maxsortlengthstop) ||
                           substr(lpad(999999999999 - fp_customernumber, 12, 0),
                                  lv_maxsortlengthcustomer * -1, lv_maxsortlengthcustomer);
        when 'Y' then
          --new option 'Y' is customer only export
          lv_sortstring := substr(lpad(fp_customernumber, 12, 0), lv_maxsortlengthcustomer * -1,
                                  lv_maxsortlengthcustomer);
        when 'Z' then
          --new option 'Z' no customer nor stopnumber; order#502901
          lv_sortstring := null;
        when 'S' then
          --new short option 'S', to use shorter values for different field
          --customer length 10, deliverypoint 3, wearer# 6, wearer searchname 12
          lv_sortstring := lpad(to_char(fp_stopnumber), 6, 0) ||
                           lpad(substr(to_char(fp_customernumber), 1, 10), 10, 0);
        else
          lv_sortstring := substr(lpad(to_char(fp_stopnumber), 6, 0), lv_maxsortlengthstop * -1,
                                  lv_maxsortlengthstop) ||
                           substr(lpad(fp_customernumber, 12, 0), lv_maxsortlengthcustomer * -1,
                                  lv_maxsortlengthcustomer);
      end case;
      return lv_sortstring;
    end get_sortroutestop;

    procedure build_string(fp_sortfield      in sortingdefinition.sortfield%type,
                           fp_sortdescending in sortingdefinition.sortdescending%type) is
      lv_maxsortlengthwearernr number;
      lv_maxsortlengthdelpoint number;

      function isanumber(fp_string in varchar2) return number is
      begin
        return to_number(fp_string);
      exception
        when others then
          return - 1;
      end isanumber;

      function get_sort_number(fp_number in number, fp_length in number) return varchar2 is
      begin
        --get_sort_number
        if fp_sortdescending = 'Y' then
          return lpad(substr(to_char(nvl((power(10, fp_length) - 1 - nvl(fp_number, 0)), 0)), 1,
                             fp_length), fp_length, '0');
        else
          return lpad(substr(to_char(nvl(fp_number, 0)), 1, fp_length), fp_length, '0');
        end if;
      end get_sort_number;

      function get_sort_string(fp_string in varchar2, fp_length in number) return varchar2 is
      begin
        --get_sort_string
        if fp_sortdescending = 'Y' then
          return substr(convertstringdesc(rpad(nvl(fp_string, ' '), fp_length, ' ')), 1, fp_length);
        else
          return rpad(substr(nvl(fp_string, ' '), 1, fp_length), fp_length, ' ');
        end if;
      end get_sort_string;

    begin
      case fp_sortfield
        when 1 then
          begin
            --fp_departmentnumber 6
            lv_sortstring := lv_sortstring || get_sort_number(fp_departmentnumber, 6);
          end;
        when 2 then
          begin
            begin
              select to_number(s.value)
              into   lv_maxsortlengthwearernr
              from   systemsetting s
              where  s.plant_id = fp_plantid_param
              and    s.name = 'MAXSORTLENGTHWEARERNR';
            exception
              when others then
                lv_maxsortlengthwearernr := 12;
            end;
            --fp_wearernumber 6/12
            if lv_sortroutestop = 'S' then
              lv_sortstring := lv_sortstring ||
                               get_sort_number(to_number(substr(to_char(fp_wearernumber), 1, 6)), 6);
            else
              lv_sortstring := lv_sortstring ||
                               substr(get_sort_number(fp_wearernumber, 12),
                                      lv_maxsortlengthwearernr * -1, lv_maxsortlengthwearernr);
            end if;
          end;
        when 3 then
          begin
            --fp_wearername 4/20
            if lv_sortroutestop = 'S' then
              lv_sortstring := lv_sortstring || get_sort_string(fp_wearername, 4);
            else
              lv_sortstring := lv_sortstring || get_sort_string(fp_wearername, 20);
            end if;
          end;
        when 4 then
          begin
            --fp_customeremployee# 10
            lv_sortstring := lv_sortstring || get_sort_string(fp_customeremployee#, 10);
          end;
        when 5 then
          begin
            --fp_banklocker 12
            lv_sortstring := lv_sortstring || get_sort_string(case
                                                                when isanumber(fp_bank) = -1 then
                                                                 rpad(fp_bank, 6, ' ')
                                                                else
                                                                 lpad(fp_bank, 6, ' ')
                                                              end || case
                                                                when isanumber(fp_locker) = -1 then
                                                                 rpad(fp_locker, 6, ' ')
                                                                else
                                                                 lpad(fp_locker, 6, ' ')
                                                              end, 12);
          end;
        when 6 then
          begin
            --fp_gender 1
            lv_sortstring := lv_sortstring || get_sort_string(fp_gender, 1);
          end;
        when 7 then
          begin
            --fp_productcode 12
            lv_sortstring := lv_sortstring || get_sort_string(fp_productcode, 12);
          end;
        when 8 then
          begin
            --fp_sizecode 12
            lv_sortstring := lv_sortstring || get_sort_string(fp_sizecode, 12);
          end;
        when 9 then
          begin
            begin
              select to_number(s.value)
              into   lv_maxsortlengthdelpoint
              from   systemsetting s
              where  s.plant_id = fp_plantid_param
              and    s.name = 'MAXSORTLENGTHDELPOINT';
            exception
              when others then
                lv_maxsortlengthdelpoint := 12;
            end;
            --fp_deliverypointcode 3/12
            if lv_sortroutestop = 'S' then
              lv_sortstring := lv_sortstring || get_sort_string(fp_deliverypointcode, 3);
            else
              lv_sortstring := lv_sortstring || substr(get_sort_string(fp_deliverypointcode, 12), 1,
                                                       lv_maxsortlengthdelpoint);
            end if;
          end;
        when 10 then
          begin
            --fp_garmentdispensercode 6
            lv_sortstring := lv_sortstring || get_sort_string(fp_garmentdispensercode, 6);
          end;
        when 11 then
          begin
            --fp_customerownedyn 1
            if fp_customerownedyn = 'Y' then
              lv_sortstring := lv_sortstring || get_sort_number(1, 12);
            else
              lv_sortstring := lv_sortstring || get_sort_number(0, 12);
            end if;
          end;
        when 12 then
          begin
            --fp_ordernumber 8
            lv_sortstring := lv_sortstring || get_sort_string(fp_ordernumber, 8);
          end;
        when 13 then
          begin
            --fp_bank 6
            lv_sortstring := lv_sortstring || get_sort_string(fp_bank, 6);
          end;
        when 14 then
          begin
            --fp_productsortgroupseq 3
            lv_sortstring := lv_sortstring || get_sort_number(fp_productsortgroupseq, 3);
          end;
        when 15 then
          begin
            --fp_lockersortgroup# 3
            lv_sortstring := lv_sortstring || get_sort_number(fp_lockersortgroup#, 3);
          end;
        when 16 then
          begin
            --fp_distributionpoint# 2
            lv_sortstring := lv_sortstring || get_sort_number(fp_distributionpoint#, 2);
          end;
        when 17 then
          begin
            --lv_sequencenumber, 3
            select nvl(max(ps.sequencenumber), 0)
            into   lv_sequencenumber
            from   productsize ps
            join   product p
            on     p.product_id = ps.product_id
            join   sizedefinition s
            on     s.sizedefinition_id = ps.sizedefinition_id
            where  p.code = fp_productcode
            and    s.code = fp_sizecode;
            lv_sortstring := lv_sortstring || get_sort_number(lv_sequencenumber, 3);
          end;
        when 18 then
          begin
            --fp_seasoncode
            lv_sortstring := lv_sortstring || get_sort_string(fp_seasoncode, 6);
          end;
        else
          begin
            write_logging('sortfield ' || fp_sortfield || ' unknown/not implemented', fp_loglevel,
                          'pack_sort2.buildsortstring', fp_plantid_param, 3);
          end;
      end case;
    end build_string;
  begin
    --check sortcustomer
    if fp_sortcustomerid is null then
      lv_customernumber := fp_customernumber;
    else
      begin
        select nvl(max(c.customernumber), 0)
        into   lv_customernumber
        from   customer c
        where  c.customer_id = fp_sortcustomerid;
      end;
    end if;
    lv_sortstring := get_sortroutestop(fp_plantid_param, fp_stopnumber, lv_customernumber);
    lv_cnt        := 0;
    if fp_sortcustomerid is not null then
      for vcursor in (select s.sortfield, s.sortdescending, s.stackchange,
                             (select count(t.sortingdefinition_id)
                               from   sortingdefinition t
                               where  t.customer_id = s.customer_id
                               and    t.stackchange = 'Y') stackyescount
                      from   sortingdefinition s
                      where  s.customer_id = fp_sortcustomerid
                      order  by s.priority asc) loop
        begin
          lv_cnt := lv_cnt + 1;
          exit when(fp_stackchange = 'Y' and vcursor.stackyescount = 0);
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    if lv_cnt = 0 then
      for vcursor in (select s.sortfield, s.sortdescending, s.stackchange,
                             (select count(t.sortingdefinition_id)
                               from   sortingdefinition t
                               where  t.customer_id = s.customer_id
                               and    t.stackchange = 'Y') stackyescount
                      from   sortingdefinition s
                      where  s.customer_id = fp_customerid
                      order  by s.priority asc) loop
        begin
          lv_cnt := lv_cnt + 1;
          exit when(fp_stackchange = 'Y' and vcursor.stackyescount = 0);
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    if lv_cnt = 0 then
      for vcursor in (select s.sortfield, s.sortdescending, s.stackchange,
                             (select count(t.sortingdefinition_id)
                               from   sortingdefinition t
                               where  t.plant_id = s.plant_id
                               and    t.stackchange = 'Y') stackyescount
                      from   sortingdefinition s
                      where  s.plant_id = fp_plantid_param
                      order  by s.priority asc) loop
        begin
          exit when(fp_stackchange = 'Y' and vcursor.stackyescount = 0);
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    begin
      select max(s.value)
      into   lv_sortstringlength
      from   systemsetting s
      where  s.plant_id = fp_plantid_param
      and    s.name = 'SORTSTRINGLENGTH';
      if lv_sortstringlength = 2 then
        lv_sortstringlength := 80;
      else
        lv_sortstringlength := 60;
      end if;
    exception
      when others then
        lv_sortstringlength := 60;
    end;
    return substr(lv_sortstring, 1, lv_sortstringlength);
  end buildsortstring;

  procedure getdeliverydaysmask(fp_customerid      in customer.customer_id%type,
                                fp_deliverydaymask out nocopy varchar2) is
  begin
    -- delivery day mask
    fp_deliverydaymask := 'NNNNNNN';
    for ddm in (select x.day_id
                from   customerdeliveryday x
                where  x.customer_id = fp_customerid
                and    x.typeofmerchadise = 2) loop
      begin
        fp_deliverydaymask := substr(fp_deliverydaymask, 1, ddm.day_id - 1) ||
                              replace(substr(fp_deliverydaymask, ddm.day_id, 1), 'N', 'Y') ||
                              substr(fp_deliverydaymask, ddm.day_id + 1, 7);
      end;
    end loop;
  end getdeliverydaysmask;

  function get_plpcid_info(fp_customerid                in customer.customer_id%type,
                           fp_productid                 in product.product_id%type,
                           fp_sizeid                    in sizedefinition.sizedefinition_id%type,
                           fp_finishingmethodid         in finishingmethod.finishingmethod_id%type,
                           fp_date                      in date,
                           fp_maxwashes                 in out nocopy productlistpercustomer.maxwashes%type,
                           fp_billingmethod             out nocopy productlistpercustomer.billingmethod%type,
                           fp_chargewashesonlyforcog    out nocopy productlistpercustomer.chargewashesonlyforcog%type,
                           fp_numwashesspecialtreatment out nocopy productlistpercustomer.numberwashesspecialtreatment%type,
                           fp_plpc_washingprocessid     out nocopy productlistpercustomer.washingprocess_id%type,
                           fp_plpc_soilcountmethod      out nocopy productlistpercustomer.soilcountmethod%type)
    return number is
    lv_plpcid number;
  begin
    --get_plpcid
    gv_message := 'get_plpcid_info';
    begin
      select l.productlistpercustomer_id,
             case
               when l.maxwashes > 0 then
                l.maxwashes
               else
                fp_maxwashes
             end, l.billingmethod, l.chargewashesonlyforcog, l.numberwashesspecialtreatment,
             l.washingprocess_id, l.soilcountmethod
      into   lv_plpcid, fp_maxwashes, fp_billingmethod, fp_chargewashesonlyforcog,
             fp_numwashesspecialtreatment, fp_plpc_washingprocessid, fp_plpc_soilcountmethod
      from   productlistpercustomer l
      where  l.customer_id = fp_customerid
      and    l.product_id = fp_productid
      and    l.sizedefinition_id = fp_sizeid
      and    l.finishingmethod_id = fp_finishingmethodid
      and    fp_date between l.dateactive and l.dateinactive;
    exception
      when no_data_found then
        begin
          select max(l.productlistpercustomer_id), max(l.maxwashes) maxwashes, max(l.billingmethod),
                 max(l.chargewashesonlyforcog), max(l.numberwashesspecialtreatment),
                 max(l.washingprocess_id), max(l.soilcountmethod)
          into   lv_plpcid, fp_maxwashes, fp_billingmethod, fp_chargewashesonlyforcog,
                 fp_numwashesspecialtreatment, fp_plpc_washingprocessid, fp_plpc_soilcountmethod
          from   productlistpercustomer l
          where  l.customer_id = fp_customerid
          and    l.product_id = fp_productid
          and    l.sizedefinition_id =
                 (select s.sizedefinition_id from sizedefinition s where s.code = '*')
          and    l.finishingmethod_id = fp_finishingmethodid
          and    fp_date between l.dateactive and l.dateinactive;
        end;
    end;
    if fp_maxwashes = 0 then
      fp_maxwashes := null;
    end if;
    return lv_plpcid;
  end get_plpcid_info;

  procedure getgarmentinfo(fp_idcode                  in uniqueitem.primaryid%type,
                           fp_plantcode               in plant.code%type,
                           fp_languagecode            in languages.code%type, /*optional parameter*/
                           fp_status                  out nocopy number, /*0=Ok otherwise error*/
                           fp_message                 out nocopy varchar2, /*(error) message*/
                           fp_businessunitcode        out nocopy businessunit.code%type,
                           fp_plantid_paramater       out nocopy plant.plant_id%type,
                           fp_secondaryid             out nocopy secondaryuniqueitem.secondaryid%type,
                           fp_checkpointselection     out nocopy varchar2,
                           fp_destination             out nocopy sortaddressperfinishingmeth.sortaddress%type,
                           fp_foldprogram             out nocopy varchar2,
                           fp_sortstring              out nocopy varchar2,
                           fp_alternatesortstring     out nocopy varchar2,
                           fp_stackchangeinfo         out nocopy varchar2,
                           fp_routenumber             out nocopy route.routenumber%type,
                           fp_routeday                out nocopy route.drivingday_id%type,
                           fp_stopnumber              out nocopy routestop.stopnumber%type,
                           fp_deliverydaymask         out nocopy varchar2,
                           fp_customernumber          out nocopy customer.customernumber%type,
                           fp_customername            out nocopy customer.name%type,
                           fp_customerowned           out nocopy uniqueitem.customerowned%type,
                           fp_chargerepaircog         out nocopy customer.chargerepaircog%type,
                           fp_chargerepairs           out nocopy customer.chargerepairs%type,
                           fp_departmentnumber        out nocopy department.departmentnumber%type,
                           fp_departmentdesc          out nocopy department.description%type,
                           fp_deliverypointcode       out nocopy deliverypoint.code%type,
                           fp_deliverypointdesc       out nocopy deliverypoint.description%type,
                           fp_street                  out nocopy varchar2,
                           fp_street2                 out nocopy varchar2,
                           fp_city                    out nocopy varchar2,
                           fp_zipcode                 out nocopy varchar2,
                           fp_distributionpointnumber out nocopy distributionpoint.distributionpointnumber%type,
                           fp_wearernumber            out nocopy wearer.wearernumber%type,
                           fp_wearerfullname          out nocopy wearer.fullname%type,
                           fp_wearersearchname        out nocopy wearer.searchname%type,
                           fp_wearerremark            out nocopy wearer.remark%type, /*infotext*/
                           fp_bank                    out nocopy varchar2,
                           fp_locker                  out nocopy varchar2,
                           fp_garmentdispensercode    out nocopy garmentdispenser.code%type,
                           fp_customeremployeenumber  out nocopy wearer.customeremployeenumber%type,
                           fp_productsortgroup        out nocopy productsortgroup.code%type,
                           fp_productcode             out nocopy product.code%type,
                           fp_packingsequence         out nocopy product.packingsequence%type,
                           fp_productdescription      out nocopy product_desc.description%type,
                           fp_productimagename        out nocopy image.imagename%type,
                           fp_finishingcodeid         out nocopy product.finishingcode_id%type,
                           fp_sizecode                out nocopy sizedefinition.code%type,
                           fp_flagcode1               out nocopy flag.code%type,
                           fp_flagcode2               out nocopy flag.code%type,
                           fp_flagcode3               out nocopy flag.code%type,
                           fp_flagcode4               out nocopy flag.code%type,
                           fp_flagsortaddress1        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagsortaddress2        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagsortaddress3        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagsortaddress4        out nocopy sortaddressperflag.sortaddress%type,
                           fp_flagdescription1        out nocopy varchar2,
                           fp_flagdescription2        out nocopy varchar2,
                           fp_flagdescription3        out nocopy varchar2,
                           fp_flagdescription4        out nocopy varchar2,
                           fp_flagfreetext1           out nocopy uniqueitemflag.freetextitem%type,
                           fp_flagfreetext2           out nocopy uniqueitemflag.freetextitem%type,
                           fp_flagfreetext3           out nocopy uniqueitemflag.freetextitem%type,
                           fp_flagfreetext4           out nocopy uniqueitemflag.freetextitem%type,
                           fp_lastinscandate          out nocopy date,
                           fp_lastoutscandate         out nocopy date,
                           fp_lastscandate            out nocopy date,
                           fp_washestotal             out nocopy uniqueitem.washestotal%type,
                           fp_repairstotal            out nocopy uniqueitem.repairstotal%type,
                           fp_rewashtotal             out nocopy uniqueitem.rewashtotal%type,
                           fp_maxwashes               out nocopy product.maxwashes%type,
                           fp_seasoncode              out nocopy season.code%type,
                           fp_residualvalueamount     out nocopy residualvaluehistory.residualvalueamount%type,
                           fp_residualvaluepercentage out nocopy residualvaluehistory.residualvaluepercentage%type,
                           fp_batchnumber             out nocopy uniqueitem.batchnumber%type) is
    lv_logname                    varchar2(64);
    lv_loglevel                   systemsetting.value%type;
    lv_languageid                 languages.language_id%type;
    lv_timezonehrsdiff            plant.timezonehrsdiff%type;
    lv_typeofmerchandise          product.typeofmerchandise%type;
    lv_customerid                 customer.customer_id%type;
    lv_sortcustomerid             customer.sortcustomer_id%type;
    lv_departmentid               department.department_id%type;
    lv_deliverypointid            deliverypoint.deliverypoint_id%type;
    lv_deliverypoint_eutid        deliverypoint.deliverypoint_id%type;
    lv_visitaddressid             address.address_id%type;
    lv_plpcid                     productlistpercustomer.productlistpercustomer_id%type;
    lv_distributionpointid        distributionpoint.distributionpoint_id%type;
    lv_gender                     wearer.sex%type;
    lv_rec_uniqueitem             uniqueitem%rowtype;
    lv_wearer_flagid              wearer.flag_id%type;
    lv_wearer_flagstartdate       wearer.flagstartdate%type;
    lv_employ_flagid              weareremployment.flag_id%type;
    lv_employ_flagstartdate       weareremployment.flagstartdate%type;
    lv_lockersortgroupnumber      lockersortgroup.lockersortgroupnumber%type;
    lv_routestopid                number;
    lv_routeid                    number;
    lv_stopid                     number;
    lv_routecontrolid             number;
    lv_drivingdate                date;
    lv_weareremploymentid         weareremployment.weareremployment_id%type;
    lv_lockerid                   locker.locker_id%type;
    lv_garmentdispenserid         garmentdispenser.garmentdispenser_id%type;
    lv_billingmethod              productlistpercustomer.billingmethod%type;
    lv_chargewashesonlyforcog     productlistpercustomer.chargewashesonlyforcog%type;
    lv_numwashesspecialtreatment  productlistpercustomer.numberwashesspecialtreatment%type;
    lv_qtytobereturneddecreasemax wearerinventory.qtytobereturneddecreasemax%type;
    lv_legacyproductcode          product.legacyproductcode%type;
    lv_productlongdescription     product_desc.longdescription%type;
    lv_productgroupdescription    productgroup_desc.description%type;
    lv_productgroupcode           productgroup.code%type;
    lv_shortdescription           product.shortdescription%type;
    lv_fabriccode                 fabric.code%type;
    lv_fabricdescription          fabric_desc.description%type;
    lv_colorcode                  color.code%type;
    lv_colordescription           color_desc.description%type;
    lv_theoreticalweight          product.theoreticalweight%type;
    lv_weighingcategoryid         product.weighingcategory_id%type;
    lv_plpc_washingprocessid      productlistpercustomer.washingprocess_id%type;
    lv_plpc_soilcountmethod       productlistpercustomer.soilcountmethod%type;
    lv_product_washingprocessid   product.washingprocess_id%type;

    procedure initialization is
    begin
      gv_message := 'initialization';
      lv_logname := 'getgarmentinfo';
      fp_status  := 0;
      --get info for fp_plantcode
      if fp_plantcode is null then
        begin
          gv_message := 'parameter fp_plantcode cannot be left blank!';
          raise gv_user__exception;
        end;
      else
        begin
          gv_message := 'Retrieving plant code ' || fp_plantcode;
          select p.plant_id, p.timezonehrsdiff, p.language_id
          into   fp_plantid_paramater, lv_timezonehrsdiff, lv_languageid
          from   plant p
          where  p.code = fp_plantcode;
        end;
      end if;
      lv_loglevel := get_loglevel(fp_plantid_paramater, 'SORTLOGGETGARMENTDATA');
      if fp_idcode is null then
        begin
          gv_message := 'parameter fp_idcode cannot be left blank!';
          raise gv_user__exception;
        end;
      end if;
      if fp_languagecode is not null then
        begin
          --get language id
          gv_message := 'Retrieving language code ' || fp_languagecode;
          select l.language_id into lv_languageid from languages l where l.code = fp_languagecode;
        end;
      end if;
    end initialization;

    procedure return_uniqueitem_values is
    begin
      --return_uniqueitem_values
      gv_message         := 'return_uniqueitem_values';
      fp_lastinscandate  := lv_rec_uniqueitem.lastinscandate;
      fp_lastoutscandate := lv_rec_uniqueitem.lastoutscandate;
      fp_lastscandate    := lv_rec_uniqueitem.lastscandate;
      fp_washestotal     := lv_rec_uniqueitem.washestotal;
      fp_repairstotal    := lv_rec_uniqueitem.repairstotal;
      fp_rewashtotal     := lv_rec_uniqueitem.rewashtotal;
      fp_customerowned   := lv_rec_uniqueitem.customerowned;
      fp_batchnumber     := lv_rec_uniqueitem.batchnumber;
    end return_uniqueitem_values;

    procedure get_address_info is
      procedure return_nulladdress is
      begin
        fp_street  := null;
        fp_street2 := null;
        fp_city    := null;
        fp_zipcode := null;
      end return_nulladdress;
    begin
      --get_address_info
      gv_message := 'get_address_info';
      if lv_visitaddressid is null then
        begin
          return_nulladdress;
        end;
      else
        begin
          select ad.street, ad.street2, ad.city, ad.zipcode
          into   fp_street, fp_street2, fp_city, fp_zipcode
          from   address ad
          where  ad.address_id = lv_visitaddressid;
        exception
          when no_data_found then
            begin
              return_nulladdress;
            end;
        end;
      end if;
    end get_address_info;

    procedure alternatesortstring is
      lv_sortpackseq systemsetting.value%type;
    begin
      gv_message := 'alternatesortstring';
      -- Alternate Sort String
      if fp_alternatesortstring = 'Y' then
        fp_alternatesortstring := to_char(fp_packingsequence);
      else
        fp_alternatesortstring := '';
      end if;
      -- Sort on packing sequence, if SORTPACKINGSEQUENCE = Y.
      -- packing sequence will be added in front of the product code
      select min(s.value)
      into   lv_sortpackseq
      from   systemsetting s
      where  s.plant_id = fp_plantid_paramater
      and    s.name = 'SORTPACKINGSEQUENCE';
      if nvl(lv_sortpackseq, 'N') = 'Y' then
        fp_productcode := lpad(to_char(fp_packingsequence), 9, '0') ||
                          lpad(trim(fp_productcode), 9, '0');
      end if;
    end alternatesortstring;

    procedure get_flags(fp_wearer_flagid        in wearer.flag_id%type,
                        fp_wearer_flagstartdate in wearer.flagstartdate%type,
                        fp_employ_flagid        in weareremployment.flag_id%type,
                        fp_employ_flagstartdate in weareremployment.flagstartdate%type) is
      lv_inscan         dialogs.dialog_id%type;
      lv_checkpointscan dialogs.dialog_id%type;
      lv_counter        number;
      lv_confirm        varchar2(1);

      procedure init_flag is
      begin
        --init_flag
        gv_message := 'get_flags.init_flag';
        lv_counter := 1;
        select dialog_id into lv_inscan from dialogs where dialogs.code = 'InScan';
        select dialog_id into lv_checkpointscan from dialogs where dialogs.code = 'CheckPointScan';
      end init_flag;
    begin
      --get_flags
      init_flag;
      for xf in (select f.flag_id, f.code,
                        (select spf.sortaddress
                          from   sortaddressperflag spf
                          where  spf.plant_id = fp_plantid_paramater
                          and    spf.flag_id = f.flag_id) sortaddress,
                        (select fd.description
                          from   flag_desc fd
                          where  fd.language_id = lv_languageid
                          and    fd.flag_id = f.flag_id) description,
                        (select uf.freetextitem
                          from   uniqueitemflag uf
                          where  uf.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id
                          and    uf.flag_id = f.flag_id
                          and    uf.startdate <= trunc(sysdate)) freetextitem
                 from   flag f
                 where  f.flag_id in
                        (case when fp_wearer_flagstartdate <= trunc(sysdate) then fp_wearer_flagid else null end,
                         case when fp_employ_flagstartdate <= trunc(sysdate) then fp_employ_flagid else null end)
                 or     exists (select uf.flag_id
                         from   uniqueitemflag uf
                         where  uf.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id
                         and    uf.flag_id = f.flag_id
                         and    uf.startdate <= trunc(sysdate))
                 order  by f.showalways desc, f.priority) loop
        begin
          --first we check the plantflagoptions, if exist, ok use em.
          select decode(max(po.confirm), 'Y', '0', 'N', '1', '2')
          into   lv_confirm
          from   plantflagoptions po
          where  po.flag_id = xf.flag_id
          and    po.plant_id = fp_plantid_paramater
          and    po.dialog_id in (lv_inscan, lv_checkpointscan)
          and    po.show = 'Y';
          if nvl(lv_confirm, '2') = '2' then
            --when confirm = 2 then no_data_found plantflagoptions, so check normal flagoptions
            select decode(max(o.confirm), 'Y', '0', 'N', '1', '2')
            into   lv_confirm
            from   flagoptions o
            where  o.flag_id = xf.flag_id
            and    o.dialog_id in (lv_inscan, lv_checkpointscan)
            and    o.show = 'Y';
          end if;
          if lv_confirm <> '2' then
            begin
              case lv_counter
                when 1 then
                  fp_flagcode1        := xf.code;
                  fp_flagsortaddress1 := xf.sortaddress;
                  fp_flagdescription1 := xf.description;
                  fp_flagfreetext1    := xf.freetextitem;
                when 2 then
                  fp_flagcode2        := xf.code;
                  fp_flagsortaddress2 := xf.sortaddress;
                  fp_flagdescription2 := xf.description;
                  fp_flagfreetext2    := xf.freetextitem;
                when 3 then
                  fp_flagcode3        := xf.code;
                  fp_flagsortaddress3 := xf.sortaddress;
                  fp_flagdescription3 := xf.description;
                  fp_flagfreetext3    := xf.freetextitem;
                when 4 then
                  fp_flagcode4        := xf.code;
                  fp_flagsortaddress4 := xf.sortaddress;
                  fp_flagdescription4 := xf.description;
                  fp_flagfreetext4    := xf.freetextitem;
                else
                  exit;
              end case;
              lv_counter := lv_counter + 1;
            end;
          end if;
        end;
      end loop;
    end get_flags;

    procedure determine_route is
      procedure no_routeinfo is
      begin
        fp_routenumber := null;
        fp_routeday    := null;
        fp_stopnumber  := null;
      end no_routeinfo;
    begin
      gv_message := 'determine_route';
      if lv_customerid is null then
        begin
          no_routeinfo;
        end;
      else
        begin
          lv_plpcid := get_plpcid_info(lv_customerid, lv_rec_uniqueitem.product_id,
                                       lv_rec_uniqueitem.sizedefinition_id,
                                       lv_rec_uniqueitem.finishingmethod_id, trunc(sysdate),
                                       fp_maxwashes, lv_billingmethod, lv_chargewashesonlyforcog,
                                       lv_numwashesspecialtreatment, lv_plpc_washingprocessid,
                                       lv_plpc_soilcountmethod);
          if lv_plpcid is null then
            begin
              lv_routeid := null;
            end;
          else
            begin
              if gv_databasecode = 'EUT' then
                begin
                  --for customer EUT, we use the wearer consump.delpoint instead to get the route
                  lv_deliverypointid := lv_deliverypoint_eutid;
                end;
              end if;
              pack_deliverybasics.determinedeldaterouteclean(fp_plantid_paramater, lv_customerid,
                                                             lv_deliverypointid, lv_departmentid,
                                                             lv_typeofmerchandise,
                                                             trunc(sysdate + 1), lv_plpcid,
                                                             lv_distributionpointid, 'N'
                                                             /*log*/, lv_routestopid, lv_routeid,
                                                             lv_stopid, lv_routecontrolid,
                                                             lv_drivingdate);
            end;
          end if;
          --get routeinfo
          select r.routenumber, r.drivingday_id
          into   fp_routenumber, fp_routeday
          from   route r
          where  r.route_id = lv_routeid;
          --get stopnumber
          if lv_stopid is not null then
            begin
              select max(s.stopnumber) into fp_stopnumber from stop s where s.stop_id = lv_stopid;
            end;
          else
            begin
              select max(rs.stopnumber)
              into   fp_stopnumber
              from   routestop rs
              where  rs.routestop_id = lv_routestopid;
            end;
          end if;
        exception
          when no_data_found then
            begin
              no_routeinfo;
            end;
        end;
      end if;
    end determine_route;

  begin
    --getgarmentinfo initialization
    initialization;
    --get uniqueitem
    get_uniqueitem(fp_idcode, fp_plantcode, fp_plantid_paramater, lv_rec_uniqueitem, fp_secondaryid);
    --return_uniqueitem_values
    return_uniqueitem_values;
    --get uniqueitem_info
    get_uniqueitem_info(fp_plantid_paramater, lv_rec_uniqueitem, lv_languageid, 'N',
                        fp_businessunitcode, fp_customernumber, lv_customerid, lv_sortcustomerid,
                        fp_customername, fp_chargerepaircog, fp_chargerepairs,
                        fp_checkpointselection, fp_departmentnumber, fp_departmentdesc,
                        lv_departmentid, fp_deliverypointcode, fp_deliverypointdesc,
                        lv_deliverypointid, lv_deliverypoint_eutid, lv_visitaddressid,
                        fp_distributionpointnumber, lv_distributionpointid, fp_wearernumber,
                        fp_wearerfullname, fp_wearersearchname, fp_wearerremark, lv_gender, fp_bank,
                        fp_locker, fp_garmentdispensercode, lv_wearer_flagid,
                        lv_wearer_flagstartdate, lv_employ_flagid, lv_employ_flagstartdate,
                        fp_customeremployeenumber, fp_productcode, fp_productdescription,
                        lv_legacyproductcode, lv_shortdescription, lv_productlongdescription,
                        lv_product_washingprocessid, fp_productimagename, fp_finishingcodeid,
                        fp_productsortgroup, lv_productgroupcode, lv_productgroupdescription,
                        fp_packingsequence, lv_typeofmerchandise, lv_theoreticalweight, fp_sizecode,
                        lv_lockersortgroupnumber, fp_alternatesortstring, fp_destination,
                        fp_foldprogram, fp_maxwashes, fp_seasoncode, fp_residualvalueamount,
                        fp_residualvaluepercentage, lv_weareremploymentid, lv_lockerid,
                        lv_garmentdispenserid, lv_qtytobereturneddecreasemax, lv_fabriccode,
                        lv_fabricdescription, lv_colorcode, lv_colordescription,
                        lv_weighingcategoryid);
    --get_address_info
    get_address_info;
    --alternatesortstring
    alternatesortstring;
    --get_flags
    get_flags(lv_wearer_flagid, lv_wearer_flagstartdate, lv_employ_flagid, lv_employ_flagstartdate);
    --determine route
    determine_route;
    --get sortstring
    fp_sortstring := pack_sort2.buildsortstring(fp_productcode, fp_sizecode, fp_customernumber,
                                                lv_customerid, fp_wearernumber, fp_wearerfullname,
                                                fp_bank, fp_locker, fp_departmentnumber,
                                                fp_customeremployeenumber, lv_gender,
                                                fp_garmentdispensercode, fp_deliverypointcode,
                                                fp_stopnumber, fp_plantid_paramater,
                                                lv_rec_uniqueitem.customerowned, null
                                                /*fp_ordernumber*/, fp_productsortgroup,
                                                lv_lockersortgroupnumber, fp_distributionpointnumber,
                                                lv_sortcustomerid, fp_seasoncode, 'N'
                                                /*fp_stackchange*/, lv_loglevel);
    --get stackchange
    fp_stackchangeinfo := pack_sort2.buildsortstring(fp_productcode, fp_sizecode, fp_customernumber,
                                                     lv_customerid, fp_wearernumber,
                                                     fp_wearerfullname, fp_bank, fp_locker,
                                                     fp_departmentnumber, fp_customeremployeenumber,
                                                     lv_gender, fp_garmentdispensercode,
                                                     fp_deliverypointcode, fp_stopnumber,
                                                     fp_plantid_paramater,
                                                     lv_rec_uniqueitem.customerowned, null
                                                     /*fp_ordernumber*/, fp_productsortgroup,
                                                     lv_lockersortgroupnumber,
                                                     fp_distributionpointnumber, lv_sortcustomerid,
                                                     fp_seasoncode, 'Y' /*fp_stackchange*/,
                                                     lv_loglevel);
    --deliverydaymask
    getdeliverydaysmask(lv_customerid, fp_deliverydaymask);
  exception
    --error handling
    when gv_user__exception then
      begin
        fp_status := 5;
        rollback;
        fp_message := 'Error, status 5; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when no_data_found then
      begin
        rollback;
        fp_status  := 1; --no_data_found
        fp_message := 'No data found, status 1; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when too_many_rows then
      begin
        rollback;
        fp_status  := 2; --too many rows
        fp_message := 'Too many rows, status 2; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when dup_val_on_index then
      begin
        rollback;
        fp_status  := 3; --dup_val_on_index
        fp_message := 'Dup val on index, status 3; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when others then
      begin
        rollback;
        fp_status := 4; --others
        write_logging('Error others, status 4; ' || gv_message || ' for parameters ID code ' ||
                      nvl(fp_idcode, 'NULL') || ' plant code ' || nvl(fp_plantcode, 'NULL') ||
                      ' see debug info!', lv_loglevel, lv_logname, fp_plantid_paramater, 3, 0);
        fp_message := 'Error others, status 4; ' || sqlerrm;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 5, 0);
      end;
  end getgarmentinfo;

  procedure getgarmentinfo_2(fp_idcode                    in uniqueitem.primaryid%type,
                             fp_plantcode                 in plant.code%type,
                             fp_languagecode              in languages.code%type, /*optional parameter*/
                             fp_status                    out nocopy number, /*0=Ok otherwise error*/
                             fp_message                   out nocopy varchar2, /*(error) message*/
                             fp_businessunitcode          out nocopy businessunit.code%type,
                             fp_plantid_paramater         out nocopy plant.plant_id%type,
                             fp_secondaryid               out nocopy secondaryuniqueitem.secondaryid%type,
                             fp_checkpointselection       out nocopy varchar2,
                             fp_destination               out nocopy sortaddressperfinishingmeth.sortaddress%type,
                             fp_foldprogram               out nocopy varchar2,
                             fp_sortstring                out nocopy varchar2,
                             fp_alternatesortstring       out nocopy varchar2,
                             fp_stackchangeinfo           out nocopy varchar2,
                             fp_routenumber               out nocopy route.routenumber%type,
                             fp_routeday                  out nocopy route.drivingday_id%type,
                             fp_stopnumber                out nocopy routestop.stopnumber%type,
                             fp_deliverydaymask           out nocopy varchar2,
                             fp_customernumber            out nocopy customer.customernumber%type,
                             fp_customername              out nocopy customer.name%type,
                             fp_customerowned             out nocopy uniqueitem.customerowned%type,
                             fp_chargerepaircog           out nocopy customer.chargerepaircog%type,
                             fp_chargerepairs             out nocopy customer.chargerepairs%type,
                             fp_departmentnumber          out nocopy department.departmentnumber%type,
                             fp_departmentdesc            out nocopy department.description%type,
                             fp_deliverypointcode         out nocopy deliverypoint.code%type,
                             fp_deliverypointdesc         out nocopy deliverypoint.description%type,
                             fp_street                    out nocopy varchar2,
                             fp_street2                   out nocopy varchar2,
                             fp_city                      out nocopy varchar2,
                             fp_zipcode                   out nocopy varchar2,
                             fp_distributionpointnumber   out nocopy distributionpoint.distributionpointnumber%type,
                             fp_wearernumber              out nocopy wearer.wearernumber%type,
                             fp_wearerfullname            out nocopy wearer.fullname%type,
                             fp_wearersearchname          out nocopy wearer.searchname%type,
                             fp_wearerremark              out nocopy wearer.remark%type, /*infotext*/
                             fp_bank                      out nocopy varchar2,
                             fp_locker                    out nocopy varchar2,
                             fp_garmentdispensercode      out nocopy garmentdispenser.code%type,
                             fp_customeremployeenumber    out nocopy wearer.customeremployeenumber%type,
                             fp_productsortgroup          out nocopy productsortgroup.code%type,
                             fp_productcode               out nocopy product.code%type,
                             fp_typeofmerchandise         out nocopy product.typeofmerchandise%type,
                             fp_packingsequence           out nocopy product.packingsequence%type,
                             fp_productdescription        out nocopy product_desc.description%type,
                             fp_productimagename          out nocopy image.imagename%type,
                             fp_finishingcodeid           out nocopy product.finishingcode_id%type,
                             fp_sizecode                  out nocopy sizedefinition.code%type,
                             fp_flagcode1                 out nocopy flag.code%type,
                             fp_flagcode2                 out nocopy flag.code%type,
                             fp_flagcode3                 out nocopy flag.code%type,
                             fp_flagcode4                 out nocopy flag.code%type,
                             fp_flagsortaddress1          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagsortaddress2          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagsortaddress3          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagsortaddress4          out nocopy sortaddressperflag.sortaddress%type,
                             fp_flagdescription1          out nocopy varchar2,
                             fp_flagdescription2          out nocopy varchar2,
                             fp_flagdescription3          out nocopy varchar2,
                             fp_flagdescription4          out nocopy varchar2,
                             fp_flagfreetext1             out nocopy uniqueitemflag.freetextitem%type,
                             fp_flagfreetext2             out nocopy uniqueitemflag.freetextitem%type,
                             fp_flagfreetext3             out nocopy uniqueitemflag.freetextitem%type,
                             fp_flagfreetext4             out nocopy uniqueitemflag.freetextitem%type,
                             fp_lastinscandate            out nocopy date,
                             fp_lastoutscandate           out nocopy date,
                             fp_lastscandate              out nocopy date,
                             fp_washestotal               out nocopy uniqueitem.washestotal%type,
                             fp_repairstotal              out nocopy uniqueitem.repairstotal%type,
                             fp_rewashtotal               out nocopy uniqueitem.rewashtotal%type,
                             fp_maxwashes                 out nocopy product.maxwashes%type,
                             fp_seasoncode                out nocopy season.code%type,
                             fp_residualvalueamount       out nocopy residualvaluehistory.residualvalueamount%type,
                             fp_residualvaluepercentage   out nocopy residualvaluehistory.residualvaluepercentage%type,
                             fp_batchnumber               out nocopy uniqueitem.batchnumber%type,
                             fp_legacyproductcode         out nocopy product.legacyproductcode%type,
                             fp_productlongdescription    out nocopy product_desc.longdescription%type,
                             fp_productgroupdescription   out nocopy productgroup_desc.description%type,
                             fp_productgroupcode          out nocopy productgroup.code%type,
                             fp_shortdescription          out nocopy product.shortdescription%type,
                             fp_fabriccode                out nocopy fabric.code%type,
                             fp_fabricdescription         out nocopy fabric_desc.description%type,
                             fp_colorcode                 out nocopy color.code%type,
                             fp_colordescription          out nocopy color_desc.description%type,
                             fp_theoreticalweight         out nocopy product.theoreticalweight%type,
                             fp_weighingcategoryid        out nocopy product.weighingcategory_id%type,
                             fp_plpc_soilcountmethod      out nocopy productlistpercustomer.soilcountmethod%type,
                             fp_ownership                 out nocopy varchar2,
                             fp_weighingcategorycode      out nocopy weighingcategory.code%type,
                             fp_weighingcategorydescrip   out nocopy weighingcategory_desc.description%type,
                             fp_washingprocesscode        out nocopy washingprocess.code%type,
                             fp_washingprocessdescription out nocopy washingprocess_desc.description%type,
                             fp_washingprocsortingadress  out nocopy washingprocess.sortcode%type) is
    lv_logname                    varchar2(64);
    lv_loglevel                   systemsetting.value%type;
    lv_languageid                 languages.language_id%type;
    lv_timezonehrsdiff            plant.timezonehrsdiff%type;
    lv_customerid                 customer.customer_id%type;
    lv_sortcustomerid             customer.sortcustomer_id%type;
    lv_departmentid               department.department_id%type;
    lv_deliverypointid            deliverypoint.deliverypoint_id%type;
    lv_deliverypoint_eutid        deliverypoint.deliverypoint_id%type;
    lv_visitaddressid             address.address_id%type;
    lv_plpcid                     productlistpercustomer.productlistpercustomer_id%type;
    lv_distributionpointid        distributionpoint.distributionpoint_id%type;
    lv_gender                     wearer.sex%type;
    lv_rec_uniqueitem             uniqueitem%rowtype;
    lv_wearer_flagid              wearer.flag_id%type;
    lv_wearer_flagstartdate       wearer.flagstartdate%type;
    lv_employ_flagid              weareremployment.flag_id%type;
    lv_employ_flagstartdate       weareremployment.flagstartdate%type;
    lv_lockersortgroupnumber      lockersortgroup.lockersortgroupnumber%type;
    lv_routestopid                number;
    lv_routeid                    number;
    lv_stopid                     number;
    lv_routecontrolid             number;
    lv_drivingdate                date;
    lv_weareremploymentid         weareremployment.weareremployment_id%type;
    lv_lockerid                   locker.locker_id%type;
    lv_garmentdispenserid         garmentdispenser.garmentdispenser_id%type;
    lv_billingmethod              productlistpercustomer.billingmethod%type;
    lv_chargewashesonlyforcog     productlistpercustomer.chargewashesonlyforcog%type;
    lv_numwashesspecialtreatment  productlistpercustomer.numberwashesspecialtreatment%type;
    lv_qtytobereturneddecreasemax wearerinventory.qtytobereturneddecreasemax%type;
    lv_product_washingprocessid   product.washingprocess_id%type;
    lv_plpc_washingprocessid      productlistpercustomer.washingprocess_id%type;

    procedure initialization is
    begin
      gv_message := 'initialization';
      lv_logname := 'getgarmentinfo';
      fp_status  := 0;
      --get info for fp_plantcode
      if fp_plantcode is null then
        begin
          gv_message := 'parameter fp_plantcode cannot be left blank!';
          raise gv_user__exception;
        end;
      else
        begin
          gv_message := 'Retrieving plant code ' || fp_plantcode;
          select p.plant_id, p.timezonehrsdiff, p.language_id
          into   fp_plantid_paramater, lv_timezonehrsdiff, lv_languageid
          from   plant p
          where  p.code = fp_plantcode;
        end;
      end if;
      lv_loglevel := get_loglevel(fp_plantid_paramater, 'SORTLOGGETGARMENTDATA');
      if fp_idcode is null then
        begin
          gv_message := 'parameter fp_idcode cannot be left blank!';
          raise gv_user__exception;
        end;
      end if;
      if fp_languagecode is not null then
        begin
          --get language id
          gv_message := 'Retrieving language code ' || fp_languagecode;
          select l.language_id into lv_languageid from languages l where l.code = fp_languagecode;
        end;
      end if;
    end initialization;

    procedure return_uniqueitem_values is
    begin
      --return_uniqueitem_values
      gv_message         := 'return_uniqueitem_values';
      fp_lastinscandate  := lv_rec_uniqueitem.lastinscandate;
      fp_lastoutscandate := lv_rec_uniqueitem.lastoutscandate;
      fp_lastscandate    := lv_rec_uniqueitem.lastscandate;
      fp_washestotal     := lv_rec_uniqueitem.washestotal;
      fp_repairstotal    := lv_rec_uniqueitem.repairstotal;
      fp_rewashtotal     := lv_rec_uniqueitem.rewashtotal;
      fp_customerowned   := lv_rec_uniqueitem.customerowned;
      fp_batchnumber     := lv_rec_uniqueitem.batchnumber;
    end return_uniqueitem_values;

    procedure get_address_info is
      procedure return_nulladdress is
      begin
        fp_street  := null;
        fp_street2 := null;
        fp_city    := null;
        fp_zipcode := null;
      end return_nulladdress;
    begin
      --get_address_info
      gv_message := 'get_address_info';
      if lv_visitaddressid is null then
        begin
          return_nulladdress;
        end;
      else
        begin
          select ad.street, ad.street2, ad.city, ad.zipcode
          into   fp_street, fp_street2, fp_city, fp_zipcode
          from   address ad
          where  ad.address_id = lv_visitaddressid;
        exception
          when no_data_found then
            begin
              return_nulladdress;
            end;
        end;
      end if;
    end get_address_info;

    procedure alternatesortstring is
      lv_sortpackseq systemsetting.value%type;
    begin
      gv_message := 'alternatesortstring';
      -- Alternate Sort String
      if fp_alternatesortstring = 'Y' then
        fp_alternatesortstring := to_char(fp_packingsequence);
      else
        fp_alternatesortstring := '';
      end if;
      -- Sort on packing sequence, if SORTPACKINGSEQUENCE = Y.
      -- packing sequence will be added in front of the product code
      select min(s.value)
      into   lv_sortpackseq
      from   systemsetting s
      where  s.plant_id = fp_plantid_paramater
      and    s.name = 'SORTPACKINGSEQUENCE';
      if nvl(lv_sortpackseq, 'N') = 'Y' then
        fp_productcode := lpad(to_char(fp_packingsequence), 9, '0') ||
                          lpad(trim(fp_productcode), 9, '0');
      end if;
    end alternatesortstring;

    procedure get_flags(fp_wearer_flagid        in wearer.flag_id%type,
                        fp_wearer_flagstartdate in wearer.flagstartdate%type,
                        fp_employ_flagid        in weareremployment.flag_id%type,
                        fp_employ_flagstartdate in weareremployment.flagstartdate%type) is
      lv_inscan         dialogs.dialog_id%type;
      lv_checkpointscan dialogs.dialog_id%type;
      lv_counter        number;
      lv_confirm        varchar2(1);

      procedure init_flag is
      begin
        --init_flag
        gv_message := 'get_flags.init_flag';
        lv_counter := 1;
        select dialog_id into lv_inscan from dialogs where dialogs.code = 'InScan';
        select dialog_id into lv_checkpointscan from dialogs where dialogs.code = 'CheckPointScan';
      end init_flag;
    begin
      --get_flags
      init_flag;
      for xf in (select f.flag_id, f.code,
                        (select spf.sortaddress
                          from   sortaddressperflag spf
                          where  spf.plant_id = fp_plantid_paramater
                          and    spf.flag_id = f.flag_id) sortaddress,
                        (select fd.description
                          from   flag_desc fd
                          where  fd.language_id = lv_languageid
                          and    fd.flag_id = f.flag_id) description,
                        (select uf.freetextitem
                          from   uniqueitemflag uf
                          where  uf.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id
                          and    uf.flag_id = f.flag_id
                          and    uf.startdate <= trunc(sysdate)) freetextitem
                 from   flag f
                 where  f.flag_id in
                        (case when fp_wearer_flagstartdate <= trunc(sysdate) then fp_wearer_flagid else null end,
                         case when fp_employ_flagstartdate <= trunc(sysdate) then fp_employ_flagid else null end)
                 or     exists (select uf.flag_id
                         from   uniqueitemflag uf
                         where  uf.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id
                         and    uf.flag_id = f.flag_id
                         and    uf.startdate <= trunc(sysdate))
                 order  by f.showalways desc, f.priority) loop
        begin
          --first we check the plantflagoptions, if exist, ok use em.
          select decode(max(po.confirm), 'Y', '0', 'N', '1', '2')
          into   lv_confirm
          from   plantflagoptions po
          where  po.flag_id = xf.flag_id
          and    po.plant_id = fp_plantid_paramater
          and    po.dialog_id in (lv_inscan, lv_checkpointscan)
          and    po.show = 'Y';
          if nvl(lv_confirm, '2') = '2' then
            --when confirm = 2 then no_data_found plantflagoptions, so check normal flagoptions
            select decode(max(o.confirm), 'Y', '0', 'N', '1', '2')
            into   lv_confirm
            from   flagoptions o
            where  o.flag_id = xf.flag_id
            and    o.dialog_id in (lv_inscan, lv_checkpointscan)
            and    o.show = 'Y';
          end if;
          if lv_confirm <> '2' then
            begin
              case lv_counter
                when 1 then
                  fp_flagcode1        := xf.code;
                  fp_flagsortaddress1 := xf.sortaddress;
                  fp_flagdescription1 := xf.description;
                  fp_flagfreetext1    := xf.freetextitem;
                when 2 then
                  fp_flagcode2        := xf.code;
                  fp_flagsortaddress2 := xf.sortaddress;
                  fp_flagdescription2 := xf.description;
                  fp_flagfreetext2    := xf.freetextitem;
                when 3 then
                  fp_flagcode3        := xf.code;
                  fp_flagsortaddress3 := xf.sortaddress;
                  fp_flagdescription3 := xf.description;
                  fp_flagfreetext3    := xf.freetextitem;
                when 4 then
                  fp_flagcode4        := xf.code;
                  fp_flagsortaddress4 := xf.sortaddress;
                  fp_flagdescription4 := xf.description;
                  fp_flagfreetext4    := xf.freetextitem;
                else
                  exit;
              end case;
              lv_counter := lv_counter + 1;
            end;
          end if;
        end;
      end loop;
    end get_flags;

    procedure determine_route is
      procedure no_routeinfo is
      begin
        fp_routenumber := null;
        fp_routeday    := null;
        fp_stopnumber  := null;
      end no_routeinfo;
    begin
      gv_message := 'determine_route';
      if lv_customerid is null then
        begin
          no_routeinfo;
        end;
      else
        begin
          lv_plpcid := get_plpcid_info(lv_customerid, lv_rec_uniqueitem.product_id,
                                       lv_rec_uniqueitem.sizedefinition_id,
                                       lv_rec_uniqueitem.finishingmethod_id, trunc(sysdate),
                                       fp_maxwashes, lv_billingmethod, lv_chargewashesonlyforcog,
                                       lv_numwashesspecialtreatment, lv_plpc_washingprocessid,
                                       fp_plpc_soilcountmethod);
          if lv_plpcid is null then
            begin
              lv_routeid := null;
            end;
          else
            begin
              if gv_databasecode = 'EUT' then
                begin
                  --for customer EUT, we use the wearer consump.delpoint instead to get the route
                  lv_deliverypointid := lv_deliverypoint_eutid;
                end;
              end if;
              if lv_rec_uniqueitem.poolitem = 2 then
                begin
                  --do not determine the route for any pool item, because if it is pool we do not know
                  --where it needs to go to next
                  pack_deliverybasics.determinedeldaterouteclean(fp_plantid_paramater,
                                                                 lv_customerid, lv_deliverypointid,
                                                                 lv_departmentid,
                                                                 fp_typeofmerchandise,
                                                                 trunc(sysdate + 1), lv_plpcid,
                                                                 lv_distributionpointid, 'N'
                                                                 /*log*/, lv_routestopid, lv_routeid,
                                                                 lv_stopid, lv_routecontrolid,
                                                                 lv_drivingdate);
                end;
              end if;
            end;
          end if;
          --get routeinfo
          select r.routenumber, r.drivingday_id
          into   fp_routenumber, fp_routeday
          from   route r
          where  r.route_id = lv_routeid;
          --get stopnumber
          if lv_stopid is not null then
            begin
              select max(s.stopnumber) into fp_stopnumber from stop s where s.stop_id = lv_stopid;
            end;
          else
            begin
              select max(rs.stopnumber)
              into   fp_stopnumber
              from   routestop rs
              where  rs.routestop_id = lv_routestopid;
            end;
          end if;
        exception
          when no_data_found then
            begin
              no_routeinfo;
            end;
        end;
      end if;
    end determine_route;

    procedure get_ownership is
    begin
      --get_ownership
      case lv_rec_uniqueitem.poolitem
        when 0 then
          fp_ownership := 'On stock';
        when 1 then
          if lv_rec_uniqueitem.relatedcustomer_id is null then
            fp_ownership := 'GeneralPool';
          else
            fp_ownership := 'CustomerRelatedPool';
          end if;
        when 2 then
          fp_ownership := 'Personalized';
        when 3 then
          fp_ownership := 'OR Pack';
        else
          fp_ownership := 'Unknown';
      end case;
    end get_ownership;

    procedure get_weighingcategory_info is
    begin
      --get_weighingcategory_info
      if fp_weighingcategoryid is null then
        begin
          fp_weighingcategorycode    := null;
          fp_weighingcategorydescrip := null;
        end;
      else
        begin
          select wc.code,
                 (select wcd.description
                   from   weighingcategory_desc wcd
                   where  wcd.weighingcategory_id = wc.weighingcategory_id
                   and    wcd.language_id = lv_languageid)
          into   fp_weighingcategorycode, fp_weighingcategorydescrip
          from   weighingcategory wc
          where  wc.weighingcategory_id = fp_weighingcategoryid;
        end;
      end if;
    end get_weighingcategory_info;

    procedure get_washingprocess_info is
    begin
      --get_washingprocess_info
      if nvl(lv_plpc_washingprocessid, lv_product_washingprocessid) is null then
        begin
          fp_washingprocesscode        := null;
          fp_washingprocessdescription := null;
        end;
      else
        begin
          select wp.code,
                 (select swp.sortaddress
                   from   sortaddressperwashprocess swp
                   where  swp.washingprocess_id = wp.washingprocess_id
                   and    swp.plant_id = fp_plantid_paramater),
                 (select wpd.description
                   from   washingprocess_desc wpd
                   where  wpd.washingprocess_id = wp.washingprocess_id
                   and    wpd.language_id = lv_languageid)
          into   fp_washingprocesscode, fp_washingprocsortingadress, fp_washingprocessdescription
          from   washingprocess wp
          where  wp.washingprocess_id = nvl(lv_plpc_washingprocessid, lv_product_washingprocessid);
        end;
      end if;
    end get_washingprocess_info;
  begin
    --getgarmentinfo initialization
    initialization;
    --get uniqueitem
    get_uniqueitem(fp_idcode, fp_plantcode, fp_plantid_paramater, lv_rec_uniqueitem, fp_secondaryid);
    --return_uniqueitem_values
    return_uniqueitem_values;
    --get uniqueitem_info
    get_uniqueitem_info(fp_plantid_paramater, lv_rec_uniqueitem, lv_languageid, 'N',
                        fp_businessunitcode, fp_customernumber, lv_customerid, lv_sortcustomerid,
                        fp_customername, fp_chargerepaircog, fp_chargerepairs,
                        fp_checkpointselection, fp_departmentnumber, fp_departmentdesc,
                        lv_departmentid, fp_deliverypointcode, fp_deliverypointdesc,
                        lv_deliverypointid, lv_deliverypoint_eutid, lv_visitaddressid,
                        fp_distributionpointnumber, lv_distributionpointid, fp_wearernumber,
                        fp_wearerfullname, fp_wearersearchname, fp_wearerremark, lv_gender, fp_bank,
                        fp_locker, fp_garmentdispensercode, lv_wearer_flagid,
                        lv_wearer_flagstartdate, lv_employ_flagid, lv_employ_flagstartdate,
                        fp_customeremployeenumber, fp_productcode, fp_productdescription,
                        fp_legacyproductcode, fp_shortdescription, fp_productlongdescription,
                        lv_product_washingprocessid, fp_productimagename, fp_finishingcodeid,
                        fp_productsortgroup, fp_productgroupcode, fp_productgroupdescription,
                        fp_packingsequence, fp_typeofmerchandise, fp_theoreticalweight, fp_sizecode,
                        lv_lockersortgroupnumber, fp_alternatesortstring, fp_destination,
                        fp_foldprogram, fp_maxwashes, fp_seasoncode, fp_residualvalueamount,
                        fp_residualvaluepercentage, lv_weareremploymentid, lv_lockerid,
                        lv_garmentdispenserid, lv_qtytobereturneddecreasemax, fp_fabriccode,
                        fp_fabricdescription, fp_colorcode, fp_colordescription,
                        fp_weighingcategoryid);
    --get_address_info
    get_address_info;
    --alternatesortstring
    alternatesortstring;
    --get_flags
    get_flags(lv_wearer_flagid, lv_wearer_flagstartdate, lv_employ_flagid, lv_employ_flagstartdate);
    --determine route
    determine_route;
    --get sortstring
    fp_sortstring := pack_sort2.buildsortstring(fp_productcode, fp_sizecode, fp_customernumber,
                                                lv_customerid, fp_wearernumber, fp_wearerfullname,
                                                fp_bank, fp_locker, fp_departmentnumber,
                                                fp_customeremployeenumber, lv_gender,
                                                fp_garmentdispensercode, fp_deliverypointcode,
                                                fp_stopnumber, fp_plantid_paramater,
                                                lv_rec_uniqueitem.customerowned, null
                                                /*fp_ordernumber*/, fp_productsortgroup,
                                                lv_lockersortgroupnumber, fp_distributionpointnumber,
                                                lv_sortcustomerid, fp_seasoncode, 'N'
                                                /*fp_stackchange*/, lv_loglevel);
    --get stackchange
    fp_stackchangeinfo := pack_sort2.buildsortstring(fp_productcode, fp_sizecode, fp_customernumber,
                                                     lv_customerid, fp_wearernumber,
                                                     fp_wearerfullname, fp_bank, fp_locker,
                                                     fp_departmentnumber, fp_customeremployeenumber,
                                                     lv_gender, fp_garmentdispensercode,
                                                     fp_deliverypointcode, fp_stopnumber,
                                                     fp_plantid_paramater,
                                                     lv_rec_uniqueitem.customerowned, null
                                                     /*fp_ordernumber*/, fp_productsortgroup,
                                                     lv_lockersortgroupnumber,
                                                     fp_distributionpointnumber, lv_sortcustomerid,
                                                     fp_seasoncode, 'Y' /*fp_stackchange*/,
                                                     lv_loglevel);
    --deliverydaymask
    getdeliverydaysmask(lv_customerid, fp_deliverydaymask);
    --get_ownership
    get_ownership;
    --get_weighingcategory_info
    get_weighingcategory_info;
    --get_washingprocess_info
    get_washingprocess_info;
  exception
    --error handling
    when gv_user__exception then
      begin
        fp_status := 5;
        rollback;
        fp_message := 'Error, status 5; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when no_data_found then
      begin
        rollback;
        fp_status  := 1; --no_data_found
        fp_message := 'No data found, status 1; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when too_many_rows then
      begin
        rollback;
        fp_status  := 2; --too many rows
        fp_message := 'Too many rows, status 2; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when dup_val_on_index then
      begin
        rollback;
        fp_status  := 3; --dup_val_on_index
        fp_message := 'Dup val on index, status 3; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 3, 0);
      end;
    when others then
      begin
        rollback;
        fp_status := 4; --others
        write_logging('Error others, status 4; ' || gv_message || ' for parameters ID code ' ||
                      nvl(fp_idcode, 'NULL') || ' plant code ' || nvl(fp_plantcode, 'NULL') ||
                      ' see debug info!', lv_loglevel, lv_logname, fp_plantid_paramater, 3, 0);
        fp_message := 'Error others, status 4; ' || sqlerrm;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      fp_plantid_paramater, 5, 0);
      end;
  end getgarmentinfo_2;

  procedure sendtrackinfo(fp_idcode            in uniqueitem.primaryid%type,
                          fp_plantcode         in plant.code%type,
                          fp_languagecode      in languages.code%type default null, /*optional parameter*/
                          fp_datep             in number, --YYYYMMDD
                          fp_timep             in number, --HHMMSS,
                          fp_locationcode      in varchar2,
                          fp_nextlocationcode  in varchar2 default null,
                          fp_notenumber        in number default null, --Packingnotenumber for outscan only
                          fp_status            out nocopy number, /*0=Ok otherwise error*/
                          fp_message           out nocopy varchar2, /*(error) message*/
                          fp_flagcode1         in varchar2 default null,
                          fp_flagcode2         in varchar2 default null,
                          fp_flagcode3         in varchar2 default null,
                          fp_flagcode4         in varchar2 default null,
                          fp_sortbatchnumber   in number default null,
                          fp_productlegacycode in varchar2 default null,
                          fp_repairsdone       in varchar2 default null,
                          fp_pickupdate        in number default null,
                          fp_retransferyn      in varchar2 default 'N',
                          fp_metricon          in varchar2 default 'N') is
    lv_logname                    varchar2(64);
    lv_loglevel                   systemsetting.value%type;
    lv_languageid                 languages.language_id%type;
    lv_timezonehrsdiff            plant.timezonehrsdiff%type;
    lv_plantid_parameter          plant.plant_id%type;
    lv_rec_uniqueitem             uniqueitem%rowtype;
    lv_secondaryid                secondaryuniqueitem.secondaryid%type;
    lv_scandate                   date;
    lv_transactiontp              sortingimportdefinition.transactiontype%type;
    lv_workstationid              workstation.workstation_id%type;
    lv_workstationcode            workstation.code%type;
    lv_plantdepartmentid          plantdepartment.plantdepartment_id%type;
    lv_packingnoteid              packingnote.packingnote_id%type;
    lv_pn_statuscode              status.code%type;
    lv_systemuserid               systemuser.systemuser_id%type;
    lv_businessunitcode           businessunit.code%type;
    lv_customernumber             customer.customernumber%type;
    lv_customerid                 customer.customer_id%type;
    lv_sortcustomerid             customer.sortcustomer_id%type;
    lv_customername               customer.name%type;
    lv_chargerepaircog            customer.chargerepaircog%type;
    lv_chargerepairs              customer.chargerepairs%type;
    lv_checkpointselection        serviceteam.sortaddress%type; --fp_checkpointselection
    lv_departmentnumber           department.departmentnumber%type;
    lv_departmentdesc             department.description%type;
    lv_departmentid               department.department_id%type;
    lv_deliverypointcode          deliverypoint.code%type;
    lv_deliverypointdesc          deliverypoint.description%type;
    lv_deliverypointid            deliverypoint.deliverypoint_id%type;
    lv_deliverypoint_eutid        deliverypoint.deliverypoint_id%type;
    lv_visitaddressid             address.address_id%type;
    lv_distributionpointnumber    distributionpoint.distributionpointnumber%type;
    lv_distributionpointid        distributionpoint.distributionpoint_id%type;
    lv_wearernumber               wearer.wearernumber%type;
    lv_wearerfullname             wearer.fullname%type;
    lv_wearersearchname           wearer.searchname%type;
    lv_wearerremark               wearer.remark%type; /*infotext*/
    lv_gender                     wearer.sex%type;
    lv_bank                       locker.bank%type;
    lv_locker                     locker.locker%type;
    lv_garmentdispensercode       garmentdispenser.code%type;
    lv_wearer_flagid              wearer.flag_id%type;
    lv_wearer_flagstartdate       wearer.flagstartdate%type;
    lv_employ_flagid              weareremployment.flag_id%type;
    lv_employ_flagstartdate       weareremployment.flagstartdate%type;
    lv_customeremployeenumber     wearer.customeremployeenumber%type;
    lv_productcode                product.code%type;
    lv_productdescription         product_desc.description%type;
    lv_productimagename           image.imagename%type;
    lv_finishingcodeid            product.finishingcode_id%type;
    lv_productsortgroup           productsortgroup.code%type;
    lv_packingsequence            product.packingsequence%type;
    lv_typeofmerchandise          product.typeofmerchandise%type;
    lv_sizecode                   sizedefinition.code%type;
    lv_lockersortgroupnumber      lockersortgroup.lockersortgroupnumber%type;
    lv_alternatesortstring        customer.alternatesorting%type;
    lv_destination                sortaddressperfinishingmeth.sortaddress%type;
    lv_foldprogram                foldingprogramdefinition.foldingprogram%type;
    lv_maxwashes                  product.maxwashes%type;
    lv_seasoncode                 season.code%type;
    lv_residualvalueamount        residualvaluehistory.residualvalueamount%type;
    lv_residualvaluepercentage    residualvaluehistory.residualvaluepercentage%type;
    lv_weareremploymentid         weareremployment.weareremployment_id%type;
    lv_lockerid                   locker.locker_id%type;
    lv_garmentdispenserid         garmentdispenser.garmentdispenser_id%type;
    lv_pickupdate                 date;
    lv_deliveryscan_ynf           varchar2(1);
    lv_plpcid                     productlistpercustomer.productlistpercustomer_id%type;
    lv_billingmethod              productlistpercustomer.billingmethod%type;
    lv_chargewashesonlyforcog     productlistpercustomer.chargewashesonlyforcog%type;
    lv_use_treatmentcheck         systemsetting.value%type;
    lv_deliverydetermination      systemsetting.value%type;
    lv_numwashesspecialtreatment  productlistpercustomer.numberwashesspecialtreatment%type;
    lv_scanbyroute                systemsetting.value%type;
    lv_qtytobereturneddecreasemax wearerinventory.qtytobereturneddecreasemax%type;
    lv_routestopid                number;
    lv_routeid                    number;
    lv_stopid                     number;
    lv_routecontrolid             number;
    lv_drivingdate                date;
    lv_legacyproductcode          product.legacyproductcode%type;
    lv_productlongdescription     product_desc.longdescription%type;
    lv_productgroupdescription    productgroup_desc.description%type;
    lv_productgroupcode           productgroup.code%type;
    lv_shortdescription           product.shortdescription%type;
    lv_fabriccode                 fabric.code%type;
    lv_fabricdescription          fabric_desc.description%type;
    lv_colorcode                  color.code%type;
    lv_colordescription           color_desc.description%type;
    lv_theoreticalweight          product.theoreticalweight%type;
    lv_weighingcategoryid         product.weighingcategory_id%type;
    lv_plpc_washingprocessid      productlistpercustomer.washingprocess_id%type;
    lv_plpc_soilcountmethod       productlistpercustomer.soilcountmethod%type;
    lv_product_washingprocessid   product.washingprocess_id%type;

    procedure initialization is
    begin
      gv_message := 'initialization';
      lv_logname := 'sendtrackinfo';
      fp_status  := 0;
      --get info for fp_plantcode
      if fp_plantcode is null then
        begin
          gv_message := 'parameter fp_plantcode cannot be left blank!';
          raise gv_user__exception;
        end;
      else
        begin
          gv_message := 'Retrieving plant code ' || fp_plantcode;
          select p.plant_id, nvl(p.timezonehrsdiff, 0), p.language_id
          into   lv_plantid_parameter, lv_timezonehrsdiff, lv_languageid
          from   plant p
          where  p.code = fp_plantcode;
        end;
      end if;
      lv_loglevel := get_loglevel(lv_plantid_parameter, 'SORTLOGSENDTRACKINFO');
      if fp_idcode is null then
        begin
          gv_message := 'parameter fp_idcode cannot be left blank!';
          raise gv_user__exception;
        end;
      end if;
      if fp_languagecode is not null then
        begin
          --get language id
          gv_message := 'Retrieving language code ' || fp_languagecode;
          select l.language_id into lv_languageid from languages l where l.code = fp_languagecode;
        end;
      end if;
      --get uniqueitem
      get_uniqueitem(fp_idcode, fp_plantcode, lv_plantid_parameter, lv_rec_uniqueitem,
                     lv_secondaryid);
      --get uniqueitem_info
      get_uniqueitem_info(lv_plantid_parameter, lv_rec_uniqueitem, lv_languageid, 'Y',
                          lv_businessunitcode, lv_customernumber, lv_customerid, lv_sortcustomerid,
                          lv_customername, lv_chargerepaircog, lv_chargerepairs,
                          lv_checkpointselection, lv_departmentnumber, lv_departmentdesc,
                          lv_departmentid, lv_deliverypointcode, lv_deliverypointdesc,
                          lv_deliverypointid, lv_deliverypoint_eutid, lv_visitaddressid,
                          lv_distributionpointnumber, lv_distributionpointid, lv_wearernumber,
                          lv_wearerfullname, lv_wearersearchname, lv_wearerremark, lv_gender,
                          lv_bank, lv_locker, lv_garmentdispensercode, lv_wearer_flagid,
                          lv_wearer_flagstartdate, lv_employ_flagid, lv_employ_flagstartdate,
                          lv_customeremployeenumber, lv_productcode, lv_productdescription,
                          lv_legacyproductcode, lv_shortdescription, lv_productlongdescription,
                          lv_product_washingprocessid, lv_productimagename, lv_finishingcodeid,
                          lv_productsortgroup, lv_productgroupcode, lv_productgroupdescription,
                          lv_packingsequence, lv_typeofmerchandise, lv_theoreticalweight,
                          lv_sizecode, lv_lockersortgroupnumber, lv_alternatesortstring,
                          lv_destination, lv_foldprogram, lv_maxwashes, lv_seasoncode,
                          lv_residualvalueamount, lv_residualvaluepercentage, lv_weareremploymentid,
                          lv_lockerid, lv_garmentdispenserid, lv_qtytobereturneddecreasemax,
                          lv_fabriccode, lv_fabricdescription, lv_colorcode, lv_colordescription,
                          lv_weighingcategoryid);
      --check fp_productlegacycode
      if coalesce(lv_legacyproductcode, lv_productcode) <>
         coalesce(fp_productlegacycode, lv_legacyproductcode, lv_productcode) then
        begin
          null; ----not used/checked for now
        end;
      end if;
      --check data parameter
      if fp_datep is null then
        begin
          gv_message := 'parameter fp_datep cannot be left blank!';
          raise gv_user__exception;
        end;
      end if;
      --check time parameter
      if fp_timep is null then
        begin
          gv_message := 'parameter fp_timep cannot be left blank!';
          raise gv_user__exception;
        end;
      end if;
      --create scandate
      begin
        lv_scandate := to_date(to_char(fp_datep) || to_char(fp_timep), 'YYYYMMDDHH24MISS');
      exception
        when others then
          begin
            gv_message := 'Error determine scandate from fp_datep ' || to_char(fp_datep) ||
                          ' and fp_time ' || to_char(fp_timep) ||
                          ' Please use the format YYYYMMDD for fp_datep and HHMMSS for fp_time';
            raise gv_user__exception;
          end;
      end;
      --take into account the timezone difference
      if lv_timezonehrsdiff <> 0 then
        begin
          lv_scandate := lv_scandate + (lv_timezonehrsdiff / 24);
        exception
          when others then
            begin
              gv_message := 'Error determine scandate using the timezone difference ' ||
                            to_char(lv_timezonehrsdiff) || ' from the plant ' || fp_plantcode ||
                            ' for fp_datep ' || to_char(fp_datep) || ' and fp_time ' ||
                            to_char(fp_timep);
              raise gv_user__exception;
            end;
        end;
      end if;
      --check parameter fp_locationcode / fp_nextlocationcode
      if fp_locationcode is null then
        begin
          gv_message := 'parameter fp_locationcode cannot be left blank!';
          raise gv_user__exception;
        end;
      else
        begin
          select s.transactiontype, s.workstation_id, w.code, w.plantdepartment_id
          into   lv_transactiontp, lv_workstationid, lv_workstationcode, lv_plantdepartmentid
          from   sortingimportdefinition s
          join   workstation w
          on     w.workstation_id = s.workstation_id
          where  s.plant_id = lv_plantid_parameter
          and    s.location = fp_locationcode
          and    nvl(s.nextlocation, 'ISNULL') = nvl(fp_nextlocationcode, 'ISNULL');
        exception
          when no_data_found then
            begin
              gv_message := 'No data found for sortingimportdefinition for parameters fp_locationcode ' ||
                            fp_locationcode || ' and fp_nextlocationcode ' ||
                            nvl(fp_nextlocationcode, '(was left blank)') || ' for plant ' ||
                            fp_plantcode;
              raise gv_user__exception;
            end;
        end;
      end if;
      --check parameter fp_notenumber, only needed for outscan and poolitem in (1,2)
      if lv_transactiontp = 2 and lv_rec_uniqueitem.poolitem in (1, 2) then
        begin
          if lv_rec_uniqueitem.poolitem = 1 and fp_notenumber is null then
            begin
              gv_message := 'parameter fp_notenumber cannot be left blank for outscan of pool items';
              raise gv_user__exception;
            end;
          elsif fp_notenumber is not null then
            begin
              --get packingnote id
              select pk.packingnote_id, st.code,
                     nvl(lv_distributionpointid, pk.distributionpoint_id),
                     nvl(lv_deliverypointid, pk.deliverypoint_id),
                     nvl(lv_customernumber, c.customernumber), nvl(lv_customerid, t.customer_id),
                     nvl(lv_departmentid, t.department_id),
                     nvl(lv_departmentnumber, t.departmentnumber)
              into   lv_packingnoteid, lv_pn_statuscode, lv_distributionpointid, lv_deliverypointid,
                     lv_customernumber, lv_customerid, lv_departmentid, lv_departmentnumber
              from   packingnote pk
              join   distributionpoint dp
              on     dp.distributionpoint_id = pk.distributionpoint_id
              join   department t
              on     t.department_id = dp.department_id
              join   customer c
              on     c.customer_id = t.customer_id
              join   status st
              on     st.status_id = pk.status_id
              where  pk.notenumber = fp_notenumber;
              if lv_pn_statuscode in ('30', '40') then
                begin
                  if lv_rec_uniqueitem.poolitem = 2 then
                    lv_packingnoteid := null;
                  else
                    begin
                      gv_message := 'Parameter fp_notenumber ' || fp_notenumber || ' has status ' ||
                                    lv_pn_statuscode ||
                                    ' which is not allowed, (30=Processed, 40=Cancelled)';
                      raise gv_user__exception;
                    end;
                  end if;
                end;
              end if;
            exception
              when no_data_found then
                begin
                  lv_pn_statuscode := null;
                  lv_packingnoteid := null;
                  if lv_rec_uniqueitem.poolitem = 1 then
                    begin
                      gv_message := 'No data found for parameter fp_notenumber ' || fp_notenumber ||
                                    ' for outscan of pool items';
                      raise gv_user__exception;
                    end;
                  end if;
                end;
            end;
          else
            begin
              lv_pn_statuscode := null;
              lv_packingnoteid := null;
            end;
          end if;
        end;
      else
        begin
          lv_pn_statuscode := null;
          lv_packingnoteid := null;
        end;
      end if;
      --systemuser
      begin
        select s.systemuser_id into lv_systemuserid from systemuser s where s.username = 'SORT';
      exception
        when no_data_found then
          select min(systemuser_id) into lv_systemuserid from systemuser s;
      end;
      --check parameter fp_pickupdate
      if fp_pickupdate is null then
        begin
          lv_pickupdate := null;
        end;
      else
        begin
          lv_pickupdate := to_date(fp_pickupdate, 'YYYYMMDD');
        exception
          when others then
            begin
              gv_message := 'parameter fp_pickupdate ' || to_char(fp_pickupdate) ||
                            ' is not a valid date, format should be YYYYMMDD';
              raise gv_user__exception;
            end;
        end;
      end if;
      --get plpc info
      lv_plpcid := get_plpcid_info(lv_customerid, lv_rec_uniqueitem.product_id,
                                   lv_rec_uniqueitem.sizedefinition_id,
                                   lv_rec_uniqueitem.finishingmethod_id, lv_scandate, lv_maxwashes,
                                   lv_billingmethod, lv_chargewashesonlyforcog,
                                   lv_numwashesspecialtreatment, lv_plpc_washingprocessid,
                                   lv_plpc_soilcountmethod);
      --get systemsetting SCANBYROUTE
      select nvl(max(s.value), 'N')
      into   lv_scanbyroute
      from   systemsetting s
      where  s.plant_id = lv_plantid_parameter
      and    s.name = 'SCANBYROUTE';
      if fp_retransferyn not in ('Y', 'N') then
        begin
          gv_message := 'parameter fp_retransferyn ' || fp_retransferyn ||
                        ' is not a valid, should be Y or N';
          raise gv_user__exception;
        end;
      end if;
      if fp_repairsdone not in ('Y', 'N') then
        begin
          gv_message := 'parameter fp_repairsdone ' || fp_repairsdone ||
                        ' is not a valid, should be Y or N';
          raise gv_user__exception;
        end;
      end if;
    end initialization;

    procedure createroutecontrol(fp_plannedrouteid in route.route_id%type, fp_planneddate in date) is
      lv_packingday           integer;
      lv_loadingdock          route.loadingdock%type;
      lv_packingdeadline      date;
      lv_driverid             employee.employee_id%type;
      lv_drivernumber         employee.employeenumber%type;
      lv_instructions         routestop.routelistinstructions%type;
      lv_truckid              truck.truck_id%type;
      lv_truckcode            truck.code%type;
      lv_routecontrolcreation systemsetting.value%type;
      lv_stopid               stop.stop_id%type;
      lv_status               integer;

      function iscustomervisitdate(fp_customerid customer.customer_id%type) return boolean is
        xyear integer;
        xweek integer;
        xday  integer;
        i     integer;
      begin
        i     := 0;
        xday  := getabsdaynumber(fp_planneddate);
        xweek := getisoweek(fp_planneddate);
        xyear := getyearofweek(fp_planneddate);
        for dcursor in (select d.deliveryscheme_id, x.frequency, x.offsetweek, c.day_id
                        from   customerdeliveryday c, customerdeliveryscheme d, deliveryscheme x
                        where  c.customer_id = fp_customerid
                        and    c.customer_id = d.customer_id
                        and    c.day_id = d.day_id
                        and    d.deliveryscheme_id = x.deliveryscheme_id
                        and    c.day_id = xday) loop
          begin
            if isweekdeliveryweek(xyear, xweek, dcursor.frequency, dcursor.offsetweek) then
              i := 1;
              exit;
            end if;
          end;
        end loop;
        if i = 1 then
          return true;
        else
          return false;
        end if;
      end iscustomervisitdate;

      function getstopstatus(fp_customerid customer.customer_id%type)

       return number is
        status number;
      begin
        status := -1;
        select decode((c.dateinactive - trunc(fp_planneddate)) -
                       abs(c.dateinactive - trunc(fp_planneddate)), 0, 0, 4)
        into   status
        from   customer c
        where  c.customer_id = fp_customerid
        and    c.active = 'Y'
        and    c.dateactive <= trunc(fp_planneddate);
        return status;
      exception
        when others then
          return - 1;
      end getstopstatus;
    begin
      select nvl(max(s.value), 0)
      into   lv_routecontrolcreation
      from   systemsetting s
      where  s.plant_id = lv_plantid_parameter
      and    s.name = 'ROUTECONTROLCREATION';
      if lv_routecontrolcreation < 3 then
        begin
          --do not create routecontrol
          lv_routecontrolid := null;
        end;
      else
        begin
          select r.routecontrol_id
          into   lv_routecontrolid
          from   routecontrol r
          where  r.route_id = fp_plannedrouteid
          and    trunc(r.drivingdate) = trunc(fp_planneddate);
        end;
      end if; --vroutecontrolcreation <> 3
    exception
      when no_data_found then
        begin
          ---- create RouteControl
          select r.packingday_id, r.loadingdock, r.packingdeadline, r.driver_id, r.truck_id
          into   lv_packingday, lv_loadingdock, lv_packingdeadline, lv_driverid, lv_truckid
          from   route r
          where  r.route_id = fp_plannedrouteid;
          if lv_driverid is not null then
            select e.employeenumber
            into   lv_drivernumber
            from   employee e
            where  e.employee_id = lv_driverid;
          end if;
          if lv_truckid is not null then
            -- LCO, todo 8189
            select t.code into lv_truckcode from truck t where t.truck_id = lv_truckid;
          end if;
          select seq_routecontrol.nextval into lv_routecontrolid from dual;
          insert into routecontrol
            (routecontrol_id, route_id, routelistprinted, soilticketsprinted, soilcountstatus,
             settlementstatus, packingstatus, originaldrivingdate, drivingdate, packingday_id,
             timestamp, systemuser_id, overageamount, voucheramount, totalcashcollected,
             totalcoddelayed, totalcodpaythisamnt, totalcodundelivered, totalcodplusadj,
             totalcodminusadj, totalcodprebilled, totalchargecollections, totalchargepaythisamnt,
             totalchargeundelivered, totalchargeplusadj, totalchargeminusadj, totalchargeprebilled,
             returntime, returndate, starttime, loadingdock, packingdeadline, truckcode,
             drivernumber, plant_id, invoicesgenerated, arbalance_id, pocketpcstatus, startmileage,
             endmileage, straightevenreturnstatus, routesettlementprinted, activestockcompleted,
             bulkputuproutecompleted, safetyremarks)
          values
            (lv_routecontrolid, fp_plannedrouteid, 'N', 'N', 1, 1, 1, trunc(fp_planneddate),
             trunc(fp_planneddate), lv_packingday, sysdate, lv_systemuserid, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, 0, null, null, null, lv_loadingdock, lv_packingdeadline, lv_truckcode,
             lv_drivernumber, lv_plantid_parameter, 1, null, 0, 0, 0, 0, 'N', 'N', 'N', null);
          if lv_loglevel > 0 then
            write_logging(' insert routecontrol for route id ' || fp_plannedrouteid, lv_loglevel,
                          lv_logname, lv_plantid_parameter, 1, 0);
          end if;
          --insert stops for routecontrol
          for stopcursor in (select rs.routestop_id, rs.stopnumber, rs.customer_id,
                                    rs.deliverypoint_id, rs.routelistinstructions,
                                    rs.instructionsstartdate, rs.instructionsenddate,
                                    rs.contactperson_id, rs.stoptype, rs.chargedeliveryfee
                             from   routestop rs
                             where  rs.route_id = fp_plannedrouteid
                             and    trunc(fp_planneddate) between rs.dateactive and rs.dateinactive
                             and    rs.stoptype <> 4) loop
            begin
              /*check for customer active and for stop status*/
              lv_status := getstopstatus(stopcursor.customer_id);
              if lv_status >= 0 and iscustomervisitdate(stopcursor.customer_id) then
                if (trunc(fp_planneddate) >= stopcursor.instructionsstartdate and
                   trunc(fp_planneddate) <= stopcursor.instructionsenddate) then
                  lv_instructions := stopcursor.routelistinstructions;
                else
                  lv_instructions := null;
                end if;
                insert into stop
                  (stop_id, routecontrol_id, routestop_id, customer_link_id, stopnumber,
                   arrivaltime, departuretime, travelminutes, visitminutes, routelistinstructions,
                   systemuser_id, timestamp, movedtostop_id, status, deliverypoint_id,
                   contactperson_id, stoptype, chargedeliveryfee)
                values
                  (seq_stop.nextval, lv_routecontrolid, stopcursor.routestop_id,
                   stopcursor.customer_id, stopcursor.stopnumber, null, null, 0, 0, lv_instructions,
                   lv_systemuserid, sysdate, null, lv_status, stopcursor.deliverypoint_id,
                   stopcursor.contactperson_id, stopcursor.stoptype, stopcursor.chargedeliveryfee)
                returning stop_id into lv_stopid;
                --link packingnotes to routecontrol
                update packingnote up
                set    up.routecontrol_id = lv_routecontrolid, up.stop_id = lv_stopid,
                       up.stopnumber = stopcursor.stopnumber, up.timestamp = sysdate,
                       up.systemuser_id = lv_systemuserid
                where  up.packingnote_id in
                       (select p.packingnote_id
                        from   packingnote p
                        join   deliverypoint delp
                        on     delp.deliverypoint_id = p.deliverypoint_id
                        where  p.route_id = fp_plannedrouteid
                        and    p.deliverydate = trunc(fp_planneddate)
                        and    p.deliverypoint_id =
                               coalesce(stopcursor.deliverypoint_id, p.deliverypoint_id)
                        and    p.routecontrol_id is null
                        and    delp.customer_id = stopcursor.customer_id);
                --link ClientDeliveryNote to routecontrol
                update clientdeliverynote cdn
                set    cdn.routecontrol_id = lv_routecontrolid, cdn.stop_id = lv_stopid,
                       cdn.stopnumber = stopcursor.stopnumber, cdn.timestamp = sysdate,
                       cdn.systemuser_id = lv_systemuserid
                where  cdn.clientdeliverynote_id in
                       (select cdnl.clientdeliverynote_id
                        from   clientdeliverynote cdnl
                        join   deliverypoint delp
                        on     delp.customer_id = cdnl.customer_link_id
                        where  cdnl.route_id = fp_plannedrouteid
                        and    cdnl.deliverydate = trunc(fp_planneddate)
                        and    delp.deliverypoint_id =
                               coalesce(stopcursor.deliverypoint_id, delp.deliverypoint_id)
                        and    cdnl.routecontrol_id is null
                        and    delp.deliverypoint_id =
                               (select dp.deliverypoint_id
                                 from   clientresident cr
                                 join   departmentroom de
                                 on     de.departmentroom_id = cr.departmentroom_id
                                 join   department d
                                 on     d.department_id = de.department_id
                                 join   distributionpoint dp
                                 on     dp.distributionpoint_id = de.distributionpoint_id
                                 where  cdnl.customer_link_id = stopcursor.customer_id
                                 and    cdnl.client_link_id = cr.client_id
                                 union
                                 select cp.deliverypoint_id
                                 from   clientprivateperson cp
                                 where  cdnl.customer_link_id = stopcursor.customer_id
                                 and    cdnl.client_link_id = cp.client_id));
                --link straightevenreturn to routecontrol
                update straightevenreturn us
                set    us.stop_id = lv_stopid, us.timestamp = sysdate,
                       us.systemuser_id = lv_systemuserid
                where  us.straightevenreturn_id in
                       (select s.straightevenreturn_id
                        from   straightevenreturn s
                        join   status st
                        on     st.status_id = s.status_id
                        join   distributionpoint di
                        on     di.distributionpoint_id = s.distributionpoint_id
                        join   department d
                        on     d.department_id = di.department_id
                        where  s.stop_id is null
                        and    s.pickupdate <= trunc(fp_planneddate)
                        and    d.customer_id = stopcursor.customer_id
                        and    di.deliverypoint_id =
                               nvl(stopcursor.deliverypoint_id, di.deliverypoint_id)
                        and    st.code = '10');
              end if;
            end;
          end loop;
          -- insert routecontrol internal bu
          createroutecontrolinternalbu(lv_routecontrolid , lv_systemuserid, lv_rec_uniqueitem.businessunit_id);
          -- insert RSC ExtraInfo for virtual route (if missing)
          createroutecontrolextrainfo(lv_routecontrolid, lv_systemuserid);
        end;
    end createroutecontrol;

    procedure process_scan is
      lv_scantype      varchar2(100);
      lv_scanid        scan.scan_id%type;
      lv_outscaninterv systemsetting.value%type;
      lv_countwashesat systemsetting.value%type;

      procedure create_uniqueitemflag(fp_uniqueitemid    in uniqueitem.uniqueitem_id%type,
                                      fp_flagid          in flag.flag_id%type,
                                      fp_startdate       in uniqueitemflag.startdate%type default sysdate,
                                      fp_freetextitem    in uniqueitemflag.freetextitem%type default null,
                                      fp_treatmenttypeid in uniqueitemflag.treatmenttype_id%type default null) is
      begin
        --create_uniqueitemflag
        if fp_flagid is not null then
          begin
            gv_message := 'create_uniqueitemflag fp_flagid ' || fp_flagid || ' fp_uniqueitemid ' ||
                          fp_uniqueitemid;
            insert into uniqueitemflag
              (uniqueitem_id, flag_id, startdate, freetextitem, systemuser_id, timestamp,
               treatmenttype_id)
              select fp_uniqueitemid, fp_flagid, trunc(fp_startdate), fp_freetextitem,
                     lv_systemuserid, sysdate, fp_treatmenttypeid
              from   dual
              where  not exists (select 1
                      from   uniqueitemflag uf
                      where  uf.uniqueitem_id = fp_uniqueitemid
                      and    uf.flag_id = fp_flagid);
            --create_scanflag
            if lv_scanid is not null then
              begin
                gv_message := 'create_scanflag';
                insert into scanflag
                  (scan_id, flag_id, flagresponse, systemuser_id, timestamp)
                values
                  (lv_scanid, fp_flagid, null, lv_systemuserid, sysdate);
              end;
            end if;
          end;
        end if;
      end create_uniqueitemflag;

      procedure create_generalflags is
      begin
        if lv_scanid is not null and (fp_flagcode1 is not null or fp_flagcode2 is not null or
           fp_flagcode3 is not null or fp_flagcode4 is not null) then
          begin
            --create_scanflag
            gv_message := 'create_scanflag';
            insert into scanflag
              (scan_id, flag_id, flagresponse, systemuser_id, timestamp)
              select lv_scanid, f.flag_id, null, lv_systemuserid, sysdate
              from   flag f
              join   sortaddressperflag sf
              on     sf.flag_id = f.flag_id
              where  f.flagtype = 1
              and    sf.sortaddress in (fp_flagcode1, fp_flagcode2, fp_flagcode3, fp_flagcode4)
              and    sf.plant_id = lv_plantid_parameter;
          exception
            when dup_val_on_index then
              null; --no problem scan flag is already there
            when no_data_found then
              begin
                write_logging('No data found for sortaddressperflag sortaddress(s) ' ||
                              trim(fp_flagcode1 || ' ' || fp_flagcode2 || ' ' || fp_flagcode3 || ' ' ||
                                   fp_flagcode4), lv_loglevel, lv_logname, lv_plantid_parameter, 2,
                              1);
              end;
          end;
        end if;
      end create_generalflags;

      procedure process_sortbatchnumber is
        lv_sortbatchstatus sortbatch.status%type;
      begin
        --process_sortbatchnumber
        if fp_flagcode4 = 'SBN' then
          begin
            gv_message := 'process_sortbatchnumber flagcode4 = SBN';
            select sortbatch.status
            into   lv_sortbatchstatus
            from   sortbatch
            where  sortbatch.sortbatch_id = fp_sortbatchnumber;
            if fp_status = 0 and lv_sortbatchstatus = 2 then
              update sortbatch s
              set    s.status = 3, s.closingtime = lv_scandate
              where  s.sortbatch_id = fp_sortbatchnumber;
              commit;
            elsif fp_status = 0 and lv_sortbatchstatus = 3 and lv_transactiontp = 2 then
              update sortbatch s
              set    s.status = 4, s.outscantime = lv_scandate
              where  s.sortbatch_id = fp_sortbatchnumber;
              commit;
            end if;
          exception
            when others then
              write_logging('(flagcode4 = SBN) Sortbatch_id ' || fp_sortbatchnumber ||
                            ' not updated ' || sqlerrm, lv_loglevel, lv_logname,
                            lv_plantid_parameter, 3, 1);
          end;
        end if;
      end process_sortbatchnumber;

      procedure processoutscan is
        lv_stayid_outscan stay.stay_id%type;

        procedure init_outscan is
        begin
          --init_outscan
          select stay.stay_id
          into   lv_stayid_outscan
          from   stay
          where  stay.staytype = 1
          and    stay.staynr = 20; --outscan/at customer
          --get valid status ids
          begin
            select status_id
            into   lv_rec_uniqueitem.status_id
            from   status
            where  status.code in ('20', '30') --in circulation/assigned
            and    status.statustype = 'UI'
            and    status.status_id = lv_rec_uniqueitem.status_id;
          exception
            when no_data_found then
              begin
                gv_message := 'Error wrong status for fp_idcode ' || fp_idcode ||
                              ' it is not in circulation or assigned';
                raise gv_user__exception;
              end;
          end;
        end init_outscan;

        procedure get_use_systemsettings_outscan is
        begin
          --getsystemsettings_outscan
          --OUTSCANALLOWHOURINTERVAL
          select nvl(max(s.value), 0)
          into   lv_outscaninterv
          from   systemsetting s
          where  s.name = 'OUTSCANALLOWHOURINTERVAL'
          and    s.plant_id = lv_plantid_parameter;
          --check lv_outscaninterv
          if lv_outscaninterv > 0 and lv_rec_uniqueitem.stay_id = lv_stayid_outscan and
             lv_rec_uniqueitem.lastoutscandate is not null and
             lv_outscaninterv > (lv_scandate - lv_rec_uniqueitem.lastoutscandate) * 24 then
            begin
              gv_message := '!> ID code ' || fp_idcode || ' was scanned out less then ' ||
                            to_char(lv_outscaninterv) || ' hours before';
              fp_status  := 6; --wrong scan interval
              raise gv_user__exception;
            end;
          end if;
          --COUNTWASHESAT
          select nvl(max(s.value), ' ')
          into   lv_countwashesat
          from   systemsetting s
          where  s.name = 'COUNTWASHESAT'
          and    s.plant_id = lv_plantid_parameter;
          if (lv_countwashesat = 'O' or (lv_countwashesat = 'I' and to_number(lv_outscaninterv) > 0 and
             lv_rec_uniqueitem.stay_id = lv_stayid_outscan)) then
            begin
              lv_rec_uniqueitem.washestotal := lv_rec_uniqueitem.washestotal + 1;
              if lv_rec_uniqueitem.poolitem = 2 then
                begin
                  --update unique item non pool
                  update uniqueitemnonpool u
                  set    u.washesthisissue = u.washesthisissue + 1,
                         u.systemuser_id = lv_systemuserid, u.timestamp = sysdate
                  where  u.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id;
                end;
              end if;
            end;
          end if;
          --USETREATMENTCHECK
          select nvl(max(s.value), '0')
          into   lv_use_treatmentcheck
          from   systemsetting s
          where  s.name = 'USETREATMENTCHECK'
          and    s.plant_id = lv_plantid_parameter;

          --DELIVERYDETERMINATION
          select nvl(max(s.value), ' ')
          into   lv_deliverydetermination
          from   systemsetting s
          where  s.name = 'DELIVERYDETERMINATION'
          and    s.plant_id = lv_plantid_parameter;
        end get_use_systemsettings_outscan;

        procedure check_processtrans2asoutscan is
          lv_noregularoutscan customergarmentdispenser.noregularoutscan%type;
        begin
          --check_processtrans2asoutscan
          if lv_garmentdispenserid is not null and lv_rec_uniqueitem.poolitem <> 1 then
            begin
              gv_message := 'check_processtrans2asoutscan';
              --get data from customergarmentdispenser
              select nvl((case max(cgd.processtrans2asoutscan)
                            when 'Y' then
                             'N'
                            else
                             'Y'
                          end), 'Y'), nvl(max(cgd.noregularoutscan), 0)
              into   lv_deliveryscan_ynf, lv_noregularoutscan
              from   customergarmentdispenser cgd
              where  cgd.customer_id = lv_customerid;
              if lv_noregularoutscan = 1 then
                lv_deliveryscan_ynf := 'F'; --free of charge deliveryscan
              elsif nvl(fp_metricon, 'N') <> 'Y' and lv_deliveryscan_ynf <> 'Y' then
                lv_deliveryscan_ynf := 'Y';
              end if;
            exception
              when no_data_found then
                lv_deliveryscan_ynf := 'Y';
            end;
          end if;
        end check_processtrans2asoutscan;

        procedure upd_packingnoteline is
          lv_minpackingnotelineid packingnoteline.packingnoteline_id%type;
          lv_chargewashcogchg     systemsetting.value%type;
        begin
          if lv_packingnoteid is not null then
            begin
              --upd_packingnoteline
              gv_message := 'upd_packingnoteline';
              if lv_loglevel > 0 then
                write_logging('ID code ' || fp_idcode ||
                              ' Passed PackingnoteID to Process Outscan: ' || lv_packingnoteid,
                              lv_loglevel, lv_logname, lv_plantid_parameter, 1, 1);
              end if;
              select min(p.packingnoteline_id)
              into   lv_minpackingnotelineid
              from   packingnoteline p
              where  p.packingnote_id = lv_packingnoteid
              and    p.product_id = lv_rec_uniqueitem.product_id
              and    p.sizedefinition_id = lv_rec_uniqueitem.sizedefinition_id
              and    p.finishingmethod_id = lv_rec_uniqueitem.finishingmethod_id;
              if lv_minpackingnotelineid is null then
                begin
                  gv_message := 'Error for ID code ' || fp_idcode ||
                                ' Not found Packingnoteline for packingnote ' || fp_notenumber ||
                                ' for product ' || lv_productcode || ' sizecode ' || lv_sizecode ||
                                ' packingnoteid ' || lv_packingnoteid;
                  raise gv_user__exception;
                end;
              end if;
              select nvl(max(s.value), 'N')
              into   lv_chargewashcogchg
              from   systemsetting s
              where  s.plant_id = lv_plantid_parameter
              and    s.name = 'CHARGEWASHCOGCHG/WEEK';
              if lv_rec_uniqueitem.customerowned = 'Y' and lv_chargewashesonlyforcog = 'Y' and
                 ((lv_billingmethod = 1 and lv_chargewashcogchg = 'Y') or (lv_billingmethod = 3) or
                 (lv_billingmethod = 4 and lv_typeofmerchandise in (1, 2)) or
                 (lv_billingmethod = 5)) then
                update packingnoteline pl
                set    pl.deliveredamount = nvl(pl.scannedqty, 0) + 1,
                       pl.deliveredcogqty = pl.deliveredcogqty + 1,
                       pl.scannedqty = nvl(pl.scannedqty, 0) + 1,
                       pl.systemuser_id = lv_systemuserid, pl.timestamp = sysdate
                where  pl.packingnoteline_id = lv_minpackingnotelineid;
              else
                update packingnoteline pl
                set    pl.deliveredamount =  nvl(pl.scannedqty, 0) + 1,
                       pl.scannedqty = nvl(pl.scannedqty, 0) + 1,
                       pl.systemuser_id = lv_systemuserid, pl.timestamp = sysdate
                where  pl.packingnoteline_id = lv_minpackingnotelineid;
              end if;
            end;
          end if;
        end upd_packingnoteline;

        procedure create_outscan is
        begin
          --create_outscan
          gv_message := 'create_outscan';
        end create_outscan;

        procedure create_out_scanflags is
          lv_flagid flag.flag_id%type;
        begin
          if lv_use_treatmentcheck = '0' and lv_rec_uniqueitem.washestotal <> 0 then
            begin
              if lv_maxwashes = lv_rec_uniqueitem.washestotal and lv_maxwashes <> 0 then
                begin
                  --Maximum number of washes reached
                  select max(flag_id)
                  into   lv_flagid
                  from   automaticflag a
                  where  a.automaticflag_id = 1;
                  create_uniqueitemflag(lv_rec_uniqueitem.uniqueitem_id, lv_flagid, lv_scandate,
                                        null, null);
                end;
              end if; --maxwashes
              if lv_countwashesat = 'O' and lv_numwashesspecialtreatment <> 0 and
                 mod(lv_rec_uniqueitem.washestotal, lv_numwashesspecialtreatment) = 0 then
                begin
                  select max(flag_id)
                  into   lv_flagid
                  from   automaticflag a
                  where  a.automaticflag_id = 6;
                  create_uniqueitemflag(lv_rec_uniqueitem.uniqueitem_id, lv_flagid, lv_scandate,
                                        to_char(lv_rec_uniqueitem.washestotal) || ' washes reached',
                                        null);
                end;
              end if; --lv_numwashesspecialtreatment
            end;
          end if; --lv_use_treatmentcheck
          if lv_qtytobereturneddecreasemax > 0 then
            begin
              rollback; -->rollback that what happend!
              select max(flag_id) into lv_flagid from automaticflag a where a.automaticflag_id = 7;
              create_uniqueitemflag(lv_rec_uniqueitem.uniqueitem_id, lv_flagid, lv_scandate,
                                    'Return to stock due to manual decrease of maximum inventory',
                                    null);
              commit; -->creation of flag
              fp_status  := 6;
              gv_message := 'quanity to be returned to decrease max. is ' ||
                            to_char(lv_qtytobereturneddecreasemax) ||
                            ' so return to stock due to manual decrease of maximum inventory';
              raise gv_user__exception;
            end;
          end if;
        end create_out_scanflags;

        procedure process_route is

          procedure determineroute is
          begin
            --determinedeldaterouteclean
            pack_deliverybasics.determinedeldaterouteclean(lv_plantid_parameter, lv_customerid,
                                                           lv_deliverypointid, lv_departmentid,
                                                           lv_typeofmerchandise, trunc(sysdate + 1),
                                                           lv_plpcid, lv_distributionpointid, 'N',
                                                           lv_routestopid, lv_routeid, lv_stopid,
                                                           lv_routecontrolid, lv_drivingdate);
          end determineroute;
        begin
          --process_route
          if lv_scanbyroute = 'Y' then
            begin
              select ur.plannedoutroute_id, ur.plannedoutdate, ur.plannedoutstop_id
              into   lv_routeid, lv_drivingdate, lv_stopid
              from   uniqueitemroute ur
              where  ur.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id;
              if not (nvl(lv_drivingdate, trunc(sysdate - 1)) >= trunc(sysdate) and
                  lv_routeid is not null and lv_routestopid is not null) then
                begin
                  determineroute;
                end;
              end if;
              -- update uniqueitemroute u
              update uniqueitemroute u
              set    u.lastoutroute_id = lv_routeid, u.lastoutdate = lv_scandate,
                     u.plannedoutroute_id = null, u.plannedoutdate = null,
                     u.plannedoutstop_id = null, u.systemuser_id = lv_systemuserid,
                     u.timestamp = sysdate, lastoutstop_id = lv_stopid
              where  u.uniqueitem_id = lv_rec_uniqueitem.uniqueitem_id;
            exception
              when no_data_found then
                begin
                  determineroute;
                  --insert into uniqueitemroute
                  insert into uniqueitemroute
                    (uniqueitem_id, lastinroute_id, lastoutroute_id, plannedoutroute_id, lastindate,
                     lastoutdate, plannedoutdate, plannedoutstop_id, systemuser_id, timestamp,
                     lastoutstop_id)
                  values
                    (lv_rec_uniqueitem.uniqueitem_id, null, lv_routeid, null, null, lv_drivingdate,
                     null, null, lv_systemuserid, sysdate, lv_stopid);
                end;
            end;
            --createroutecontrol
            createroutecontrol(lv_routeid, lv_scandate);
          else
            begin
              --set values to null
              lv_routestopid    := null;
              lv_routeid        := null;
              lv_stopid         := null;
              lv_routecontrolid := null;
              lv_drivingdate    := null;
            end;
          end if;
        end process_route;
      begin
        --processoutscan
        gv_message := 'processoutscan';
        --init_outscan
        init_outscan;
        --get_use_systemsettings_outscan
        get_use_systemsettings_outscan;
        --check_processtrans2asoutscan
        check_processtrans2asoutscan;
        --upd_packingnoteline
        upd_packingnoteline;
        --process_route
        process_route;
        --create_outscan
        create_outscan;
        --create outscan flags
        create_out_scanflags;
      end processoutscan;
    begin
      --process_scan
      gv_message := 'process_scan';
      case lv_transactiontp
        when 1 then
          begin
            --Inscan
            gv_message  := 'processinscan';
            lv_scantype := 'InScan';
          end;
        when 2 then
          begin
            --Outscan
            gv_message  := 'processoutscan';
            lv_scantype := 'OutScan';
            processoutscan;
          end;
        when 3 then
          begin
            --Repair Scan
            gv_message  := 'processrepairscan';
            lv_scantype := 'RepairScan';
          end;
        when 6 then
          begin
            --Checkpoint scan
            gv_message  := 'processcheckpointscan';
            lv_scantype := 'CheckpointScan';
          end;
        when 7 then
          begin
            --Sort scan
            gv_message  := 'processsortscan';
            lv_scantype := 'SortScan';
          end;
        else
          begin
            gv_message := 'Error Unknown transactiontp ' || lv_transactiontp;
            raise gv_user__exception;
          end;
      end case;
      --create_generalflags
      create_generalflags;
      --process sortbatchnumber
      process_sortbatchnumber;
      --commit
      ------>commit;<------
      rollback; ----->for now test cases rollback!
      --write into log all ok
      write_logging('fp_plantcode ' || fp_plantcode || '  fp_idcode ' || fp_idcode || ' fp_datep ' ||
                    fp_datep || ' fp_timep ' || fp_timep || ' fp_locationcode ' || fp_locationcode ||
                    ' fp_nextlocationcode ' || nvl(fp_nextlocationcode, ' left blank') || ' ' ||
                    lv_scantype, lv_loglevel, lv_logname, lv_plantid_parameter, 1, 0);
    end process_scan;
  begin
    --sendtrackinfo initialization
    initialization;
    --process_scan
    process_scan;
  exception
    --error handling
    when gv_user__exception then
      begin
        if fp_status = 0 then
          fp_status := 5;
        end if;
        rollback;
        fp_message := 'Error, status ' || to_char(fp_status) || '; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      lv_plantid_parameter, 3, 0);
      end;
    when no_data_found then
      begin
        rollback;
        fp_status  := 1; --no_data_found
        fp_message := 'No data found, status 1; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      lv_plantid_parameter, 3, 0);
      end;
    when too_many_rows then
      begin
        rollback;
        fp_status  := 2; --too many rows
        fp_message := 'Too many rows, status 2; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      lv_plantid_parameter, 3, 0);
      end;
    when dup_val_on_index then
      begin
        rollback;
        fp_status  := 3; --dup_val_on_index
        fp_message := 'Dup val on index, status 3; ' || gv_message;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      lv_plantid_parameter, 3, 0);
      end;
    when others then
      begin
        rollback;
        fp_status := 4; --others
        write_logging('Error others, status 4; ' || gv_message || ' for parameters ID code ' ||
                      nvl(fp_idcode, 'NULL') || ' plant code ' || nvl(fp_plantcode, 'NULL') ||
                      ' see debug info!', lv_loglevel, lv_logname, lv_plantid_parameter, 3, 0);
        fp_message := 'Error others, status 4; ' || sqlerrm;
        write_logging(fp_message || ' for parameters ID code ' || nvl(fp_idcode, 'NULL') ||
                      ' plant code ' || nvl(fp_plantcode, 'NULL'), lv_loglevel, lv_logname,
                      lv_plantid_parameter, 5, 0);
      end;
  end sendtrackinfo;

end pack_sort2;
/
create or replace package pack_sort_rs is

  -- Author  : PVD   Version 3.6
  -- Created : 17-04-2012
  -- Updated : 18-01-2013 ToDo 21986, add sortstring option Y customer number only
  -- Updated : 13-08-2013 Sortstring when stopnumber is NULL make it 0
  -- Updated : 20-08-2013 Check on Batchnumber for labels, to skip these, using a systemsetting
  -- Updated : 22-11-2013 If route id was not known, link it now to the clientdeliverynote
  -- Updated : 24-06-2015 for WSP module counting added origin 5 for creating clientdelnoteline
  -- Update  : 19-09-2016 Check databasecode, and when looking for day use stoptype as well for routes
  -- Update  : 24-11-2016 Check customerresidentialsettings.returnitems setting for determining next deliveryday
  -- Update  : 17-06-2019 ABS-83933 GetgarmentdataRS, always create new CDN
  -- Update  : 02-07-2020 ABS-102309 reduce length sort string based on system settings
  -- Update  : 03-02-2021 ABS-114001 check RFL batch per customer
  --           29-09-2021 ABS-125019 Changes in WGID interface, beautified code
  --           06-09-2021 ABS-125019 check batchcode when use when looking up clientdeliverynote
  --           23-12-2021 ABS-127598 change get_next_deldate_tom5 in pack_sort_rs
  --           23-01-2024 ABS-160635 Pack_Sort_RS , get_uniqueitem_rs > also check SEC ID
  --           08-04-2024 ABS-163313 increase batch range for RFL in pack_sort _rs
  --           03-11-2025 ABSN-11968 pack_sort_rs.get_create_clientdelnote does not populate the roomnumber
  -- Purpose : Group of procedures en functions to support the Residential Service
  --           procedure GetGarmentDataRS
  --           And procedure SendTrackInfoRS

  procedure write_logging(fp_message    in abslog.message%type,
                          fp_loglevel   in number,
                          fp_logname    in varchar2,
                          fp_plantid    in plant.plant_id%type default null,
                          fp_priority   in number default 1,
                          fp_detailinfo in number default 0); ---0=no detail 1=detail

  function get_systemsettting(fp_plantid in plant.plant_id%type, fp_name systemsetting.name%type)
    return systemsetting.value%type;

  function get_sortstring(fp_plantid             in plant.plant_id%type,
                          fp_customerid          in customer.customer_id%type,
                          fp_customernumber      in customer.customernumber%type,
                          fp_stopnumber          in routestop.stopnumber%type,
                          fp_departmentnumber    in department.departmentnumber%type,
                          fp_clientnumber        in client.clientnumber%type,
                          fp_clientsearchname    in client.searchname%type,
                          fp_roomnumber          in departmentroom.roomnumber%type,
                          fp_productcode         in product.code%type,
                          fp_productsortgroupseq in productsortgroupperplant.sequencenumber%type,
                          fp_deliverypointcode   in deliverypoint.code%type,
                          fp_clientdeliverynote  in clientdeliverynote.clientdeliverynotenumber%type,
                          fp_departmentroomseq   in departmentroom.sequencenumber%type,
                          fp_stackchange         in sortingdefinition.stackchange%type)
    return varchar2;

  procedure get_deliverydaysmask(fp_customerid      in customer.customer_id%type,
                                 fp_deliverydaymask out nocopy varchar2);

  procedure get_uniqueitem_rs(fp_idcode                  in uniqueresidentialitem.primaryid%type,
                              fp_plantcode               in plant.code%type,
                              fp_typecall                in number, --getgarmentdate=0  sendtrackinfo=1
                              fp_plantlanguageid         out nocopy plant.language_id%type,
                              fp_uniqueresidentialitemid out nocopy uniqueresidentialitem.uniqueresidentialitem_id%type,
                              fp_plantid_parameter       out nocopy plant.plant_id%type,
                              fp_plantid_garment         out nocopy plant.plant_id%type,
                              fp_unitcode                out nocopy businessunit.code%type,
                              fp_businessunitid          out nocopy businessunit.businessunit_id%type,
                              fp_status                  out nocopy number,
                              fp_message                 out nocopy abslog.message%type,
                              fp_customernumber          out nocopy customer.customernumber%type,
                              fp_customerid              out nocopy customer.customer_id%type,
                              fp_customername            out nocopy customer.name%type,
                              fp_serviceteamid           out nocopy customer.serviceteam_id%type,
                              fp_clientnumber            out nocopy client.clientnumber%type,
                              fp_clientid                out nocopy client.client_id%type,
                              fp_clientsearchname        out nocopy client.searchname%type,
                              fp_roomnumber              out nocopy departmentroom.roomnumber%type,
                              fp_departmentroomid        out nocopy departmentroom.departmentroom_id%type,
                              fp_departmentroomseq       out nocopy departmentroom.sequencenumber%type,
                              fp_departmentnumber        out nocopy department.departmentnumber%type,
                              fp_clientadminnumber       out nocopy client.adminnumber%type,
                              fp_gender                  out nocopy client.gender%type,
                              fp_deliverypointcode       out nocopy deliverypoint.code%type,
                              fp_deliverypointid         out nocopy deliverypoint.deliverypoint_id%type,
                              fp_productcode             out nocopy product.code%type,
                              fp_productid               out nocopy product.product_id%type,
                              fp_productgroupid          out nocopy product.productgroup_id%type,
                              fp_productdescription      out nocopy product_desc.description%type,
                              fp_productcolorid          out nocopy product.color_id%type,
                              fp_sizecode                out nocopy sizedefinition.code%type,
                              fp_productsortgroup        out nocopy productsortgroup.code%type,
                              fp_productsortgroupid      out nocopy product.productsortgroup_id%type,
                              fp_sizeid                  out nocopy sizedefinition.sizedefinition_id%type,
                              fp_finishingmethodid       out nocopy finishingmethod.finishingmethod_id%type,
                              fp_infotext                out nocopy client.remark%type,
                              fp_timezonehrsdiff         out nocopy plant.timezonehrsdiff%type,
                              fp_statusid                out nocopy status.status_id%type,
                              fp_lastinscandate          out nocopy uniqueresidentialitem.lastinscandate%type,
                              fp_lastoutscandate         out nocopy uniqueresidentialitem.lastoutscandate%type,
                              fp_lastrewashdate          out nocopy uniqueresidentialitem.lastrewashdate%type,
                              fp_lastrepairdate          out nocopy uniqueresidentialitem.lastrepairdate%type,
                              fp_loglevel                out nocopy number,
                              fp_departmentid            out nocopy department.department_id%type,
                              fp_department_desc         out nocopy department.description%type,
                              fp_clientfirstlastname     out nocopy varchar2,
                              fp_productvolume           out nocopy product.volumeunits%type,
                              fp_databasecode            out nocopy databasesettings.code%type);

  procedure get_plpc_info(fp_plantid                     in plant.plant_id%type,
                          fp_customerid                  in customer.customer_id%type,
                          fp_productid                   in product.product_id%type,
                          fp_sizeid                      in sizedefinition.sizedefinition_id%type,
                          fp_finishingmethodid           in finishingmethod.finishingmethod_id%type,
                          fp_status                      out nocopy number,
                          fp_message                     out nocopy abslog.message%type,
                          fp_sortaddressperfinishingcode out nocopy sortaddressperfinishingcode.sortaddress%type);

  function get_next_deldate_tom5(fp_date_param   in date,
                                 fp_customerid   in customer.customer_id%type,
                                 fp_departmentid in department.department_id%type,
                                 fp_databasecode in varchar2) return date;

  function create_cliendelnoteline(fp_idcode               in uniqueresidentialitem.primaryid%type,
                                   fp_clientdeliverynote   in clientdeliverynote.clientdeliverynotenumber%type,
                                   fp_clientdeliverynoteid in clientdeliverynote.clientdeliverynote_id%type,
                                   fp_plantid              in plant.plant_id%type,
                                   fp_unitcode             in businessunit.code%type,
                                   fp_businessunitid       in businessunit.businessunit_id%type,
                                   fp_customerid           in customer.customer_id%type,
                                   fp_productgroupid       in productgroup.productgroup_id%type,
                                   fp_productid            in product.product_id%type,
                                   fp_sizeid               in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid    in finishingmethod.finishingmethod_id%type,
                                   fp_systemuserid         in systemuser.systemuser_id%type,
                                   fp_loglevel             in number,
                                   fp_logname              in varchar2,
                                   fp_origin               in clientdeliverynoteline.origin%type,
                                   fp_quantitycounted      in number default 0) --for counting not scanning when fp_origin = 5 only!
   return clientdeliverynoteline.clientdeliverynoteline_id%type;

  procedure create_clientdelnotescan(fp_clientdelnotelinescanid  in out clientdelnotelinescan.clientdelnotelinescan_id%type,
                                     fp_idcode                   in uniqueresidentialitem.primaryid%type,
                                     fp_clientdeliverynote       in clientdeliverynote.clientdeliverynotenumber%type,
                                     fp_clientdeliverynotelineid in clientdeliverynoteline.clientdeliverynoteline_id%type,
                                     fp_plantid                  in plant.plant_id%type,
                                     fp_unitcode                 in businessunit.code%type,
                                     fp_loglevel                 in number,
                                     fp_logname                  in varchar2,
                                     fp_systemuserid             in systemuser.systemuser_id%type,
                                     fp_uniqueresidentialitemid  in uniqueresidentialitem.uniqueresidentialitem_id%type,
                                     fp_scantype_in_out          in varchar2 default 'OUT',
                                     fp_scandate                 in date default sysdate);

  procedure get_clientdelnotescan(fp_uniqueresidentialitemid  in uniqueresidentialitem.uniqueresidentialitem_id%type,
                                  fp_businessunitid           in businessunit.businessunit_id%type,
                                  fp_update_startoutscan      in number,
                                  fp_batchid                  out nocopy batch.batch_id%type,
                                  fp_clientdelnotlinescanid   out nocopy clientdelnotelinescan.clientdelnotelinescan_id%type,
                                  fp_clientdeliverynote       out nocopy clientdeliverynote.clientdeliverynotenumber%type,
                                  fp_routid                   out nocopy route.route_id%type,
                                  fp_stopnumber               out nocopy clientdeliverynote.stopnumber%type,
                                  fp_clientdeliverynoteid     out nocopy clientdeliverynote.clientdeliverynote_id%type,
                                  fp_deliverydate             out nocopy clientdeliverynote.deliverydate%type,
                                  fp_clientdeliverynotelineid out nocopy clientdeliverynoteline.clientdeliverynoteline_id%type,
                                  fp_logname                  in varchar2 default null,
                                  fp_batchcode                in batch.batchcode%type default null);

  procedure get_create_clientdelnote(fp_uniqueresidentialitemid in uniqueresidentialitem.uniqueresidentialitem_id%type,
                                     fp_businessunitid          in businessunit.businessunit_id%type,
                                     fp_unitcode                in businessunit.code%type,
                                     fp_plantid                 in plant.plant_id%type,
                                     fp_customerid              in customer.customer_id%type,
                                     fp_clientid                in client.client_id%type,
                                     fp_productgroupid          in product.productgroup_id%type,
                                     fp_deliverypointid         in deliverypoint.deliverypoint_id%type,
                                     fp_routenumber             out nocopy route.routenumber%type,
                                     fp_routid                  out nocopy route.route_id%type,
                                     fp_routeday                out nocopy route.drivingday_id%type,
                                     fp_depot                   out nocopy depot.code%type,
                                     fp_stopnumber              out nocopy clientdeliverynote.stopnumber%type,
                                     fp_clientdeliverynote      out nocopy clientdeliverynote.clientdeliverynotenumber%type,
                                     fp_clientdeliverynoteid    out nocopy clientdeliverynote.clientdeliverynote_id%type,
                                     fp_clientdelnotlinescanid  out nocopy clientdelnotelinescan.clientdelnotelinescan_id%type,
                                     fp_out_batchid             out nocopy batch.batch_id%type,
                                     fp_status                  out nocopy number,
                                     fp_message                 out nocopy abslog.message%type,
                                     fp_update_startoutscan     in number,
                                     fp_loglevel                in number,
                                     fp_logname                 in varchar2,
                                     fp_systemuserid            in systemuser.systemuser_id%type,
                                     fp_departmentid            in department.department_id%type,
                                     fp_idcode                  in uniqueresidentialitem.primaryid%type,
                                     fp_productid               in product.product_id%type,
                                     fp_sizeid                  in sizedefinition.sizedefinition_id%type,
                                     fp_finishingmethodid       in finishingmethod.finishingmethod_id%type,
                                     fp_date_param              in date,
                                     fp_databasecode            in databasesettings.code%type,
                                     fp_in_batchid              in batch.batch_id%type default null,
                                     fp_batchcode               in batch.batchcode%type default null);

  function call_ws_printclientdelnote(fp_clientdeliverynoteid in number,
                                      fp_workstationid        in number,
                                      fp_loglevel             in number,
                                      fp_year                 in number,
                                      fp_month                in number,
                                      fp_day                  in number,
                                      fp_hours                in number,
                                      fp_minutes              in number,
                                      fp_seconds              in number,
                                      fp_milliseconds         in number,
                                      v_url                   in varchar2) return varchar2;

  procedure close_batch(fp_batch_id in batch.batch_id%type);

end pack_sort_rs;
/
create or replace package body pack_sort_rs is

  procedure write_logging(fp_message    in abslog.message%type,
                          fp_loglevel   in number,
                          fp_logname    in varchar2,
                          fp_plantid    in plant.plant_id%type default null,
                          fp_priority   in number default 1,
                          fp_detailinfo in number default 0) is ---0=no detail 1=detail
  begin
    --write_logging
    if fp_priority > 1 then
      begin
        abslogwrite.abslog_write(5, fp_logname, fp_plantid, fp_priority, fp_message);
      end;
    else
      case fp_loglevel
        when 0 then
          null; --no logging other then errors
        when 1 then
          if fp_detailinfo = 1 then
            --Log level 1 and detailinfo=1 write detail info
            abslogwrite.abslog_write(5, fp_logname, fp_plantid, fp_priority, fp_message);
          end if;
        when 2 then
          --write all logs
          abslogwrite.abslog_write(5, fp_logname, fp_plantid, fp_priority, fp_message);
        else
          null;
      end case;
    end if;
  end write_logging;

  function get_systemsettting(fp_plantid in plant.plant_id%type, fp_name systemsetting.name%type)
    return systemsetting.value%type is
    lv_value   systemsetting.value%type;
    lv_logdate date;
  begin
    select ss.value, trunc(ss.timestamp) logdate
    into   lv_value, lv_logdate
    from   systemsetting ss
    where  ss.plant_id = fp_plantid
    and    ss.name = fp_name;
    if fp_name in ('SORTLOGGETGARMENTDATAPWB', 'SORTLOGSENDTRACKINFOPWB') and lv_value <> '0' and
       lv_logdate < trunc(sysdate) then
      begin
        --turn of detailed logging
        update systemsetting ss
        set    ss.value = '0'
        where  ss.plant_id = fp_plantid
        and    ss.name = fp_name;
        lv_value := '0';
      end;
    end if;
    return lv_value;
  exception
    when no_data_found then
      return null;
    when others then
      return null;
  end get_systemsettting;

  function get_sortstring(fp_plantid             in plant.plant_id%type,
                          fp_customerid          in customer.customer_id%type,
                          fp_customernumber      in customer.customernumber%type,
                          fp_stopnumber          in routestop.stopnumber%type,
                          fp_departmentnumber    in department.departmentnumber%type,
                          fp_clientnumber        in client.clientnumber%type,
                          fp_clientsearchname    in client.searchname%type,
                          fp_roomnumber          in departmentroom.roomnumber%type,
                          fp_productcode         in product.code%type,
                          fp_productsortgroupseq in productsortgroupperplant.sequencenumber%type,
                          fp_deliverypointcode   in deliverypoint.code%type,
                          fp_clientdeliverynote  in clientdeliverynote.clientdeliverynotenumber%type,
                          fp_departmentroomseq   in departmentroom.sequencenumber%type,
                          fp_stackchange         in sortingdefinition.stackchange%type)
    return varchar2 is
    lv_sortstring varchar2(512);
    lv_counter    number;

    function get_sortroutestop(fp_plantid        in plant.plant_id%type,
                               fp_stopnumber     in stop.stopnumber%type,
                               fp_customernumber in customer.customernumber%type) return varchar2 is
      lv_sortstring            varchar2(255);
      lv_maxsortlengthstop     number;
      lv_maxsortlengthcustomer number;
      lv_sortroutestop_param   systemsetting.value%type;
    begin
      --Sort string --Stack change info
      lv_sortroutestop_param   := nvl(get_systemsettting(fp_plantid, 'SORTROUTESTOP'), 'A');
      lv_maxsortlengthstop     := nvl(to_number(get_systemsettting(fp_plantid, 'MAXSORTLENGTHSTOP')),
                                      6);
      lv_maxsortlengthcustomer := nvl(to_number(get_systemsettting(fp_plantid,
                                                                   'MAXSORTLENGTHCUSTOMER')), 12);
      case lv_sortroutestop_param
        when 'A' then
          --default is 'A' ascending
          lv_sortstring := substr(lpad(to_char(fp_stopnumber), 6, 0), lv_maxsortlengthstop * -1,
                                  lv_maxsortlengthstop) ||
                           substr(lpad(fp_customernumber, 12, 0), lv_maxsortlengthcustomer * -1,
                                  lv_maxsortlengthcustomer);
        when 'D' then
          --other option 'D' descending
          lv_sortstring := substr(lpad(to_char(999999 - fp_stopnumber), 6, 0),
                                  lv_maxsortlengthstop * -1, lv_maxsortlengthstop) ||
                           substr(lpad(999999999999 - fp_customernumber, 12, 0),
                                  lv_maxsortlengthcustomer * -1, lv_maxsortlengthcustomer);
        when 'Y' then
          --new option 'Y' is customer only export
          lv_sortstring := substr(lpad(fp_customernumber, 12, 0), lv_maxsortlengthcustomer * -1,
                                  lv_maxsortlengthcustomer);
        when 'Z' then
          --new option 'Z' no customer nor stopnumber
          lv_sortstring := null;
        when 'S' then
          --new short option 'S', to use shorter values for different field
          lv_sortstring := lpad(to_char(fp_stopnumber), 6, 0) ||
                           lpad(substr(to_char(fp_customernumber), 1, 10), 10, 0);
        else
          lv_sortstring := substr(lpad(to_char(fp_stopnumber), 6, 0), lv_maxsortlengthstop * -1,
                                  lv_maxsortlengthstop) ||
                           substr(lpad(fp_customernumber, 12, 0), lv_maxsortlengthcustomer * -1,
                                  lv_maxsortlengthcustomer);
      end case;
      return lv_sortstring;
    end get_sortroutestop;

    procedure build_string(fp_sortfield      in sortingdefinition.sortfield%type,
                           fp_sortdescending in sortingdefinition.sortdescending%type) is
      lv_maxsortlengthdelpoint number;
      function convertstringdesc(receivedstring varchar2) return varchar2 is
        aux          varchar2(1);
        newaux       varchar2(1);
        returnstring varchar2(100);
        cnt          integer;
      begin
        --convertstringdesc internal function
        returnstring := '';
        cnt          := length(receivedstring);
        if cnt > 0 then
          for i in 1 .. cnt loop
            aux := substr(receivedstring, i, 1);
            if 32 <= ascii(aux) and ascii(aux) <= 126 then
              newaux := chr(126 - (ascii(aux) - 32));
            else
              newaux := aux;
            end if;
            returnstring := returnstring || newaux;
          end loop;
        end if;
        return returnstring;
      end convertstringdesc;
    begin
      --build_string
      case fp_sortfield
        when 1 then
          begin
            --fp_departmentnumber
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring || lpad(to_char(999999 - fp_departmentnumber), 6, '0');
            else
              lv_sortstring := lv_sortstring || lpad(to_char(fp_departmentnumber), 6, '0');
            end if;
          end;
        when 2 then
          begin
            --fp_clientnumber
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring ||
                               lpad(to_char(999999999999 - fp_clientnumber), 12, '0');
            else
              lv_sortstring := lv_sortstring || lpad(to_char(fp_clientnumber), 12, '0');
            end if;
          end;
        when 3 then
          begin
            --fp_clientsearchname
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring ||
                               convertstringdesc(rpad(fp_clientsearchname, 20, ' '));
            else
              lv_sortstring := lv_sortstring || rpad(fp_clientsearchname, 20, ' ');
            end if;
          end;
        when 4 then
          begin
            --fp_roomnumber
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring || convertstringdesc(rpad(fp_roomnumber, 12, ' '));
            else
              lv_sortstring := lv_sortstring || rpad(fp_roomnumber, 12, ' ');
            end if;
          end;
        when 5 then
          --fpproductcode
          begin
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring || convertstringdesc(rpad(fp_productcode, 12, ' '));
            else
              lv_sortstring := lv_sortstring || rpad(fp_productcode, 12, ' ');
            end if;
          end;
        when 6 then
          --fp_productsortgroupseq
          begin
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring || lpad(to_char(999 - fp_productsortgroupseq), 3, '0');
            else
              lv_sortstring := lv_sortstring || lpad(to_char(fp_productsortgroupseq), 3, '0');
            end if;
          end;
        when 7 then
          begin
            --fp_deliverypointcode
            lv_maxsortlengthdelpoint := nvl(to_number(get_systemsettting(fp_plantid,
                                                                         'MAXSORTLENGTHDELPOINT')),
                                            12);
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring ||
                               substr(convertstringdesc(rpad(fp_deliverypointcode, 12, ' ')), 1,
                                      lv_maxsortlengthdelpoint);
            else
              lv_sortstring := lv_sortstring || substr(rpad(fp_deliverypointcode, 12, ' '), 1,
                                                       lv_maxsortlengthdelpoint);
            end if;
          end;
        when 8 then
          begin
            --fp_clientdeliverynote
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring ||
                               lpad(to_char(999999999999 - fp_clientdeliverynote), 12, '0');
            else
              lv_sortstring := lv_sortstring || lpad(to_char(fp_clientdeliverynote), 12, '0');
            end if;
          end;
        when 9 then
          begin
            --fp_departmentroomseq
            if fp_sortdescending = 'Y' then
              lv_sortstring := lv_sortstring || lpad(to_char(9999 - fp_departmentroomseq), 4, '0');
            else
              lv_sortstring := lv_sortstring || lpad(to_char(fp_departmentroomseq), 4, '0');
            end if;
          end;
      end case;
    end build_string;
  begin
    --get_sortstring
    lv_sortstring := get_sortroutestop(fp_plantid, nvl(fp_stopnumber, 0), fp_customernumber);
    lv_counter    := 0;
    for vcursor in (select s.sortfield, s.sortdescending, s.stackchange
                    from   sortingdefinitionrs s
                    where  s.customer_id = fp_customerid
                    order  by s.priority asc) loop
      begin
        build_string(vcursor.sortfield, vcursor.sortdescending);
        lv_counter := lv_counter + 1;
        exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
      end;
    end loop;
    if lv_counter = 0 then
      for vcursor in (select s.sortfield, s.sortdescending, s.stackchange
                      from   sortingdefinitionrs s
                      where  s.plant_id = fp_plantid
                      order  by s.priority asc) loop
        begin
          build_string(vcursor.sortfield, vcursor.sortdescending);
          exit when fp_stackchange = 'Y' and vcursor.stackchange = 'Y';
        end;
      end loop;
    end if;
    return lv_sortstring;
  end get_sortstring;

  procedure get_deliverydaysmask(fp_customerid      in customer.customer_id%type,
                                 fp_deliverydaymask out nocopy varchar2) is
  begin
    -- delivery day mask
    fp_deliverydaymask := 'NNNNNNN';
    for vcustdays in (select x.day_id
                      from   customerdeliveryday x
                      where  x.customer_id = fp_customerid
                      and    x.typeofmerchadise = 5
                      and    x.deliverytype in ('B', 'D')) loop
      begin
        fp_deliverydaymask := substr(fp_deliverydaymask, 1, vcustdays.day_id - 1) || 'Y' ||
                              substr(fp_deliverydaymask, vcustdays.day_id + 1, 7);
      end;
    end loop;
  end get_deliverydaysmask;

  procedure get_uniqueitem_rs(fp_idcode                  in uniqueresidentialitem.primaryid%type,
                              fp_plantcode               in plant.code%type,
                              fp_typecall                in number, --getgarmentdate=0  sendtrackinfo=1
                              fp_plantlanguageid         out nocopy plant.language_id%type,
                              fp_uniqueresidentialitemid out nocopy uniqueresidentialitem.uniqueresidentialitem_id%type,
                              fp_plantid_parameter       out nocopy plant.plant_id%type,
                              fp_plantid_garment         out nocopy plant.plant_id%type,
                              fp_unitcode                out nocopy businessunit.code%type,
                              fp_businessunitid          out nocopy businessunit.businessunit_id%type,
                              fp_status                  out nocopy number,
                              fp_message                 out nocopy abslog.message%type,
                              fp_customernumber          out nocopy customer.customernumber%type,
                              fp_customerid              out nocopy customer.customer_id%type,
                              fp_customername            out nocopy customer.name%type,
                              fp_serviceteamid           out nocopy customer.serviceteam_id%type,
                              fp_clientnumber            out nocopy client.clientnumber%type,
                              fp_clientid                out nocopy client.client_id%type,
                              fp_clientsearchname        out nocopy client.searchname%type,
                              fp_roomnumber              out nocopy departmentroom.roomnumber%type,
                              fp_departmentroomid        out nocopy departmentroom.departmentroom_id%type,
                              fp_departmentroomseq       out nocopy departmentroom.sequencenumber%type,
                              fp_departmentnumber        out nocopy department.departmentnumber%type,
                              fp_clientadminnumber       out nocopy client.adminnumber%type,
                              fp_gender                  out nocopy client.gender%type,
                              fp_deliverypointcode       out nocopy deliverypoint.code%type,
                              fp_deliverypointid         out nocopy deliverypoint.deliverypoint_id%type,
                              fp_productcode             out nocopy product.code%type,
                              fp_productid               out nocopy product.product_id%type,
                              fp_productgroupid          out nocopy product.productgroup_id%type,
                              fp_productdescription      out nocopy product_desc.description%type,
                              fp_productcolorid          out nocopy product.color_id%type,
                              fp_sizecode                out nocopy sizedefinition.code%type,
                              fp_productsortgroup        out nocopy productsortgroup.code%type,
                              fp_productsortgroupid      out nocopy product.productsortgroup_id%type,
                              fp_sizeid                  out nocopy sizedefinition.sizedefinition_id%type,
                              fp_finishingmethodid       out nocopy finishingmethod.finishingmethod_id%type,
                              fp_infotext                out nocopy client.remark%type,
                              fp_timezonehrsdiff         out nocopy plant.timezonehrsdiff%type,
                              fp_statusid                out nocopy status.status_id%type,
                              fp_lastinscandate          out nocopy uniqueresidentialitem.lastinscandate%type,
                              fp_lastoutscandate         out nocopy uniqueresidentialitem.lastoutscandate%type,
                              fp_lastrewashdate          out nocopy uniqueresidentialitem.lastrewashdate%type,
                              fp_lastrepairdate          out nocopy uniqueresidentialitem.lastrepairdate%type,
                              fp_loglevel                out nocopy number,
                              fp_departmentid            out nocopy department.department_id%type,
                              fp_department_desc         out nocopy department.description%type,
                              fp_clientfirstlastname     out nocopy varchar2,
                              fp_productvolume           out nocopy product.volumeunits%type,
                              fp_databasecode            out nocopy databasesettings.code%type) is
    lv_overalluniqueresidentialid databasesettings.overalluniquegarmentid%type;

    procedure get_uniqueresiteminfo is
    begin
      --get_uniqueresiteminfo
      select ur.businessunit_id, bu.code, bu.plant_id, p.product_id, p.code,
             (select pd.description
               from   product_desc pd
               where  pd.product_id = p.product_id
               and    pd.language_id = c.language_id), p.color_id, s.sizedefinition_id, s.code,
             f.finishingmethod_id, cl.client_id, cl.clientnumber, cl.searchname, cl.gender,
             cl.adminnumber, dpr.roomnumber, t.departmentnumber, dt.code, dt.deliverypoint_id,
             c.customernumber, c.customer_id, c.name, c.serviceteam_id,
             (select pt.language_id from plant pt where pt.plant_id = bu.plant_id),
             (select psg.code
               from   productsortgroup psg
               where  psg.productsortgroup_id = p.productsortgroup_id), cl.remark, p.productgroup_id,
             p.productsortgroup_id, dpr.departmentroom_id, dpr.sequencenumber, ur.status_id,
             ur.lastinscandate, ur.lastoutscandate, ur.lastrewashdate, ur.lastrepairdate,
             t.department_id, t.description, cl.name || ', ' || cl.firstname, p.volumeunits
      into   fp_businessunitid, fp_unitcode, fp_plantid_garment, fp_productid, fp_productcode,
             fp_productdescription, fp_productcolorid, fp_sizeid, fp_sizecode, fp_finishingmethodid,
             fp_clientid, fp_clientnumber, fp_clientsearchname, fp_gender, fp_clientadminnumber,
             fp_roomnumber, fp_departmentnumber, fp_deliverypointcode, fp_deliverypointid,
             fp_customernumber, fp_customerid, fp_customername, fp_serviceteamid, fp_plantlanguageid,
             fp_productsortgroup, fp_infotext, fp_productgroupid, fp_productsortgroupid,
             fp_departmentroomid, fp_departmentroomseq, fp_statusid, fp_lastinscandate,
             fp_lastoutscandate, fp_lastrewashdate, fp_lastrepairdate, fp_departmentid,
             fp_department_desc, fp_clientfirstlastname, fp_productvolume
      from   uniqueresidentialitem ur
      join   businessunit bu
      on     bu.businessunit_id = ur.businessunit_id
      join  (client cl
      join   customer c
      on     c.customer_id = cl.customer_id
      join  (clientresident clr
      join   departmentroom dpr
      on     dpr.departmentroom_id = clr.departmentroom_id
      join   department t
      on     t.department_id = dpr.department_id
      join   distributionpoint dp
      on     dp.distributionpoint_id = dpr.distributionpoint_id
      join   deliverypoint dt
      on     dt.deliverypoint_id = dp.deliverypoint_id) on clr.client_id = cl.client_id) on cl.client_id = ur.client_id
      left   outer join(uniqueresidentialitemproduct urp
      join   product p
      on     p.product_id = urp.product_id
      join   sizedefinition s
      on     s.sizedefinition_id = urp.sizedefinition_id
      join   finishingmethod f
      on     f.finishingmethod_id = urp.finishingmethod_id) on urp.uniqueresidentialitem_id = ur.uniqueresidentialitem_id
      where  ur.uniqueresidentialitem_id = fp_uniqueresidentialitemid;
    end get_uniqueresiteminfo;
  begin
    --get_uniqueitem_rs
    fp_status := 0;
    --get info for fp_plantcode
    if fp_plantcode is null then
      begin
        fp_message := 'parameter fp_plantcode cannot be left empty!';
        raise no_data_found;
      end;
    else
      begin
        fp_message := 'Retrieve plant code ';
        select p.plant_id, p.timezonehrsdiff
        into   fp_plantid_parameter, fp_timezonehrsdiff
        from   plant p
        where  p.code = fp_plantcode;
      end;
    end if;
    --get info overalluniquegarmentid
    select nvl(max(d.code), 'NULL') databasecode, nvl(max(d.overalluniqueresidentialid), 'N')
    into   fp_databasecode, lv_overalluniqueresidentialid
    from   databasesettings d;
    --get ID code
    fp_message := null;
    if lv_overalluniqueresidentialid = 'Y' then
      begin
        --we only get clientresident barcodes!
        --fp_plantid_parameter is null
        select ur.businessunit_id, bu.code, bu.plant_id, ur.uniqueresidentialitem_id, p.product_id,
               p.code,
               (select pd.description
                 from   product_desc pd
                 where  pd.product_id = p.product_id
                 and    pd.language_id = c.language_id), p.color_id, s.sizedefinition_id, s.code,
               f.finishingmethod_id, cl.client_id, cl.clientnumber, cl.searchname, cl.gender,
               cl.adminnumber, dpr.roomnumber, t.departmentnumber, dt.code, dt.deliverypoint_id,
               c.customernumber, c.customer_id, c.name, c.serviceteam_id,
               (select pt.language_id from plant pt where pt.plant_id = bu.plant_id),
               (select psg.code
                 from   productsortgroup psg
                 where  psg.productsortgroup_id = p.productsortgroup_id), cl.remark,
               p.productgroup_id, p.productsortgroup_id, dpr.departmentroom_id, dpr.sequencenumber,
               ur.status_id, ur.lastinscandate, ur.lastoutscandate, ur.lastrewashdate,
               ur.lastrepairdate, t.department_id, t.description, cl.name || ', ' || cl.firstname,
               p.volumeunits
        into   fp_businessunitid, fp_unitcode, fp_plantid_garment, fp_uniqueresidentialitemid,
               fp_productid, fp_productcode, fp_productdescription, fp_productcolorid, fp_sizeid,
               fp_sizecode, fp_finishingmethodid, fp_clientid, fp_clientnumber, fp_clientsearchname,
               fp_gender, fp_clientadminnumber, fp_roomnumber, fp_departmentnumber,
               fp_deliverypointcode, fp_deliverypointid, fp_customernumber, fp_customerid,
               fp_customername, fp_serviceteamid, fp_plantlanguageid, fp_productsortgroup,
               fp_infotext, fp_productgroupid, fp_productsortgroupid, fp_departmentroomid,
               fp_departmentroomseq, fp_statusid, fp_lastinscandate, fp_lastoutscandate,
               fp_lastrewashdate, fp_lastrepairdate, fp_departmentid, fp_department_desc,
               fp_clientfirstlastname, fp_productvolume
        from   uniqueresidentialitem ur
        join   businessunit bu
        on     bu.businessunit_id = ur.businessunit_id
        join  (client cl
        join   customer c
        on     c.customer_id = cl.customer_id
        join  (clientresident clr
        join   departmentroom dpr
        on     dpr.departmentroom_id = clr.departmentroom_id
        join   department t
        on     t.department_id = dpr.department_id
        join   distributionpoint dp
        on     dp.distributionpoint_id = dpr.distributionpoint_id
        join   deliverypoint dt
        on     dt.deliverypoint_id = dp.deliverypoint_id) on clr.client_id = cl.client_id) on cl.client_id = ur.client_id
        left   outer join(uniqueresidentialitemproduct urp
        join   product p
        on     p.product_id = urp.product_id
        join   sizedefinition s
        on     s.sizedefinition_id = urp.sizedefinition_id
        join   finishingmethod f
        on     f.finishingmethod_id = urp.finishingmethod_id) on urp.uniqueresidentialitem_id = ur.uniqueresidentialitem_id
        where  ur.primaryid = fp_idcode
        and    ur.sequencenumber = 1;
      exception
        when no_data_found then
          begin
            select sur.uniqueresidentialitem_id
            into   fp_uniqueresidentialitemid
            from   secondaryidresidentialitem sur
            where  sur.secondaryid = fp_idcode;
            --get_uniqueresiteminfo
            get_uniqueresiteminfo;
          end;
      end;
    else
      begin
        --we only get clientresident barcodes!
        --plant id filled
        select ur.businessunit_id, bu.code, bu.plant_id, ur.uniqueresidentialitem_id, p.product_id,
               p.code,
               (select pd.description
                 from   product_desc pd
                 where  pd.product_id = p.product_id
                 and    pd.language_id = c.language_id), p.color_id, s.sizedefinition_id, s.code,
               f.finishingmethod_id, cl.client_id, cl.clientnumber, cl.searchname, cl.gender,
               cl.adminnumber, dpr.roomnumber, t.departmentnumber, dt.code, dt.deliverypoint_id,
               c.customernumber, c.customer_id, c.name, c.serviceteam_id,
               (select pt.language_id from plant pt where pt.plant_id = bu.plant_id),
               (select psg.code
                 from   productsortgroup psg
                 where  psg.productsortgroup_id = p.productsortgroup_id), cl.remark,
               p.productgroup_id, p.productsortgroup_id, dpr.departmentroom_id, dpr.sequencenumber,
               ur.status_id, ur.lastinscandate, ur.lastoutscandate, ur.lastrewashdate,
               ur.lastrepairdate, t.department_id, t.description, cl.name || ', ' || cl.firstname,
               p.volumeunits
        into   fp_businessunitid, fp_unitcode, fp_plantid_garment, fp_uniqueresidentialitemid,
               fp_productid, fp_productcode, fp_productdescription, fp_productcolorid, fp_sizeid,
               fp_sizecode, fp_finishingmethodid, fp_clientid, fp_clientnumber, fp_clientsearchname,
               fp_gender, fp_clientadminnumber, fp_roomnumber, fp_departmentnumber,
               fp_deliverypointcode, fp_deliverypointid, fp_customernumber, fp_customerid,
               fp_customername, fp_serviceteamid, fp_plantlanguageid, fp_productsortgroup,
               fp_infotext, fp_productgroupid, fp_productsortgroupid, fp_departmentroomid,
               fp_departmentroomseq, fp_statusid, fp_lastinscandate, fp_lastoutscandate,
               fp_lastrewashdate, fp_lastrepairdate, fp_departmentid, fp_department_desc,
               fp_clientfirstlastname, fp_productvolume
        from   uniqueresidentialitem ur
        join   businessunit bu
        on     bu.businessunit_id = ur.businessunit_id
        join  (client cl
        join   customer c
        on     c.customer_id = cl.customer_id
        join  (clientresident clr
        join   departmentroom dpr
        on     dpr.departmentroom_id = clr.departmentroom_id
        join   department t
        on     t.department_id = dpr.department_id
        join   distributionpoint dp
        on     dp.distributionpoint_id = dpr.distributionpoint_id
        join   deliverypoint dt
        on     dt.deliverypoint_id = dp.deliverypoint_id) on clr.client_id = cl.client_id) on cl.client_id = ur.client_id
        left   outer join(uniqueresidentialitemproduct urp
        join   product p
        on     p.product_id = urp.product_id
        join   sizedefinition s
        on     s.sizedefinition_id = urp.sizedefinition_id
        join   finishingmethod f
        on     f.finishingmethod_id = urp.finishingmethod_id) on urp.uniqueresidentialitem_id = ur.uniqueresidentialitem_id
        where  ur.primaryid = fp_idcode
        and    bu.plant_id = fp_plantid_parameter
        and    ur.sequencenumber = 1;
      exception
        when no_data_found then
          begin
            select sur.uniqueresidentialitem_id
            into   fp_uniqueresidentialitemid
            from   secondaryidresidentialitem sur
            join   businessunit bu
            on     bu.businessunit_id = sur.businessunit_id
            where  sur.secondaryid = fp_idcode
            and    bu.plant_id = fp_plantid_parameter;
            --get_uniqueresiteminfo
            get_uniqueresiteminfo;
          end;
      end;
    end if;
    fp_message := null;
    fp_status  := 0;
    --determine log level
    if fp_typecall = 0 then
      fp_loglevel := nvl(to_number(pack_sort_rs.get_systemsettting(fp_plantid_parameter,
                                                                   'SORTLOGGETGARMENTDATAPWB')), 0);
    else
      fp_loglevel := nvl(to_number(pack_sort_rs.get_systemsettting(fp_plantid_parameter,
                                                                   'SORTLOGSENDTRACKINFOPWB')), 0);
    end if;
  exception
    --error handling
    when no_data_found then
      begin
        fp_status := 1; --no_data_found
        raise;
      end;
    when too_many_rows then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 2; --too many rows
        raise;
      end;
    when dup_val_on_index then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 3; --dup_val_on_index
        raise;
      end;
    when others then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 4; --others
        raise;
      end;
  end get_uniqueitem_rs;

  procedure get_plpc_info(fp_plantid                     in plant.plant_id%type,
                          fp_customerid                  in customer.customer_id%type,
                          fp_productid                   in product.product_id%type,
                          fp_sizeid                      in sizedefinition.sizedefinition_id%type,
                          fp_finishingmethodid           in finishingmethod.finishingmethod_id%type,
                          fp_status                      out nocopy number,
                          fp_message                     out nocopy abslog.message%type,
                          fp_sortaddressperfinishingcode out nocopy sortaddressperfinishingcode.sortaddress%type) is
    lv_finishingcodeid finishingcode.finishingcode_id%type;
  begin
    --get_plpc_info
    fp_status  := 0;
    fp_message := 'Get ProductListPerCustomer ';
    select max(l.finishingcode_id)
    into   lv_finishingcodeid
    from   productlistpercustomer l
    where  l.customer_id = fp_customerid
    and    l.product_id = fp_productid
    and    l.sizedefinition_id = fp_sizeid
    and    l.finishingmethod_id = fp_finishingmethodid
    and    sysdate between l.dateactive and l.dateinactive;
    fp_message := 'Get SortaddressPerFinishingcode ';
    select max(saf.sortaddress)
    into   fp_sortaddressperfinishingcode
    from   sortaddressperfinishingcode saf
    where  saf.finishingcode_id =
           nvl(lv_finishingcodeid,
               (select p.finishingcode_id from product p where p.product_id = fp_productid))
    and    saf.plant_id = fp_plantid;
    fp_message := null;
    fp_status  := 0;
  exception
    --error handling
    when no_data_found then
      begin
        fp_status := 1; --no_data_found
        raise;
      end;
    when too_many_rows then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 2; --too many rows
        raise;
      end;
    when dup_val_on_index then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 3; --dup_val_on_index
        raise;
      end;
    when others then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 4; --others
        raise;
      end;
  end get_plpc_info;

  function get_next_deldate_tom5(fp_date_param   in date,
                                 fp_customerid   in customer.customer_id%type,
                                 fp_departmentid in department.department_id%type,
                                 fp_databasecode in varchar2) return date is
    type visitdates is table of number index by varchar2(8);
    lv_dates            visitdates;
    i                   integer := 1;
    lv_param_data_daynr day.day_id%type;
    lv_dayparam         number;
    lv_returnitems      customerresidentialsettings.returnitems%type;
    lv_weeknr           number;
    lv_yearnr           number;
    lv_date             date;
    lv_daynumber        number;
  begin
    lv_param_data_daynr := getabsdaynumber(fp_date_param);
    ---1 = Next visit,2 = Same route next week,3 = Return route
    select nvl(max(x.returnitems), 1)
    into   lv_returnitems
    from   customerresidentialsettings x
    where  x.customer_id = fp_customerid;
    --determine next visit day
    case lv_returnitems
      when 1 then
        begin
          --1 = Next visit
          for xcd in (select cd.day_id
                      from   customerdeliveryday cd
                      where  cd.customer_id = fp_customerid
                      and    cd.typeofmerchadise = 5
                      and    not exists (select 1
                              from   deliveryday dd
                              where  dd.department_id = fp_departmentid
                              and    dd.day_id = cd.day_id)) loop
            begin
              if (xcd.day_id > lv_param_data_daynr) or
                 (fp_databasecode = 'CLO' and xcd.day_id >= lv_param_data_daynr) then
                lv_dates(to_char(fp_date_param + xcd.day_id - lv_param_data_daynr, 'YYYYMMDD')) := i;
              else
                lv_dates(to_char(fp_date_param + xcd.day_id - lv_param_data_daynr + 7, 'YYYYMMDD')) := i;
              end if;
              i := i + 1;
            end;
          end loop; --xcd
          return(to_date(lv_dates.first, 'YYYYMMDD'));
        end;
      when 2 then
        begin
          --2 = Same route next week
          lv_weeknr   := getisoweek(fp_date_param);
          lv_yearnr   := getyearofweek(fp_date_param);
          lv_dayparam := getabsdaynumber(fp_date_param);
          --Find incoming route
          select max((case
                       when (cd.day_id >= lv_dayparam) then
                        cd.day_id - 7
                       else
                        cd.day_id
                     end)) daynr
          into   lv_daynumber
          from   customerdeliveryday cd
          where  cd.customer_id = fp_customerid
          and    cd.typeofmerchadise = 5
          and    not exists (select 1
                  from   deliveryday dd
                  where  dd.department_id = fp_departmentid
                  and    dd.day_id = cd.day_id)
          and    exists (select 1
                  from   routestop rs
                  join   route r
                  on     r.route_id = rs.route_id
                  where  rs.customer_id = fp_customerid
                  and    r.drivingday_id = cd.day_id
                  and    fp_date_param between rs.dateactive and rs.dateinactive
                  and    rs.stoptype in (2, 3, 4));
          if lv_daynumber < 1 then
            lv_daynumber := lv_daynumber + 7;
          end if;
          lv_date := getdateforweekyear(lv_daynumber, lv_weeknr, lv_yearnr);
          if lv_date >= fp_date_param then
            return lv_date;
          else
            return lv_date + 7;
          end if;
        end;
      else
        begin
          --3 = Return route
          lv_weeknr   := getisoweek(fp_date_param);
          lv_yearnr   := getyearofweek(fp_date_param);
          lv_dayparam := getabsdaynumber(fp_date_param);
          --Find incoming route
          select max((case
                       when (cd.day_id >= lv_dayparam) then
                        cd.day_id - 7
                       else
                        cd.day_id
                     end)) daynr
          into   lv_daynumber
          from   customerdeliveryday cd
          where  cd.customer_id = fp_customerid
          and    cd.typeofmerchadise = 5
          and    not exists (select 1
                  from   deliveryday dd
                  where  dd.department_id = fp_departmentid
                  and    dd.day_id = cd.day_id)
          and    exists (select 1
                  from   routestop rs
                  join   route r
                  on     r.route_id = rs.route_id
                  where  rs.customer_id = fp_customerid
                  and    r.drivingday_id = cd.day_id
                  and    fp_date_param between rs.dateactive and rs.dateinactive
                  and    rs.stoptype in (2, 3, 4));
          if lv_daynumber < 1 then
            lv_daynumber := lv_daynumber + 7;
          end if;
          --  get return day
          select max(rr.drivingday_id)
          into   lv_daynumber
          from   routestop rs
          join   route r
          on     r.route_id = rs.route_id
          join   route rr
          on     rr.route_id = rs.returnroute_id
          where  rs.customer_id = fp_customerid
          and    r.drivingday_id = lv_daynumber
          and    fp_date_param between rs.dateactive and rs.dateinactive
          and    rs.stoptype in (2, 3, 4);
          lv_date := getdateforweekyear(lv_daynumber, lv_weeknr, lv_yearnr);
          if lv_date >= fp_date_param then
            return lv_date;
          else
            return lv_date + 7;
          end if;
        end;
    end case;
  end get_next_deldate_tom5;

  function create_cliendelnoteline(fp_idcode               in uniqueresidentialitem.primaryid%type,
                                   fp_clientdeliverynote   in clientdeliverynote.clientdeliverynotenumber%type,
                                   fp_clientdeliverynoteid in clientdeliverynote.clientdeliverynote_id%type,
                                   fp_plantid              in plant.plant_id%type,
                                   fp_unitcode             in businessunit.code%type,
                                   fp_businessunitid       in businessunit.businessunit_id%type,
                                   fp_customerid           in customer.customer_id%type,
                                   fp_productgroupid       in productgroup.productgroup_id%type,
                                   fp_productid            in product.product_id%type,
                                   fp_sizeid               in sizedefinition.sizedefinition_id%type,
                                   fp_finishingmethodid    in finishingmethod.finishingmethod_id%type,
                                   fp_systemuserid         in systemuser.systemuser_id%type,
                                   fp_loglevel             in number,
                                   fp_logname              in varchar2,
                                   fp_origin               in clientdeliverynoteline.origin%type,
                                   fp_quantitycounted      in number default 0) --for counting not scanning when fp_origin = 5 only!
   return clientdeliverynoteline.clientdeliverynoteline_id%type is
    lv_clientdeliverynotelineid clientdeliverynoteline.clientdeliverynoteline_id%type;
    lv_invoicebusinessunitid    businessunit.businessunit_id%type;
  begin
    --create clientdeliverynoteline
    --check if client del not is there CLIENTDELIVERINOTE_ID, PRODUCT_LINK_ID, SIZEDEFINITION_LINK_ID, FINISHINGMETHOD_ID
    select cdl.clientdeliverynoteline_id
    into   lv_clientdeliverynotelineid
    from   clientdeliverynoteline cdl
    where  cdl.clientdeliverinote_id = fp_clientdeliverynoteid
    and    cdl.product_link_id = fp_productid
    and    cdl.sizedefinition_link_id = fp_sizeid
    and    cdl.finishingmethod_id = fp_finishingmethodid;
    --update clientdeliverynoteline cdl
    update clientdeliverynoteline cdl
    set    cdl.qtyscannedout = case fp_origin
                                  when 4 then
                                   cdl.qtyscannedout + 1
                                  else
                                   cdl.qtyscannedout
                                end,
           cdl.qtyscannedin = case fp_origin
                                 when 2 then
                                  cdl.qtyscannedin + 1
                                 else
                                  cdl.qtyscannedin
                               end,
           cdl.qtycountedin = case fp_origin
                                 when 5 then
                                  cdl.qtycountedin + fp_quantitycounted
                                 else
                                  cdl.qtycountedin
                               end,
           cdl.qtycountedout = case fp_origin
                                  when 5 then
                                   cdl.qtycountedout + fp_quantitycounted
                                  else
                                   cdl.qtycountedout
                                end, cdl.timestamp = sysdate, cdl.systemuser_id = fp_systemuserid
    where  cdl.clientdeliverynoteline_id = lv_clientdeliverynotelineid;
    pack_sort_rs.write_logging('For ID code ' || nvl(fp_idcode, 'NULL') ||
                               ' updated clientdeliverynoteline with ID ' ||
                               to_char(lv_clientdeliverynotelineid) || ' for client note ' ||
                               to_char(fp_clientdeliverynote) || ' for businessunit ' ||
                               fp_unitcode, fp_loglevel, fp_logname, fp_plantid, 1, 1);
    return lv_clientdeliverynotelineid;
  exception
    when no_data_found then
      begin
        --get gv_invoicebusinessunitid
        select nvl(max(ca.invoicebusinessunit_id), fp_businessunitid)
        into   lv_invoicebusinessunitid
        from   customeractivities ca
        where  ca.customer_id = fp_customerid
        and    ca.activity_id = (select g.activity_id
                                 from   productgroup g
                                 where  g.productgroup_id = fp_productgroupid);
        --insert into clientdeliverynoteline
        insert into clientdeliverynoteline
          (clientdeliverynoteline_id, clientdeliverinote_id, product_link_id,
           sizedefinition_link_id, finishingmethod_id, qtyscannedin, qtycountedin, qtyscannedout,
           origin, invoicebusinessunit_id, systemuser_id, timestamp, invoiceline_id, price,
           priceondelnote, qtycountedout)
        values
          (seq_clientdeliverynoteline.nextval, fp_clientdeliverynoteid, fp_productid, fp_sizeid,
           fp_finishingmethodid, case fp_origin when 2 then 1 else 0 end,
           case fp_origin when 5 then fp_quantitycounted else 0 end,
           case fp_origin when 4 then 1 else 0 end, fp_origin, lv_invoicebusinessunitid,
           fp_systemuserid, sysdate, null, null, null,
           case fp_origin when 5 then fp_quantitycounted else 0 end)
        returning clientdeliverynoteline_id into lv_clientdeliverynotelineid;
        pack_sort_rs.write_logging('For ID code ' || nvl(fp_idcode, 'NULL') ||
                                   ' created clientdeliverynoteline with ID ' ||
                                   to_char(lv_clientdeliverynotelineid) || ' for client note ' ||
                                   to_char(fp_clientdeliverynote) || ' for businessunit ' ||
                                   fp_unitcode, fp_loglevel, fp_logname, fp_plantid, 1, 1);
        return lv_clientdeliverynotelineid;
      end;
  end create_cliendelnoteline;

  procedure create_clientdelnotescan(fp_clientdelnotelinescanid  in out clientdelnotelinescan.clientdelnotelinescan_id%type,
                                     fp_idcode                   in uniqueresidentialitem.primaryid%type,
                                     fp_clientdeliverynote       in clientdeliverynote.clientdeliverynotenumber%type,
                                     fp_clientdeliverynotelineid in clientdeliverynoteline.clientdeliverynoteline_id%type,
                                     fp_plantid                  in plant.plant_id%type,
                                     fp_unitcode                 in businessunit.code%type,
                                     fp_loglevel                 in number,
                                     fp_logname                  in varchar2,
                                     fp_systemuserid             in systemuser.systemuser_id%type,
                                     fp_uniqueresidentialitemid  in uniqueresidentialitem.uniqueresidentialitem_id%type,
                                     fp_scantype_in_out          in varchar2 default 'OUT',
                                     fp_scandate                 in date) is
  begin
    --create_clientdelnotescan
    if fp_clientdelnotelinescanid is not null then
      update clientdelnotelinescan cds
      set    cds.outscanclientdelnoteline_id = case fp_scantype_in_out
                                                  when 'OUT' then
                                                   fp_clientdeliverynotelineid
                                                  else
                                                   cds.outscanclientdelnoteline_id
                                                end,
             cds.inscanclientdelnoteline_id = case fp_scantype_in_out
                                                 when 'IN' then
                                                  fp_clientdeliverynotelineid
                                                 else
                                                  cds.inscanclientdelnoteline_id
                                               end,
             cds.outscantimestamp = case fp_scantype_in_out
                                       when 'OUT' then
                                        fp_scandate
                                       else
                                        cds.outscantimestamp
                                     end,
             cds.inscantimestamp = case fp_scantype_in_out
                                      when 'IN' then
                                       fp_scandate
                                      else
                                       cds.inscantimestamp
                                    end,
             cds.delayed = case
                             when (case fp_scantype_in_out
                                    when 'OUT' then
                                     fp_clientdeliverynotelineid
                                    else
                                     cds.outscanclientdelnoteline_id
                                  end) <> (case fp_scantype_in_out
                                    when 'IN' then
                                     fp_clientdeliverynotelineid
                                    else
                                     cds.inscanclientdelnoteline_id
                                  end) then
                              'Y'
                             else
                              'N'
                           end, cds.systemuser_id = fp_systemuserid
      where  cds.clientdelnotelinescan_id = fp_clientdelnotelinescanid;
      pack_sort_rs.write_logging('ID code ' || nvl(fp_idcode, 'NULL') ||
                                 ' scanned out on client delivery note ' ||
                                 to_char(fp_clientdeliverynote) || ' for businessunit ' ||
                                 fp_unitcode || ' and updated clientdelnotelinescan with ID ' ||
                                 to_char(fp_clientdelnotelinescanid), fp_loglevel, fp_logname,
                                 fp_plantid, 1, 1);
    else
      insert into clientdelnotelinescan
        (clientdelnotelinescan_id, uniqueresidentialitem_link_id, inscanclientdelnoteline_id,
         outscanclientdelnoteline_id, inscantimestamp, outscantimestamp, delayed, systemuser_id,
         timestamp)
      values
        (seq_clientdelnotelinescan.nextval, fp_uniqueresidentialitemid,
         case fp_scantype_in_out when 'IN' then fp_clientdeliverynotelineid else null end,
         case fp_scantype_in_out when 'OUT' then fp_clientdeliverynotelineid else null end,
         case fp_scantype_in_out when 'IN' then fp_scandate else null end,
         case fp_scantype_in_out when 'OUT' then fp_scandate else null end, 'N', fp_systemuserid,
         sysdate)
      returning clientdelnotelinescan_id into fp_clientdelnotelinescanid;
      pack_sort_rs.write_logging('ID code ' || nvl(fp_idcode, 'NULL') || ' scanned ' ||
                                 fp_scantype_in_out || ' on client delivery note ' ||
                                 to_char(fp_clientdeliverynote) || ' for businessunit ' ||
                                 fp_unitcode || ' and inserted clientdelnotelinescan with ID ' ||
                                 to_char(fp_clientdelnotelinescanid), fp_loglevel, fp_logname,
                                 fp_plantid, 1, 1);
    end if; --gv_clientdelnotlinescanid is null
  end create_clientdelnotescan;

  procedure get_clientdelnotescan(fp_uniqueresidentialitemid  in uniqueresidentialitem.uniqueresidentialitem_id%type,
                                  fp_businessunitid           in businessunit.businessunit_id%type,
                                  fp_update_startoutscan      in number,
                                  fp_batchid                  out nocopy batch.batch_id%type,
                                  fp_clientdelnotlinescanid   out nocopy clientdelnotelinescan.clientdelnotelinescan_id%type,
                                  fp_clientdeliverynote       out nocopy clientdeliverynote.clientdeliverynotenumber%type,
                                  fp_routid                   out nocopy route.route_id%type,
                                  fp_stopnumber               out nocopy clientdeliverynote.stopnumber%type,
                                  fp_clientdeliverynoteid     out nocopy clientdeliverynote.clientdeliverynote_id%type,
                                  fp_deliverydate             out nocopy clientdeliverynote.deliverydate%type,
                                  fp_clientdeliverynotelineid out nocopy clientdeliverynoteline.clientdeliverynoteline_id%type,
                                  fp_logname                  in varchar2 default null,
                                  fp_batchcode                in batch.batchcode%type default null) is
  begin
    --step 2 we take the latest clientdelnotlinescan, highest ID
    select cdn.batch_id, cds.clientdelnotelinescan_id, cdn.clientdeliverynotenumber, cdn.route_id,
           cdn.stopnumber, cdn.clientdeliverynote_id, cdn.deliverydate,
           cdnl.clientdeliverynoteline_id
    into   fp_batchid, fp_clientdelnotlinescanid, fp_clientdeliverynote, fp_routid, fp_stopnumber,
           fp_clientdeliverynoteid, fp_deliverydate, fp_clientdeliverynotelineid
    from   clientdelnotelinescan cds
    left   outer join(clientdeliverynoteline cdnl
    join   clientdeliverynote cdn
    on     cdn.clientdeliverynote_id = cdnl.clientdeliverinote_id
    and    cdn.processbusinessunit_id = fp_businessunitid) on cdnl.clientdeliverynoteline_id = cds.inscanclientdelnoteline_id
    left   outer join batch b
    on     b.batch_id = cdn.batch_id
    where  nvl(cdn.closingdate, to_date('31-12-2099', 'dd-mm-yyyy')) =
           to_date('31-12-2099', 'dd-mm-yyyy')
    and    (nvl(cdn.startoutscan, to_date('31-12-2099', 'dd-mm-yyyy')) =
            to_date('31-12-2099', 'dd-mm-yyyy') or fp_update_startoutscan = 1)
    and    cds.clientdelnotelinescan_id =
           (select max(cdsx.clientdelnotelinescan_id)
             from   clientdelnotelinescan cdsx
             where  cdsx.uniqueresidentialitem_link_id = fp_uniqueresidentialitemid)
    and    (fp_logname is null -- not RFL
            or (fp_logname <> 'SENDTRACKINFORS' and b.origin = 11) -- GETGARMENTDATA/SENDTRACKINFORSX = Jensen
            or (fp_logname = 'SENDTRACKINFORS' and b.origin <> 11) -- SENDTRACKINFORS = Technico
            )
    and    (b.batchcode = fp_batchcode or fp_batchcode is null);
  exception
    when no_data_found then
      begin
        fp_clientdelnotlinescanid   := null;
        fp_clientdeliverynote       := null;
        fp_routid                   := null;
        fp_stopnumber               := null;
        fp_clientdeliverynoteid     := null;
        fp_deliverydate             := null;
        fp_clientdeliverynotelineid := null;
      end;
  end get_clientdelnotescan;

  procedure get_create_clientdelnote(fp_uniqueresidentialitemid in uniqueresidentialitem.uniqueresidentialitem_id%type,
                                     fp_businessunitid          in businessunit.businessunit_id%type,
                                     fp_unitcode                in businessunit.code%type,
                                     fp_plantid                 in plant.plant_id%type,
                                     fp_customerid              in customer.customer_id%type,
                                     fp_clientid                in client.client_id%type,
                                     fp_productgroupid          in product.productgroup_id%type,
                                     fp_deliverypointid         in deliverypoint.deliverypoint_id%type,
                                     fp_routenumber             out nocopy route.routenumber%type,
                                     fp_routid                  out nocopy route.route_id%type,
                                     fp_routeday                out nocopy route.drivingday_id%type,
                                     fp_depot                   out nocopy depot.code%type,
                                     fp_stopnumber              out nocopy clientdeliverynote.stopnumber%type,
                                     fp_clientdeliverynote      out nocopy clientdeliverynote.clientdeliverynotenumber%type,
                                     fp_clientdeliverynoteid    out nocopy clientdeliverynote.clientdeliverynote_id%type,
                                     fp_clientdelnotlinescanid  out nocopy clientdelnotelinescan.clientdelnotelinescan_id%type,
                                     fp_out_batchid             out nocopy batch.batch_id%type,
                                     fp_status                  out nocopy number,
                                     fp_message                 out nocopy abslog.message%type,
                                     fp_update_startoutscan     in number,
                                     fp_loglevel                in number,
                                     fp_logname                 in varchar2,
                                     fp_systemuserid            in systemuser.systemuser_id%type,
                                     fp_departmentid            in department.department_id%type,
                                     fp_idcode                  in uniqueresidentialitem.primaryid%type,
                                     fp_productid               in product.product_id%type,
                                     fp_sizeid                  in sizedefinition.sizedefinition_id%type,
                                     fp_finishingmethodid       in finishingmethod.finishingmethod_id%type,
                                     fp_date_param              in date,
                                     fp_databasecode            in databasesettings.code%type,
                                     fp_in_batchid              in batch.batch_id%type default null,
                                     fp_batchcode               in batch.batchcode%type default null) is
    lv_deliverydate            clientdeliverynote.deliverydate%type;
    lv_origin                  clientdeliverynote.origin%type;
    lv_batchnrforlabels        batch.batchnumber%type;
    lv_clientdeliverynotlineid clientdeliverynoteline.clientdeliverynoteline_id%type;
    lv_userexception           exception;
    procedure get_routeinfo is
    begin
      fp_message := 'get_create_clientdelnote.get_routeinfo';
      if fp_routid is not null then
        --get_routeinfo
        select r.routenumber, r.drivingday_id, dpt.code
        into   fp_routenumber, fp_routeday, fp_depot
        from   route r
        left   outer join depot dpt
        on     dpt.depot_id = r.depot_id
        where  r.route_id = fp_routid;
      else
        fp_routenumber := null;
        fp_routeday    := null;
        fp_depot       := null;
      end if;
    end get_routeinfo;

    procedure get_batch is
      lv_batchcolor_id  batchcolor.batchcolor_id%type;
      lv_year           number;
      lv_week           number;
      lv_addvalue       number := 0;
      lv_range          number := 50;
      lv_batchnumber    batch.batchnumber%type;
      lv_batchnumber_ss batch.batchnumber%type;
    begin
      fp_message := 'get_create_clientdelnote.get_batch';
      lv_year    := getyearofweek(fp_date_param);
      lv_week    := getisoweek(fp_date_param);
      --get default batch number
      lv_batchnumber_ss := nvl(to_number(get_systemsettting(fp_plantid, 'BATCHFORSORTINGSYSTEM')), 1);
      lv_batchnumber    := lv_batchnumber_ss;
      if fp_logname = 'SENDTRACKINFORS' then
        begin
          lv_addvalue    := 50; --added value for sendtrackinfo HVL/PVD 24-9-2013
          lv_batchnumber := lv_batchnumber + lv_addvalue; --HVL 25-09-2012
        end;
      end if;
      --get_batch
      fp_message := 'get batch';
      select min(bt.batch_id)
      into   fp_out_batchid
      from   batch bt
      where  bt.businessunit_id = fp_businessunitid
      and    bt.year = lv_year
      and    bt.week = lv_week
      and    bt.origin = 9
      and    bt.batchnumber >= lv_batchnumber_ss + lv_addvalue
      and    bt.batchnumber < lv_batchnumber_ss + lv_addvalue + lv_range
      and    bt.status <> 4;
      if fp_out_batchid is null then
        begin
          --get a batch color, the first one created
          select min(batchcolor_id) into lv_batchcolor_id from batchcolor;
          --get highest possible batch number
          select nvl(max(bt.batchnumber), 0) + 1
          into   lv_batchnumber
          from   batch bt
          where  bt.businessunit_id = fp_businessunitid
          and    bt.year = lv_year
          and    bt.week = lv_week
          and    bt.batchnumber >= lv_batchnumber_ss + lv_addvalue
          and    bt.batchnumber < lv_batchnumber_ss + lv_addvalue + lv_range;
          if lv_batchnumber < lv_batchnumber_ss then
            begin
              lv_batchnumber := lv_batchnumber_ss + lv_addvalue; --HVL 09-10-2013
            end;
          end if;
          --create batch
          fp_message := 'create batch';
          insert into batch
            (batch_id, businessunit_id, year, week, batchnumber, batchcode, day_id, batchdate,
             origin, status, extrahandling, bulkmasterbatch_id, closingdate, closinguser_id,
             customer_link_id, systemuser_id, timestamp, batchcolor_id, employee_id, route_id,
             directinvoicetimestamp)
          values
            (seq_batch.nextval, fp_businessunitid, lv_year, lv_week, lv_batchnumber, null,
             getabsdaynumber(fp_date_param), fp_date_param, 9, 0, 'N', null, null, null, null,
             fp_systemuserid, sysdate, lv_batchcolor_id, null, null, null)
          returning batch_id into fp_out_batchid;
          write_logging('created batch ' || to_char(lv_batchnumber) || ' for year ' ||
                        to_char(lv_year) || ' week ' || to_char(lv_week) || ' day ' ||
                        to_char(getabsdaynumber(fp_date_param)) || ' for businessunit ' ||
                        fp_unitcode, fp_loglevel, fp_logname, fp_plantid, 1, 1);
        end;
      end if;
    end get_batch;

    procedure get_batch_with_batchcode is
      lv_batchcolor_id batchcolor.batchcolor_id%type;
      lv_year          number;
      lv_week          number;
      lv_batchnumber   batch.batchnumber%type;
      lv_batchcode     batch.batchcode%type;

      procedure get_next_batchnumber is
        lv_batchforsortingsystem number;
        procedure check_batchnumber(fp_batchnumber in number) is
          lv_xbatchnumber number;
        begin
          select bt.batchnumber
          into   lv_xbatchnumber
          from   batch bt
          where  bt.businessunit_id = fp_businessunitid
          and    bt.year = lv_year
          and    bt.week = lv_week
          and    bt.batchnumber = fp_batchnumber;
          lv_batchnumber := lv_xbatchnumber;
        end check_batchnumber;
      begin
        --get_next_batchnumber
        lv_batchforsortingsystem := nvl(to_number(get_systemsettting(fp_plantid,
                                                                     'BATCHFORSORTINGSYSTEM')), 1);
        for i in lv_batchforsortingsystem .. lv_batchforsortingsystem * 10000 loop
          begin
            --we loop batch per bu year week,
            --starting with BATCHFORSORTINGSYSTEM startnumber to get next new value
            check_batchnumber(i);
          end;
        end loop;
      exception
        when no_data_found then
          begin
            lv_batchnumber := nvl(lv_batchnumber + 1, lv_batchforsortingsystem);
          end;
      end get_next_batchnumber;
    begin
      fp_message := 'get_create_clientdelnote.get_batch_with_batchcode';
      if (fp_in_batchid is not null) then
        fp_out_batchid := fp_in_batchid;
        select min(b.batchcode) into lv_batchcode from batch b where b.batch_id = fp_in_batchid;
        if (lv_batchcode is null) then
          begin
            update batch b set b.batchcode = fp_batchcode where b.batch_id = fp_in_batchid;
          end;
        end if;
      else
        select min(bt.batch_id)
        into   fp_out_batchid
        from   batch bt
        where  bt.businessunit_id = fp_businessunitid
        and    bt.batchcode = fp_batchcode
        and    bt.customer_link_id = fp_customerid
        and    bt.status <> 4;
      end if;
      if fp_out_batchid is null then
        begin
          --get year week
          lv_year := getyearofweek(fp_date_param);
          lv_week := getisoweek(fp_date_param);
          --get_next_batchnumber
          get_next_batchnumber;
          select min(batchcolor_id) into lv_batchcolor_id from batchcolor;
          fp_message := 'create batch';
          insert into batch
            (batch_id, businessunit_id, year, week, batchnumber, batchcode, day_id, batchdate,
             origin, status, extrahandling, bulkmasterbatch_id, closingdate, closinguser_id,
             customer_link_id, systemuser_id, timestamp, batchcolor_id, employee_id, route_id,
             directinvoicetimestamp)
          values
            (seq_batch.nextval, fp_businessunitid, lv_year, lv_week, lv_batchnumber, fp_batchcode,
             getabsdaynumber(fp_date_param), fp_date_param, 9, 3, 'N', null, null, null,
             fp_customerid, fp_systemuserid, sysdate, lv_batchcolor_id, null, null, null)
          returning batch_id into fp_out_batchid;
          write_logging('created batch ' || to_char(lv_batchnumber) || ' for year ' ||
                        to_char(lv_year) || ' week ' || to_char(lv_week) || ' day ' ||
                        to_char(getabsdaynumber(fp_date_param)) || ' for businessunit ' ||
                        fp_unitcode, fp_loglevel, fp_logname, fp_plantid, 1, 1);
        end;
      end if;
    end get_batch_with_batchcode;

    procedure get_batch_rfl is
      lv_batchcolor_id  batchcolor.batchcolor_id%type;
      lv_year           number;
      lv_week           number;
      lv_day            number;
      lv_addvalue       number := 0;
      lv_range          number := 2000; -- RvdZ: more space for customer/day-batches    HVL 20240330  changed to 2000
      lv_batchnumber    batch.batchnumber%type;
      lv_batchnumber_ss batch.batchnumber%type;
      lv_origin         number;
      lv_colornr        number;
    begin
      fp_message := 'get_create_clientdelnote.get_batch';
      lv_year    := getyearofweek(fp_date_param);
      lv_week    := getisoweek(fp_date_param);
      lv_day     := getabsdaynumber(fp_date_param);
      --get default batch number
      lv_batchnumber_ss := nvl(to_number(get_systemsettting(fp_plantid, 'BATCHFORSORTINGSYSTEM')), 1);
      lv_batchnumber    := lv_batchnumber_ss;
      if fp_logname = 'SENDTRACKINFORS' then
        begin
          lv_addvalue    := lv_range; --added value for sendtrackinfo HVL/PVD 24-9-2013
          lv_batchnumber := lv_batchnumber + lv_addvalue; --HVL 25-09-2012
        end;
      end if;
      -- determine lv_origin
      if fp_logname = 'GETGARMENTDATARS' or fp_logname = 'SENDTRACKINFORSX' then
        -- metricon getgarmentdata or fp_hangsorting=1
        lv_origin  := 11;
        lv_colornr := 6;
      else
        -- technico fp_hangsorting=0
        lv_origin  := 9;
        lv_colornr := 7;
      end if;
      --get_batch
      fp_message := 'get batch';
      select min(bt.batch_id)
      into   fp_out_batchid
      from   batch bt
      where  bt.businessunit_id = fp_businessunitid
      and    bt.year = lv_year
      and    bt.week = lv_week
      and    bt.day_id = lv_day
      and    bt.origin = lv_origin
      and    bt.batchnumber >= lv_batchnumber_ss + lv_addvalue
      and    bt.batchnumber < lv_batchnumber_ss + lv_addvalue + lv_range
      and    bt.status <> 4
      and    ((lv_origin = 9 and bt.customer_link_id is null) or -- technico: single batch
            (lv_origin = 11 and bt.customer_link_id = fp_customerid) -- metricon: batch per customer
            );
      if fp_out_batchid is null then
        begin
          if fp_databasecode = 'RFL' then
            begin
              --get color
              select col.batchcolor_id
              into   lv_batchcolor_id
              from   batchcolor col
              where  col.batchcolornumber = lv_colornr;
            exception
              when no_data_found then
                begin
                  --get a batch color, the first one created
                  select min(batchcolor_id) into lv_batchcolor_id from batchcolor;
                end;
            end;
          else
            begin
              --get a batch color, the first one created
              select min(batchcolor_id) into lv_batchcolor_id from batchcolor;
            end;
          end if;
          --get highest possible batch number
          select nvl(max(bt.batchnumber), 0) + 1
          into   lv_batchnumber
          from   batch bt
          where  bt.businessunit_id = fp_businessunitid
          and    bt.year = lv_year
          and    bt.week = lv_week
          and    bt.batchnumber >= lv_batchnumber_ss + lv_addvalue
          and    bt.batchnumber < lv_batchnumber_ss + lv_addvalue + lv_range;
          if lv_batchnumber < lv_batchnumber_ss then
            begin
              lv_batchnumber := lv_batchnumber_ss + lv_addvalue; --HVL 09-10-2013
            end;
          end if;
          --create batch
          fp_message := 'create batch';
          insert into batch
            (batch_id, businessunit_id, year, week, batchnumber, batchcode, day_id, batchdate,
             origin, status, extrahandling, bulkmasterbatch_id, closingdate, closinguser_id,
             customer_link_id, systemuser_id, timestamp, batchcolor_id, employee_id, route_id,
             directinvoicetimestamp)
          values
            (seq_batch.nextval, fp_businessunitid, lv_year, lv_week, lv_batchnumber, null, lv_day,
             fp_date_param, lv_origin, 0, 'N', null, null, null,
             (case when lv_origin = 11 then fp_customerid else null end), fp_systemuserid, sysdate,
             lv_batchcolor_id, null, null, null)
          returning batch_id into fp_out_batchid;
          write_logging('created batch ' || to_char(lv_batchnumber) || ' for year ' ||
                        to_char(lv_year) || ' week ' || to_char(lv_week) || ' day ' ||
                        to_char(getabsdaynumber(fp_date_param)) || ' for businessunit ' ||
                        fp_unitcode, fp_loglevel, fp_logname, fp_plantid, 1, 1);
        end;
      end if;
    end get_batch_rfl;

    procedure get_route_pwb is
    begin
      --get_route_pwb
      --ROUTE_ID, CUSTOMER_ID, STOPNUMBER, DATEACTIVE
      select min(rs.route_id), min(rs.stopnumber)
      into   fp_routid, fp_stopnumber
      from   routestop rs
      join   route r
      on     r.route_id = rs.route_id
      where  rs.customer_id = fp_customerid
      and    r.drivingday_id = getabsdaynumber(lv_deliverydate)
      and    (rs.deliverypoint_id is null or rs.deliverypoint_id = fp_deliverypointid)
      and    fp_date_param between rs.dateactive and rs.dateinactive;
    end get_route_pwb;

    procedure create_inscan is
      lv_clientdeliverynotelineid clientdeliverynoteline.clientdeliverynoteline_id%type := null;
      lv_clientdelnotelinescanid  clientdelnotelinescan.clientdelnotelinescan_id%type := null;
    begin
      --HVL 25-09-2012
      --create_inscan
      if fp_logname = 'GETGARMENTDATARS' and fp_clientdeliverynoteid is not null then
        begin
          lv_clientdeliverynotelineid := pack_sort_rs.create_cliendelnoteline(fp_idcode,
                                                                              fp_clientdeliverynote,
                                                                              fp_clientdeliverynoteid,
                                                                              fp_plantid, fp_unitcode,
                                                                              fp_businessunitid,
                                                                              fp_customerid,
                                                                              fp_productgroupid,
                                                                              fp_productid, fp_sizeid,
                                                                              fp_finishingmethodid,
                                                                              fp_systemuserid,
                                                                              fp_loglevel, fp_logname,
                                                                              2);
          -- Call the procedure
          pack_sort_rs.create_clientdelnotescan(lv_clientdelnotelinescanid, fp_idcode,
                                                fp_clientdeliverynote, lv_clientdeliverynotelineid,
                                                fp_plantid, fp_unitcode, fp_loglevel, fp_logname,
                                                fp_systemuserid, fp_uniqueresidentialitemid, 'IN',
                                                fp_date_param);
        end;
      end if;
    end create_inscan;

    procedure create_cdn is
      lv_sequencenumber        clientdeliverynote.sequencenumber%type;
      lv_invoicebusinessunitid businessunit.businessunit_id%type;
      lv_rooomnumber           departmentroom.roomnumber%type;
    begin
      fp_message := 'get_create_clientdelnote.create_cdn';
      lv_rooomnumber:=null;
      --check lv_deliverydate
      if lv_deliverydate is null then
        begin
          fp_message := 'Cannot find residential delivery day(s) for this customer / department!';
          raise no_data_found;
        end;
      end if;
      -- get roomnumber
      select dr.roomnumber
      into lv_rooomnumber
      from clientresident cr, departmentroom dr
      where cr.departmentroom_id=dr.departmentroom_id
      and cr.client_id=fp_clientid;
      -- get sequence number
      select nvl(max(cdn.sequencenumber), 0) + 1
      into   lv_sequencenumber
      from   clientdeliverynote cdn
      where  cdn.batch_id = fp_out_batchid;
      --get lv_invoicebusinessunitid
      select nvl(max(ca.invoicebusinessunit_id), fp_businessunitid)
      into   lv_invoicebusinessunitid
      from   customeractivities ca
      where  ca.customer_id = fp_customerid
      and    ca.activity_id =
             (select g.activity_id from productgroup g where g.productgroup_id = fp_productgroupid);
      --fp_clientdeliverynote
      execute immediate 'select seq_clientdelnote_' || fp_unitcode || '.nextval from dual'
        into fp_clientdeliverynote;
      --create client delivery note;
      fp_message := 'insert into clientdeliverynote';
      insert into clientdeliverynote
        (clientdeliverynote_id, processbusinessunit_id, invoicebusinessunit_id,
         clientdeliverynotenumber, batch_id, sequencenumber, customer_link_id, client_link_id, name,
         street, zipcode, city, state, roomnumber, route_id, stopnumber, origin,
         weighingcategory_link_id, tareweight, grossweight, weightdecimals, weighingsequencenumber,
         weighingtimestamp, startinscan, startoutscan, deliverydate, creationdate, creationuser_id,
         closingdate, closinguser_id, boxnumber, systemuser_id, timestamp, weightprice,
         originaldeliverydate)
      values
        (seq_clientdeliverynote.nextval, fp_businessunitid, lv_invoicebusinessunitid,
         fp_clientdeliverynote, fp_out_batchid, lv_sequencenumber, fp_customerid, fp_clientid, null,
         null, null, null, null, lv_rooomnumber , fp_routid, fp_stopnumber, nvl(lv_origin, 9), null, 0, 0, 0,
         null, null, null, null, lv_deliverydate, sysdate, 1, null, null, 0, fp_systemuserid,
         sysdate, 0, lv_deliverydate)
      returning clientdeliverynote_id into fp_clientdeliverynoteid;
      write_logging(fp_logname || ' created clientdeliverynote number ' ||
                    to_char(fp_clientdeliverynote) || ' for businessunit ' || fp_unitcode,
                    fp_loglevel, fp_logname, fp_plantid, 1, 1);
      if fp_routid is null then
        begin
          write_logging(fp_logname || ' No route found newly created clientdeliverynote number ' ||
                        to_char(fp_clientdeliverynote) || ' for businessunit ' || fp_unitcode,
                        fp_loglevel, fp_logname, fp_plantid, 2, 1);
        end;
      end if;
      --HVL 25-09-2012 create inscan
      create_inscan;
    end create_cdn;
  begin
    fp_message := 'get_create_clientdelnote';
    if fp_databasecode = 'RFL' and fp_logname = 'GETGARMENTDATARS' then
      lv_origin := 11;
    else
      case fp_logname
        when 'SENDTRACKINFORS' then
          --HVL  25-09-2012
          lv_origin := 10; --send track info clientdeliverynote when it is created
        when 'SENDTRACKINFORSX' then
          lv_origin := 11;
        else
          lv_origin := 9; --get garment data clientdeliverynote when it is created
      end case;
    end if;
    --get system setting lv_batchnrforlabels
    lv_batchnrforlabels := nvl(to_number(get_systemsettting(fp_plantid, 'BATCHNRFORLABELS')), -1);
    --get_clientdelnotescan
    fp_message := 'get_clientdelnotescan';
    get_clientdelnotescan(fp_uniqueresidentialitemid, fp_businessunitid, fp_update_startoutscan,
                          fp_out_batchid, fp_clientdelnotlinescanid, fp_clientdeliverynote,
                          fp_routid, fp_stopnumber, fp_clientdeliverynoteid, lv_deliverydate,
                          lv_clientdeliverynotlineid,
                          (case when fp_databasecode = 'RFL' then fp_logname else null end),
                          fp_batchcode);
    --check for another note is the clientdeliverynote is not found
    if (fp_clientdeliverynote is null) then
      --step 3
      --determine if there is a client delivery note
      fp_clientdelnotlinescanid := null;
      fp_message                := 'get_create_clientdelnote check for client del note';
      for ycd in (select cdn.clientdeliverynote_id, cdn.clientdeliverynotenumber, cdn.route_id,
                         cdn.stopnumber, cdn.batch_id, cdn.deliverydate
                  from   clientdeliverynote cdn
                  left   outer join batch b
                  on     b.batch_id = cdn.batch_id
                  where  cdn.client_link_id = fp_clientid
                  and    cdn.processbusinessunit_id = fp_businessunitid
                  and    nvl(cdn.closingdate, to_date('31-12-2099', 'dd-mm-yyyy')) =
                         to_date('31-12-2099', 'dd-mm-yyyy')
                  and    (nvl(cdn.startoutscan, to_date('31-12-2099', 'dd-mm-yyyy')) =
                        to_date('31-12-2099', 'dd-mm-yyyy') or fp_update_startoutscan = 1)
                  and    ((fp_update_startoutscan <> 1 and cdn.origin <> 10) or
                        (fp_update_startoutscan = 1 and cdn.origin in (10, 11))) --check HVL PVD 2-10-2012
                  and    not exists (select 1
                          from   batch bt
                          where  bt.batch_id = cdn.batch_id
                          and    bt.batchnumber = lv_batchnrforlabels)
                  and    (fp_databasecode <> 'RFL' or
                        (fp_logname <> 'SENDTRACKINFORS' and cdn.origin = 11) -- GETGARMENTDATA/SENDTRACKINFORSX = Jensen
                        or (fp_logname = 'SENDTRACKINFORS' and cdn.origin <> 11) -- SENDTRACKINFORS = Technico
                        )
                  and    (b.batchcode = fp_batchcode or fp_batchcode is null)
                  order  by cdn.deliverydate desc, cdn.clientdeliverynotenumber desc) loop
        begin
          fp_clientdeliverynoteid := ycd.clientdeliverynote_id;
          fp_clientdeliverynote   := ycd.clientdeliverynotenumber;
          fp_routid               := ycd.route_id;
          fp_stopnumber           := ycd.stopnumber;
          fp_out_batchid          := ycd.batch_id;
          lv_deliverydate         := ycd.deliverydate;
          --HVL 25-09-2012 create inscan
          create_inscan;
          exit;
        end;
      end loop; --ycd
    end if;
    if (lv_deliverydate is null or fp_databasecode = 'CLO') then
      lv_deliverydate := get_next_deldate_tom5(fp_date_param, fp_customerid, fp_departmentid,
                                               fp_databasecode);
    end if;
    if (fp_routid is null or fp_databasecode = 'CLO') then
      begin
        --determine the not existing route id
        get_route_pwb;
        if fp_databasecode = 'CLO' then
          begin
            --always update for Clova
            update clientdeliverynote cdn
            set    cdn.route_id = fp_routid, cdn.deliverydate = lv_deliverydate
            where  cdn.clientdeliverynote_id = fp_clientdeliverynoteid;
          end;
        elsif fp_routid is not null then
          --link route found to clientdeliverynote HVL 22-11-2013
          update clientdeliverynote cdn
          set    cdn.route_id = fp_routid, cdn.deliverydate = lv_deliverydate
          where  cdn.route_id is null
          and    cdn.clientdeliverynote_id = fp_clientdeliverynoteid;
        end if;
      end;
    end if;
    --get the route info
    get_routeinfo;
    if fp_clientdeliverynote is null then
      begin
        if fp_databasecode = 'RFL' then
          get_batch_rfl;
        else
          if (fp_batchcode is not null) then
            get_batch_with_batchcode;
          else
            get_batch;
          end if;
        end if;
        create_cdn;
      end;
    end if;
    if fp_update_startoutscan = 1 then
      begin
        fp_message := 'update clientdeliverynote ' || to_char(fp_clientdeliverynote) ||
                      ' startoutscan date';
        update clientdeliverynote cdn
        set    cdn.startoutscan = fp_date_param
        where  cdn.clientdeliverynote_id = fp_clientdeliverynoteid;
      end;
    end if;
    fp_message := null;
    fp_status  := 0;
  exception
    --error handling
    when no_data_found then
      begin
        fp_clientdeliverynote := null;
        fp_status             := 1; --no_data_found
        raise;
      end;
    when too_many_rows then
      begin
        fp_message            := fp_message || sqlerrm;
        fp_clientdeliverynote := null;
        fp_status             := 2; --too many rows
        raise;
      end;
    when dup_val_on_index then
      begin
        fp_message            := fp_message || sqlerrm;
        fp_clientdeliverynote := null;
        fp_status             := 3; --dup_val_on_index
        raise;
      end;
    when lv_userexception then
      begin
        fp_message := fp_message || sqlerrm;
        fp_status  := 3; --user exception
        raise;
      end;
    when others then
      begin
        fp_message            := fp_message || sqlerrm;
        fp_clientdeliverynote := null;
        fp_status             := 4; --others
        raise;
      end;
  end get_create_clientdelnote;

  function call_ws_printclientdelnote(fp_clientdeliverynoteid in number,
                                      fp_workstationid        in number,
                                      fp_loglevel             in number,
                                      fp_year                 in number,
                                      fp_month                in number,
                                      fp_day                  in number,
                                      fp_hours                in number,
                                      fp_minutes              in number,
                                      fp_seconds              in number,
                                      fp_milliseconds         in number,
                                      v_url                   in varchar2) return varchar2 as
    req_text varchar2(4000);
    --req_text2            varchar2(4000);
    req                 utl_http.req;
    res                 utl_http.resp;
    res_text            varchar2(32767);
    resp_pos1           number;
    resp_pos2           number;
    resp_string         varchar2(4000);
    resp_errorcode_pos1 number;
    resp_errorcode_pos2 number;
    resp_errormess_pos1 number;
    resp_errormess_pos2 number;
    resp_errorcode      varchar2(4000);
    resp_errormess      varchar2(4000);
    lv_sequence         number;
    lv_user_exception   exception;
  begin
    --get the sequence seq_wsprintclientdelnote
    select seq_wsprintclientdelnote.nextval into lv_sequence from dual;
    --fill the text
    req_text := '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
    <ns0:processRequest xmlns:ns0="urn:ABS">
      <String_1>
      &lt;ns0:ABSServiceHeader xmlns:ns0="http://absgroup/webservice/generated/xmlbindings/ABSServiceHeader"&gt;
         &lt;messageID&gt;' || lv_sequence || '&lt;/messageID&gt;
         &lt;transactionType&gt;Update&lt;/transactionType&gt;
         &lt;function&gt;PRINTCLIENTDELIVERYNOTE&lt;/function&gt;
         &lt;application&gt;JUnit Test&lt;/application&gt;
         &lt;customer&gt;QuickFit&lt;/customer&gt;
         &lt;webuser&gt;WEBUSER&lt;/webuser&gt;
      &lt;/ns0:ABSServiceHeader&gt;
      </String_1>
      <String_2>
       &lt;tns:PrintClientDeliveryNoteRequest xmlns:tns="http://absgroup/webservice/generated/xmlbindings/PrintClientDeliveryNoteRequest"&gt;
       &lt;ClientDeliveryNote_ID&gt;' || fp_clientdeliverynoteid ||
                '&lt;/ClientDeliveryNote_ID&gt;
       &lt;Workstation_ID&gt;' || fp_workstationid || '&lt;/Workstation_ID&gt;';
    if (fp_year <> 0 and fp_month <> 0 and fp_day <> 0) then
      req_text := req_text || '&lt;ClosingDate&gt;
            &lt;year&gt;' || fp_year || '&lt;/year&gt;
            &lt;month&gt;' || fp_month || '&lt;/month&gt;
            &lt;day&gt;' || fp_day || '&lt;/day&gt;
            &lt;hours&gt;' || fp_hours || '&lt;/hours&gt;
            &lt;minutes&gt;' || fp_minutes || '&lt;/minutes&gt;
            &lt;seconds&gt;' || fp_seconds || '&lt;/seconds&gt;
            &lt;milliseconds&gt;' || fp_milliseconds ||
                  '&lt;/milliseconds&gt;
       &lt;/ClosingDate&gt;';
    end if;
    req_text := req_text || '&lt;LogLevel&gt;' || fp_loglevel || '&lt;/LogLevel&gt;
       &lt;/tns:PrintClientDeliveryNoteRequest&gt;
      </String_2>
    </ns0:processRequest>
   </soap:Body>
  </soap:Envelope>';
    begin
      req := utl_http.begin_request(v_url, 'POST', 'HTTP/1.1');
    exception
      when others then
        begin
          return utl_http.get_detailed_sqlerrm();
        end;
    end;
    utl_http.set_header(req, 'Content-Type', 'text/xml');
    utl_http.set_header(req, 'Content-Length', length(req_text));
    utl_http.set_header(req, 'SOAPAction', v_url || '/processRequest');
    utl_http.write_text(req, req_text);
    res := utl_http.get_response(req);
    utl_http.read_text(res, res_text);
    utl_http.end_response(res);
    --output
    dbms_output.enable(100000);
    dbms_output.put_line(res_text);
    --extract response code
    begin
      select instr(res_text, '&lt;ResponseCode xmlns=""&gt;', 1, 1) into resp_pos1 from dual;
      select instr(res_text, '&lt;/ResponseCode&gt;', 1, 1) into resp_pos2 from dual;
      select substr(res_text, resp_pos1 + length('&lt;ResponseCode xmlns=""&gt;'),
                     resp_pos2 - (resp_pos1 + length('&lt;ResponseCode xmlns=""&gt;')))
      into   resp_string
      from   dual;
      if resp_string is null then
        raise lv_user_exception;
      end if;
      if resp_string <> 'OK' then
        --get error code
        select instr(res_text, '&lt;Code xmlns=""&gt;', 1, 1) into resp_errorcode_pos1 from dual;
        select instr(res_text, '&lt;/Code&gt;', 1, 1) into resp_errorcode_pos2 from dual;
        select substr(res_text, resp_errorcode_pos1 + length('&lt;Code xmlns=""&gt;'),
                       resp_errorcode_pos2 - (resp_errorcode_pos1 + length('&lt;Code xmlns=""&gt;')))
        into   resp_errorcode
        from   dual;
        --get error message
        select instr(res_text, '&lt;Message xmlns=""&gt;', 1, 1)
        into   resp_errormess_pos1
        from   dual;
        select instr(res_text, '&lt;/Message&gt;', 1, 1) into resp_errormess_pos2 from dual;
        select substr(res_text, resp_errormess_pos1 + length('&lt;Message xmlns=""&gt;'),
                       resp_errormess_pos2 -
                        (resp_errormess_pos1 + length('&lt;Message xmlns=""&gt;')))
        into   resp_errormess
        from   dual;
        return resp_errorcode || ' ' || resp_errormess;
      end if;
    exception
      when lv_user_exception then
        begin
          select utl_http.get_detailed_sqlerrm into resp_string from dual;
          return sqlerrm || ' ' || resp_string;
        end;
      when others then
        begin
           return res_text;
        end;
    end;
    return resp_string;
  end call_ws_printclientdelnote;

  procedure close_batch(fp_batch_id in batch.batch_id%type) is
    lv_open_cdn_count number;
    lv_systemuserid   systemuser.systemuser_id%type;
  begin
    --close_batch
    select count(1)
    into   lv_open_cdn_count
    from   clientdeliverynote cdn
    where  cdn.batch_id = fp_batch_id
    and    cdn.closingdate is null;
    if lv_open_cdn_count = 0 then
      begin
        begin
          select s.systemuser_id into lv_systemuserid from systemuser s where s.username = 'SORT';
        exception
          when no_data_found then
            select min(systemuser_id) into lv_systemuserid from systemuser;
        end;
        --close batch
        update batch bt
        set    bt.closingdate = trunc(sysdate), bt.status = 4, bt.systemuser_id = lv_systemuserid
        where  bt.batch_id = fp_batch_id;
      end;
    end if;
  end close_batch;

end pack_sort_rs;
/
create or replace package pack_sqitemsincirculation is

  /****************************************************************************************************\
  * New version 08-dec-2017                                                                            *
  * Version 2.11  Pack_SQItemsInCirculation                                                            *
  * Updated:                                                                                           *
  *   08-Dec-2017 totally new version ABS-55074 Rework PACKAGE pack_sqitemsincirculation from scratch  *
  *   12-Mar-2018 updates the PLPC fields totalincirculation totalincirculationcharged as well         *
  *   20-Mar-2018 take into account fp_inactiveplpc also inactive customers                            *
  *   13-Mar-2019 ABS-80386 Customer owned items invoiced for rent                                     *
  *   03-07-2019 ABS-84024 Deposit stay on garments not taken in to consideration                      *
  *   12-08-2020 ABS-106202 Invoice QTY of emblem rent is not correct
  *   27-08-2020 ABS-106202 Invoice QTY of emblem rent is not correct  (rework)
  *   02-09-2020  ABS-106202 Invoice QTY of emblem rent is not correct  (rework2)
  *   05-11-2020  ABS-108411 Temporary rent stop for wearer inventory is invoiced                      *
  *   02-03-2021  ABS-114088 uniqueitems are counted for all customerActivity.processingBU
  *   20-07-2021  ABS-121877 DEPOSITSTOCK - Status Quo quantities are not calculated           *
  *   09-09-2021  ABS-123487 Issue with rent pieces in SQ items in circ                                *
  *   09-09-2021  ABS-124415 Add missing part for season and update freeseasoncircinv and
                  beyondlifetimecirc conditions on sq_itemsincirculation.pck
  *   04-03-2022 ABS-131822 problem with fully amortized garments                                      *
    \****************************************************************************************************/

  --Main procedure createsqitemsincirculation
  procedure createsqitemsincirculation(fp_sqheaderid                out nocopy statusquoheader.statusquoheader_id%type,
                                       fp_processbuid               in businessunit.businessunit_id%type,
                                       fp_invoicebuid               in businessunit.businessunit_id%type,
                                       fp_sqdate                    in date,
                                       fp_sqyear                    in int,
                                       fp_sqweek                    in int,
                                       fp_sqmonth                   in int,
                                       fp_sqsubtype                 in int,
                                       fp_systemuserid              in systemuser.systemuser_id%type,
                                       fp_checkinvoicebu            in int,
                                       fp_userentonstock            in int,
                                       fp_inactiveplpc              in int,
                                       fp_plantid                   in plant.plant_id%type,
                                       fp_invoicereplacements       in int,
                                       fp_invoicesubstitutes        in int,
                                       fp_sqonwearerlevel           in int,
                                       fp_userentbasedonreturnweeks in int,
                                       fp_settlementactive          in int,
                                       fp_chargereplacedproduct     in int,
                                       fp_abslogprocessjob          in int);

  --Check_Duplicate_PLPC make sure there are no duplicate PLPC's
  procedure check_duplicate_plpc;

end pack_sqitemsincirculation;
/
create or replace package body pack_sqitemsincirculation is
  --external procedure
  procedure createsqitemsincirculation(fp_sqheaderid                out nocopy statusquoheader.statusquoheader_id%type,
                                       fp_processbuid               in businessunit.businessunit_id%type,
                                       fp_invoicebuid               in businessunit.businessunit_id%type,
                                       fp_sqdate                    in date,
                                       fp_sqyear                    in int,
                                       fp_sqweek                    in int,
                                       fp_sqmonth                   in int,
                                       fp_sqsubtype                 in int,
                                       fp_systemuserid              in systemuser.systemuser_id%type,
                                       fp_checkinvoicebu            in int,
                                       fp_userentonstock            in int,
                                       fp_inactiveplpc              in int,
                                       fp_plantid                   in plant.plant_id%type,
                                       fp_invoicereplacements       in int,
                                       fp_invoicesubstitutes        in int,
                                       fp_sqonwearerlevel           in int,
                                       fp_userentbasedonreturnweeks in int,
                                       fp_settlementactive          in int,
                                       fp_chargereplacedproduct     in int,
                                       fp_abslogprocessjob          in int) is
    --global variables
    /*Parameter fp_inactiveplpc
     This setting is applicable both for SQ items in circulation and SQ mats in circulation.
       0 = All items are processed, also with inactive PLPC.
           When PLPC is inactive the billing method from the last (last dateinactive) PLPC is taken.
       1 = All items are processed, also with inactive PLPC.
       2 = Process only items with active PLPC.
    In case of mats in circulation option 0 and 1 are the same.
    */
    gv_message                  abslog.message%type;
    gv_sizestarid               sizedefinition.sizedefinition_id%type;
    gv_flagsubstituteid         flag.flag_id%type;
    gv_flagreplacementid        flag.flag_id%type;
    gv_statusidforuniqueinstock status.status_id%type;
    gv_statusincirculation      status.status_id%type;
    gv_statusassigned           status.status_id%type;
    gv_underusemethodss         systemsetting.value%type;
    gv_bm3maxinvreducedepositss systemsetting.value%type;
    gv_staydepositstockid       stay.stay_id%type;
    gv_sqheaderid               statusquoheader.statusquoheader_id%type;

    --interal procedures
    procedure write_log(fp_message in varchar2, fp_priority in number) is
    begin
      /* writes logs into database.
      priority
      1 = Message
      2 = Warning
      3 = Error
      4 = Stack trace
      5 = Debug info  */
      abslogwrite.abslog_write(5, 'Pack_SQItemInCirculation', null, fp_priority, fp_message,
                               fp_systemuserid);
      begin
        dbms_output.put_line(fp_message);
      exception
        when others then
          null;
      end;
    end write_log;

    procedure initialize is
    begin
      --initialize
      -- size *
      gv_message := 'get size *';
      select sizedefinition_id into gv_sizestarid from sizedefinition where code = '*';
      --automaticflag substitute
      gv_message := 'automaticflag substitute (12)';
      select af.flag_id
      into   gv_flagsubstituteid
      from   automaticflag af
      where  af.automaticflag_id = 12;
      --automaticflag replacement
      gv_message := 'automaticflag replacement (4)';
      select af.flag_id
      into   gv_flagreplacementid
      from   automaticflag af
      where  af.automaticflag_id = 4;
      --status_id for UI Assigned
      gv_message := 'get status UI, 30';
      select st.status_id
      into   gv_statusassigned
      from   status st
      where  st.statustype = 'UI'
      and    st.code = '30';
      --status_id for UI In circulation
      gv_message := 'get status UI, 20';
      select st.status_id
      into   gv_statusincirculation
      from   status st
      where  st.statustype = 'UI'
      and    st.code = '20';
      --status_id for UI In stock (used for createSQItemInCircOnUniqueRent )
      gv_message := 'get status UI, 10';
      select st.status_id
      into   gv_statusidforuniqueinstock
      from   status st
      where  st.statustype = 'UI'
      and    st.code = '10';
      --gv_staydepositstockid
      select st.stay_id
      into   gv_staydepositstockid
      from   stay st
      where  st.staytype = 1
      and    st.staynr = 37;
      --system setting underuseMethodSS
      gv_message := 'UNDERUSEMETHOD for plant id ' || fp_plantid;
      select ss.value
      into   gv_underusemethodss
      from   systemsetting ss
      where  upper(ss.name) like upper('UNDERUSEMETHOD')
      and    ss.groupname = 'Billing'
      and    ss.plant_id = fp_plantid;
      --system setting bm3MaxInvReduceDepositSS
      gv_message := 'BM3MAXINVREDUCEDEPOSIT for plant id ' || fp_plantid;
      select ss.value
      into   gv_bm3maxinvreducedepositss
      from   systemsetting ss
      where  upper(ss.name) like upper('BM3MAXINVREDUCEDEPOSIT')
      and    ss.groupname = 'Billing'
      and    ss.plant_id = fp_plantid;
    end initialize;

    procedure create_sq_header is
    begin
      --cleanup old sq
      gv_message := 'cleanup old sq';
      delete statusquoheader sh
      where  sh.year = fp_sqyear
      and    sh.week = fp_sqweek
      and    sh.processbusinessunit_id = fp_processbuid
      and    sh.invoicebusinessunit_id = fp_invoicebuid
      and    sh.statusquotype = 1
      and    sh.totalquantity = 0;
      --create_sq_header
      gv_message := 'create_sq_header';
      insert into statusquoheader
        (statusquoheader_id, processbusinessunit_id, invoicebusinessunit_id, statusquodate,
         statusquotype, totalquantity, year, week, month, subtype, abslogprocessjob_id,
         systemuser_id, timestamp)
      values
        (seq_statusquoheader.nextval, fp_processbuid, fp_invoicebuid, fp_sqdate, 1, 0, fp_sqyear,
         fp_sqweek, fp_sqmonth, fp_sqsubtype, fp_abslogprocessjob, fp_systemuserid, sysdate)
      returning statusquoheader_id into gv_sqheaderid;
    end create_sq_header;

    procedure add_non_uniqueitem is
    begin
      --Add_NON_uniqueitem
      gv_message := 'Add_NON_uniqueitem';
      insert into sqitemincirculation
        (sqitemincirculation_id, statusquoheader_id, customer_link_id, department_link_id,
         distributionpoint_link_id, weareremployment_link_id, product_link_id,
         sizedefinition_link_id, finishingmethod_id, maxinv, totalcircinv, changesperweek,
         maxfreeinv, freeissuedcircinv, cogcircinv, freeseasoncircinv, beyondlifetimecirc,
         variationmaxinv, variationtotalcircinv, variationchangesperweek, variationmaxfreeinv,
         variationrentedperpiece, variationfreeissuedcircinv, variationcogcircinv,
         variationfreeseasoncircinv, variationbeyondlifetimecirc, systemuser_id, timestamp,
         qtyrentedperpiece, qtyrentedother, variationrentedother, qtycustomerrentstop,
         variationqtycustomerrentstop, qtyrentstop, variationqtyrentstop, emblemtemplate_id,
         qtyrentemblem, variationqtyrentemblem, qtyreplacement, variationqtyreplacement, qtyassigned,
         variationqtyassigned, qtyrenteddepositstock, variationrenteddepositstock, qtysubstitute,
         variationqtysubstitute, chargeafterdepreciation, yearweek, qtyrentedperpiecepool,
         variationrentedperpiecepool, wearerinvoicecategory_id, qtyfullyamortized,
         variationqtyfullyamortized, qtyrentedreturnrent, variationqtyrentedreturnrent,
         qtyrentedminrent, variationqtyrentedminrent)
        select seq_sqitemincirculation.nextval, gv_sqheaderid, x.customer_id, x.department_id,
               x.distributionpoint_id, x.weareremployment_id, x.product_id, x.sizedefinition_id,
               x.finishingmethod_id, x.maxinventory, x.totalcircinv, x.changesperweek,
               x.maxfreeofcharge, x.freeissuedcircinv, 0 /*cogcircinv*/, x.freeseasoncircinv, 0
               /*beyondlifetimecirc*/, 0 /*variationmaxinv*/, 0 /*variationtotalcircinv*/, 0
               /*variationchangesperweek*/, 0 /*variationmaxfreeinv*/, 0 /*variationrentedperpiece*/,
               0 /*variationfreeissuedcircinv*/, 0 /*variationcogcircinv*/, 0
               /*variationfreeseasoncircinv*/, 0 /*variationbeyondlifetimecirc*/, fp_systemuserid,
               sysdate /*timestamp*/, x.qtyrentedperpiece /*qtyrentedperpiece*/, x.qtyrentedother, 0
               /*variationrentedother*/, x.qtycustomerrentstop, 0 /*variationqtycustomerrentstop*/,
               x.qtyrentstop, 0 /*variationqtyrentstop*/, x.emblemtemplate_id, x.qtyrentemblem, 0
               /*variationqtyrentemblem*/, x.qtyreplacement, 0 /*variationqtyreplacement*/,
               x.qtyassigned, 0 /*variationqtyassigned*/, 0 /*qtyrenteddepositstock*/, 0
               /*variationrenteddepositstock*/, x.qtysubstitute, 0 /*variationqtysubstitute*/,
               x.chargeafterdepreciation, (fp_sqyear * 100 + fp_sqweek) /*yearweek*/, 0
               /*qtyrentedperpiecepool*/, 0 /*variationrentedperpiecepool*/, null
               /*wearerinvoicecategory_id*/, 0 /*qtyfullyamortized*/, 0
               /*variationqtyfullyamortized*/, 0 /*qtyrentedreturnrent*/, 0
               /*variationqtyrentedreturnrent*/, 0 /*qtyrentedminrent*/, 0 /*variationqtyrentedminrent*/
        from   (select a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                        a.product_id, a.sizedefinition_id, a.finishingmethod_id,
                        sum(case
                              when (fp_sqdate between wi.dateactive and wi.dateinactive and
                                (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                 wi.circinventory > 0 and a.qtyrentstop = 0) then
                                     wi.maxinventory
                             else
                                     0
                            end) maxinventory, sum(a.totalcircinv) totalcircinv,
                        sum(wi.changesperweek) changesperweek, sum(wi.maxfreeofcharge) maxfreeofcharge,
                        sum(a.freeissuedcircinv) freeissuedcircinv,
                        sum(case
                          when (a.qtycustomerrentstop = 0) then
                            a.freeseasoncircinv
                            else
                              0
                              end) freeseasoncircinv,
                        sum(a.qtycustomerrentstop) qtycustomerrentstop,
                        sum(case
                          when (a.qtycustomerrentstop = 0) then
                            a.qtyrentstop
                            else
                              0
                              end) qtyrentstop,
                        max(a.emblemtemplate_id) emblemtemplate_id,
                        sum(case
                          when (a.qtycustomerrentstop = 0) then
                            a.qtyreplacement
                            else
                              0
                              end) qtyreplacement,
                        sum(a.qtyassigned) qtyassigned,
                        sum(case
                          when (a.qtycustomerrentstop = 0) then
                            a.qtysubstitute
                            else
                              0
                              end) qtysubstitute,
                        max(a.chargeafterdepreciation) chargeafterdepreciation,
                        sum((case
                              when ((a.billingmethod = 3 or
                                   (gv_underusemethodss = 4 and a.billingmethod = 2))  and (a.qtycustomerrentstop = 0)) then
                               (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                               a.freeseasoncircinv - a.qtysubstitute - a.qtyreplacement)
                              else
                               0
                            end)) qtyrentedperpiece,
                        sum((case a.billingmethod
                               when 3 then
                                0
                               else
                                (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                                a.freeseasoncircinv)
                             end)) qtyrentedother,
                        sum((case
                              when (a.emblemtemplate_id is null or a.qtycustomerrentstop >0) then
                               0
                              else
                               (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                               a.freeseasoncircinv)
                            end)) qtyrentemblem
                 from   (select t.customer_id, t.department_id, dp.distributionpoint_id,
                                 case fp_sqonwearerlevel
                                    when 1 then
                                     wi.weareremployment_id
                                    else
                                     null
                                  end weareremployment_id, wi.product_id, wi.sizedefinition_id,
                                 wi.finishingmethod_id, count(non.nonuniqueitem_id) totalcircinv,
                                 wi.wearerinventory_id,
                                 sum((case
                                       when non.freeitem = 'Y' then
                                        1
                                       else
                                        0
                                     end)) freeissuedcircinv,
                                 sum((case
                                       when (coalesce(l.seasonalrent, ls.seasonalrent, -1) in (0, 1) and
                                            non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                            wi.season_id is not null and not exists
                                             (select sw.season_id
                                              from   seasonweek sw
                                              where  sw.season_id = wi.season_id
                                              and    sw.weeknumber = fp_sqweek)) then
                                        1
                                       else
                                        0
                                     end)) freeseasoncircinv,
                                 sum((case
                                       when (non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            exists
                                             (select 1
                                              from   temporarygarmentrentstop trs
                                              where  trs.customer_id = t.customer_id
                                              and    ((trs.endyear <> 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek and fp_sqyear*100+fp_sqweek <= trs.endyear*100 + trs.endweek)
                                                     or (trs.endyear = 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek)))) then
                                        1
                                       else
                                        0
                                     end)) qtycustomerrentstop,
                                 sum((case
                                       when (non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1))) then
                                        1
                                       else
                                        0
                                     end)) qtyrentstop,
                                 max(coalesce(l.emblemtemplate_id, ls.emblemtemplate_id)) emblemtemplate_id,
                                 sum((case
                                       when fp_invoicereplacements <> 1 and
                                            non.flag_id = gv_flagreplacementid and
                                            non.flagstartdate <= fp_sqdate and
                                            non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) then
                                        1
                                       else
                                        0
                                     end)) qtyreplacement,
                                 sum((case
                                       when non.startrentdate > fp_sqdate then
                                        1
                                       else
                                        0
                                     end)) qtyassigned,
                                 sum((case
                                       when fp_invoicesubstitutes <> 1 and non.flag_id = gv_flagsubstituteid and
                                            non.flagstartdate <= fp_sqdate and
                                            non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) then
                                        1
                                       else
                                        0
                                     end)) qtysubstitute,
                                 max((case
                                       when coalesce(l.percentageafterdepreciation,
                                                     ls.percentageafterdepreciation) > 0 and
                                            coalesce(l.billingmethod, ls.billingmethod, -1) = 3 then
                                        'Y'
                                       else
                                        'N'
                                     end)) chargeafterdepreciation,
                                 coalesce(l.billingmethod, ls.billingmethod, -1) billingmethod
                          from   wearerinventory wi
                          left   outer join nonuniqueitem non
                          on     non.wearerinventory_id = wi.wearerinventory_id
                          join   weareremployment we
                          on     we.weareremployment_id = wi.weareremployment_id
                          join   wearer w
                          on     w.wearer_id = we.wearer_id
                          join   product p
                          on     p.product_id = wi.product_id
                          join   productgroup pg
                          on     pg.productgroup_id = p.productgroup_id
                          join   distributionpoint dp
                          on     dp.distributionpoint_id = we.distributionpoint_id
                          join   department t
                          on     t.department_id = dp.department_id
                          left   outer join productlistpercustomer l
                          on     (l.customer_id = t.customer_id and l.product_id = wi.product_id and
                                 l.sizedefinition_id = wi.sizedefinition_id and
                                 l.finishingmethod_id = wi.finishingmethod_id and
                                 fp_sqdate between l.dateactive and l.dateinactive)
                          left   outer join productlistpercustomer ls
                          on     (ls.customer_id = t.customer_id and ls.product_id = wi.product_id and
                                 ls.sizedefinition_id = gv_sizestarid and
                                 ls.finishingmethod_id = wi.finishingmethod_id and
                                 fp_sqdate between ls.dateactive and ls.dateinactive)
                          where  (coalesce(l.billingmethod, ls.billingmethod, -1) <> -1 or
                                 fp_inactiveplpc <> 2)
                          and    (select min(ca.processbusinessunit_id)
                                  from   customeractivities ca
                                  where  ca.customer_id = t.customer_id
                                  and    ca.activity_id = pg.activity_id
                                  and    (fp_checkinvoicebu = 0 or
                                        ca.invoicebusinessunit_id = fp_invoicebuid)) = fp_processbuid
                          group  by wi.wearerinventory_id, t.customer_id, t.department_id,
                                    dp.distributionpoint_id,
                                    case fp_sqonwearerlevel
                                      when 1 then
                                       wi.weareremployment_id
                                      else
                                       null
                                    end, wi.product_id, wi.sizedefinition_id, wi.finishingmethod_id,
                                    coalesce(l.billingmethod, ls.billingmethod, -1)) a
                 join   wearerinventory wi
                 on     wi.wearerinventory_id = a.wearerinventory_id
                 group  by a.customer_id, a.department_id, a.distributionpoint_id,
                           a.weareremployment_id, a.product_id, a.sizedefinition_id,
                           a.finishingmethod_id) x;
    end add_non_uniqueitem;

 procedure add_uniqueitem is
    begin
      --Add_uniqueitem
      gv_message := 'Add_uniqueitem';
      merge into sqitemincirculation sqi
      using (select a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                    a.product_id, a.sizedefinition_id, a.finishingmethod_id,
                    sum(a.maxinventory) maxinventory, sum(a.totalcircinv) totalcircinv,
                    sum(a.changesperweek) changesperweek, sum(a.maxfreeinv) maxfreeinv,
                    max(a.emblemtemplate_id) emblemtemplate_id, sum(a.qtyassigned) qtyassigned,
                    sum(a.cogcircinv) cogcircinv, sum(a.freeissuedcircinv) freeissuedcircinv,
                    sum(case
                      when (a.qtycustomerrentstop = 0) then
                        a.qtyrentstop
                        else
                          0
                          end) qtyrentstop,
                    sum(a.qtycustomerrentstop) qtycustomerrentstop,
                    sum(case
                      when (a.qtycustomerrentstop = 0) then
                        a.freeseasoncircinv
                        else
                          0
                          end) freeseasoncircinv,
                    sum(case
                      when (a.qtycustomerrentstop = 0) then
                        a.beyondlifetimecirc
                        else
                          0
                          end) beyondlifetimecirc,
                    sum(case
                          when (a.billingmethod = 3 or (gv_underusemethodss = 4 and a.billingmethod = 2)) then
                           (a.qtyrentedother)
                          else
                           case
                             when (a.totalcircinv - a.qtyassigned - a.cogcircinv - a.qtyrentedother -
                                  a.freeissuedcircinv - a.qtyrentstop - a.freeseasoncircinv -
                                  a.qtyfullyamortized) > 0 then
                              (a.totalcircinv - a.qtyassigned - a.cogcircinv - a.qtyrentedother -
                              a.freeissuedcircinv - a.qtyrentstop - a.freeseasoncircinv - a.qtyfullyamortized)
                             else
                              0
                           end
                        end) qtyrentedother,
                    sum(case
                     when (a.qtycustomerrentstop = 0) then
                       a.qtyreplacement
                       else
                         0
                         end) qtyreplacement,
                    sum(case
                     when (a.qtycustomerrentstop = 0) then
                       a.qtysubstitute
                       else
                         0
                         end) qtysubstitute,
                    max(a.chargeafterdepreciation) chargeafterdepreciation,
                    sum(case
                     when (a.qtycustomerrentstop = 0) then
                       a.qtyrentedperpiecepool
                       else
                         0
                         end) qtyrentedperpiecepool,
                    sum(case
                      when (a.qtycustomerrentstop = 0) then
                        a.qtyfullyamortized
                        else
                          0
                          end) qtyfullyamortized,
                    sum(a.qtyrenteddepositstock) qtyrenteddepositstock,
                    sum((case
                          when ((a.billingmethod = 3 or (gv_underusemethodss = 4 and a.billingmethod = 2)) and (a.qtycustomerrentstop = 0) and
                               (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv -
                               a.qtyrentstop - a.freeseasoncircinv - a.qtysubstitute -
                               a.qtyreplacement - a.beyondlifetimecirc - a.cogcircinv - a.qtyrenteddepositstock - a.qtyfullyamortized) > 0) then
                           (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                           a.freeseasoncircinv - a.qtysubstitute - a.qtyreplacement - a.beyondlifetimecirc - a.cogcircinv -
                           a.qtyrenteddepositstock - a.qtyfullyamortized)
                          else
                           0
                        end)) qtyrentedperpiece
             from   (select t.customer_id, t.department_id, dp.distributionpoint_id,
                             case fp_sqonwearerlevel
                                when 1 then
                                 wi.weareremployment_id
                                else
                                 null
                              end weareremployment_id, wi.product_id, wi.sizedefinition_id,
                             wi.finishingmethod_id, 0 maxinventory, count(u.uniqueitem_id) totalcircinv,
                             0 changesperweek, max(wi.maxfreeofcharge) maxfreeinv,
                             coalesce(l.billingmethod, ls.billingmethod, -1) billingmethod,
                             case
                               when ((max(coalesce(wi.emblemtemplate_id,l.emblemtemplate_id, ls.emblemtemplate_id)) is not null) or (fp_sqdate between max(wi.dateactive) and max(wi.dateinactive))) then
                                 CASE fp_sqonwearerlevel
                                   when 1 then
                                     case when max(wi.emblemtemplate_id) is null then
                                       null
                                       else
                                          max(wi.emblemtemplate_id)
                                       end
                                    else
                                       max(coalesce(wi.emblemtemplate_id,l.emblemtemplate_id, ls.emblemtemplate_id))
                                   end
                               else
                                 null end emblemtemplate_id,
                             sum((case
                                   when u.status_id = gv_statusassigned then
                                    1
                                   else
                                    0
                                 end)) qtyassigned,
                             sum((case
                                   when u.status_id = gv_statusincirculation and u.customerowned = 'Y' then
                                    1
                                   else
                                    0
                                 end)) cogcircinv,
                             sum((case
                                   when u.status_id = gv_statusincirculation and nvl(u.leaseweeks, 0) = 0 and
                                        nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                        un.freeextragarment = 'Y' and u.customerowned <> 'Y' then
                                    1
                                   else
                                    0
                                 end)) freeissuedcircinv,
                             sum((case
                                   when u.status_id = gv_statusincirculation and nvl(u.leaseweeks, 0) = 0 and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        fp_sqdate between wi.temporaryrentstopstartdate and
                                        wi.temporaryrentstopenddate then
                                    1
                                   else
                                    0
                                 end)) qtyrentstop,
                             sum((case
                                   when u.status_id = gv_statusincirculation and exists
                                    (select 1
                                         from   temporarygarmentrentstop trs
                                         where  trs.customer_id = t.customer_id
                                         and    ((trs.endyear <> 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek and fp_sqyear*100+fp_sqweek <= trs.endyear*100 + trs.endweek)
                                                or (trs.endyear = 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek))) then
                                    1
                                   else
                                    0
                                 end)) qtycustomerrentstop,
                             sum((case
                                   when u.status_id = gv_statusincirculation and
                                        (coalesce(l.seasonalrent, ls.seasonalrent, -1) in (0, 1) and
                    										coalesce(l.seasontype_id, ls.seasontype_id,0) > 0 and
                                        nvl(u.leaseweeks, 0) = 0 and not (u.customerowned = 'Y') and
                                        not (un.freeextragarment = 'Y' and
                                         nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate) and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        wi.season_id is not null and not exists
                                         (select sw.season_id
                                          from   seasonweek sw
                                          where  sw.season_id = wi.season_id
                                          and    sw.weeknumber = fp_sqweek)) then
                                    1
                                   else
                                    0
                                 end)) freeseasoncircinv,
                             sum((case
                                   when nvl(u.leaseweeks, 0) = 0 and u.status_id = gv_statusincirculation and
                                        uf.enddatefullrent < fp_sqdate and not exists (select 1
                                        from residualvaluehistory rvh
                                         where rvh.uniqueitem_link_id = u.uniqueitem_id
                                         and rvh.residualvalueamount = 0 and u.residualvalueamount = 0) and
                                        not (u.stay_id = gv_staydepositstockid) and
                                        not (un.freeextragarment = 'Y' and
                                         (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate)) and
                                        (fp_sqdate < nvl(wi.temporaryrentstopstartdate, fp_sqdate + 1) or
                                         fp_sqdate > nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        (nvl(wi.season_id, 0) = 0 or
                                         (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 and exists
                                          (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) and not (u.customerowned = 'Y') then
                                    1
                                   else
                                    0
                                 end)) beyondlifetimecirc,
                             sum((case
                                   when (u.status_id = gv_statusincirculation and u.leaseweeks is not null) then
                                    1
                                   else
                                    0
                                 end)) qtyrentedother,
                             sum((case
                                   when fp_invoicereplacements <> 1 and u.status_id = gv_statusincirculation and
                                        nvl(u.leaseweeks, 0) = 0 and not uf.enddatefullrent < fp_sqdate and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        (nvl(wi.season_id, 0) = 0 or
                                        (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 and exists
                                         (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) and exists
                                    (select 1
                                         from   uniqueitemflag ff
                                         where  ff.uniqueitem_id = u.uniqueitem_id
                                         and    ff.flag_id = gv_flagreplacementid
                                         and    ff.startdate <= fp_sqdate) then
                                    1
                                   else
                                    0
                                 end)) qtyreplacement,
                             sum((case
                                   when fp_invoicesubstitutes <> 1 and u.status_id = gv_statusincirculation and
                                        nvl(u.leaseweeks, 0) = 0 and not uf.enddatefullrent < fp_sqdate and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        (nvl(wi.season_id, 0) = 0 or
                                        (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 and exists
                                         (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) and not exists
                                    (select 1
                                         from   uniqueitemflag ff
                                         where  ff.uniqueitem_id = u.uniqueitem_id
                                         and    ff.flag_id = gv_flagreplacementid
                                         and    ff.startdate <= fp_sqdate) and exists
                                    (select 1
                                         from   uniqueitemflag ff
                                         where  ff.uniqueitem_id = u.uniqueitem_id
                                         and    ff.flag_id = gv_flagsubstituteid
                                         and    ff.startdate <= fp_sqdate) then
                                    1
                                   else
                                    0
                                 end)) qtysubstitute,
                             max((case
                                   when coalesce(l.percentageafterdepreciation, ls.percentageafterdepreciation,
                                                 0) > 0 and coalesce(l.billingmethod, ls.billingmethod, -1) = 3 then
                                    'Y'
                                   else
                                    'N'
                                 end)) chargeafterdepreciation,
                             sum((case
                                   when u.status_id = gv_statusincirculation and
                                        trunc(u.lastoutscandate) <
                                        trunc(fp_sqdate) -
                                        7 * coalesce(l.chargerentnoreturnpoolafterwks,
                                                     ls.chargerentnoreturnpoolafterwks) and
                                        coalesce(l.billingmethod, ls.billingmethod, -1) = 3 and
                                        coalesce(l.inventorybillingtype, ls.inventorybillingtype, -1) = 4 and
                                        coalesce(l.chargerentnotreturned, ls.chargerentnotreturned, -1) <> 0 and
                                        coalesce(l.chargerentnoreturnpoolafterwks,
                                                 ls.chargerentnoreturnpoolafterwks, -1) > 0 and
                                        coalesce(l.codeuniquely, ls.codeuniquely, 'N') = 'Y' and
                                        u.stay_id in (select st.stay_id
                                                      from   stay st
                                                      where  st.staytype = 1
                                                      and    st.staynr in (20, 27, 28)) then
                                    1
                                   else
                                    0
                                 end)) qtyrentedperpiecepool,
                             sum((case
                                   when c.chargeamortizeduniqueitems = 0 and u.residualvalueamount = 0 and
                                        u.status_id = gv_statusincirculation and nvl(u.leaseweeks, 0) = 0
                                        and exists (select 1 from residualvaluehistory rvh
                                         where rvh.uniqueitem_link_id = u.uniqueitem_id
                                         and rvh.residualvalueamount = 0) and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1))
                                        and
                                        (nvl(wi.season_id, 0) = 0 or
                                         (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 or exists
                                          (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) then
                                    1
                                   else
                                    0
                                 end)) qtyfullyamortized,
                             sum(case
                                   when
                                     u.stay_id = gv_staydepositstockid and
                                     u.status_id = gv_statusincirculation and
                                     u.BUSINESSUNIT_ID = fp_processbuid and
                                     nvl(u.leaseweeks, 0) = 0 and
                                     NOT (un.freeextragarment = 'Y' AND
                                       (un.enddatefreeextra > fp_sqdate OR
                                        nvl(un.enddatefreeextra, to_date('01/01/0001','dd/mm/yyyy')) =
                                           to_date('01/01/0001','dd/mm/yyyy'))) and
                                     NOT (u.customerowned = 'Y') and
                                    ((fp_sqdate < wi.temporaryrentstopstartdate OR
                                        fp_sqdate > temporaryrentstopenddate) OR
                                        (nvl(wi.temporaryrentstopstartdate,
                                        to_date('01/01/0001', 'dd/mm/yyyy')) = to_date('01/01/0001','dd/mm/yyyy') AND
                                        nvl(wi.temporaryrentstopenddate, to_date('01/01/0001','dd/mm/yyyy')) =
                                         to_date('01/01/0001', 'dd/mm/yyyy'))) and
                                    NOT EXISTS (SELECT r.uniqueitem_id
                                       FROM uniqueitemflag r
                                         WHERE r.uniqueitem_id = u.uniqueitem_id
                                            AND r.flag_id = gv_flagreplacementid
                                            AND r.startdate <= fp_sqdate) and
                                    NOT EXISTS (SELECT r.uniqueitem_id
                                       FROM uniqueitemflag r
                                         WHERE r.uniqueitem_id = u.uniqueitem_id
                                           AND r.flag_id = gv_flagSubstituteID
                                           AND r.startdate <= fp_sqdate)
                                    then
                                    1
                                   else 0
                                 end) qtyrenteddepositstock,
								 un.wearerinventory_id,
                             coalesce(l.productlistpercustomer_id, ls.productlistpercustomer_id, -1) plpc_id
                      from   uniqueitem u
                      join   uniqueitemnonpool un
                      on     un.uniqueitem_id = u.uniqueitem_id
                      left   outer join uniqueitemfixedinfo uf
                      on     uf.uniqueitem_id = u.uniqueitem_id
                      join   weareremployment we
                      on     we.weareremployment_id = un.weareremployment_id
                      join   wearerinventory wi
                      on     wi.wearerinventory_id = un.wearerinventory_id
                      join   distributionpoint dp
                      on     dp.distributionpoint_id = we.distributionpoint_id
                      join   department t
                      on     t.department_id = dp.department_id
                      join   customer c
                      on     c.customer_id = t.customer_id
                      join   product p
                      on     p.product_id = wi.product_id
                      join   productgroup pg
                      on     pg.productgroup_id = p.productgroup_id
                      left   outer join productlistpercustomer l
                      on     (l.customer_id = t.customer_id and l.product_id = wi.product_id and
                             l.sizedefinition_id = wi.sizedefinition_id and
                             l.finishingmethod_id = wi.finishingmethod_id and
                             fp_sqdate between l.dateactive and l.dateinactive)
                      left   outer join productlistpercustomer ls
                      on     (ls.customer_id = t.customer_id and ls.product_id = wi.product_id and
                             ls.sizedefinition_id = gv_sizestarid and
                             ls.finishingmethod_id = wi.finishingmethod_id and
                             fp_sqdate between ls.dateactive and ls.dateinactive)
                      where  (coalesce(l.billingmethod, ls.billingmethod, -1) <> -1 or
                             fp_inactiveplpc <> 2)
                      and    u.businessunit_id = fp_processbuid
                      and    exists
                       (select 1
                              from   customeractivities ca
                              where  ca.customer_id = t.customer_id
                              and    ca.processbusinessunit_id = fp_processbuid
                              and    ca.activity_id = pg.activity_id
                              and    (fp_checkinvoicebu = 0 or ca.invoicebusinessunit_id = fp_invoicebuid))
                      group  by t.customer_id, t.department_id, dp.distributionpoint_id,
                                case fp_sqonwearerlevel
                                  when 1 then
                                   wi.weareremployment_id
                                  else
                                   null
                                end, un.wearerinventory_id, wi.product_id, wi.sizedefinition_id,
                                wi.finishingmethod_id, coalesce(l.billingmethod, ls.billingmethod, -1),
                                coalesce(l.productlistpercustomer_id, ls.productlistpercustomer_id, -1)) a
             group  by a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                       a.product_id, a.sizedefinition_id, a.finishingmethod_id) x
      on (sqi.statusquoheader_id = gv_sqheaderid and sqi.distributionpoint_link_id = x.distributionpoint_id and (sqi.weareremployment_link_id = x.weareremployment_id or (sqi.weareremployment_link_id is null and x.weareremployment_id is null)) and sqi.product_link_id = x.product_id and sqi.sizedefinition_link_id = x.sizedefinition_id and sqi.finishingmethod_id = x.finishingmethod_id)
      when matched then
        update
        set    sqi.maxinv = sqi.maxinv + x.maxinventory,
               sqi.totalcircinv = sqi.totalcircinv + x.totalcircinv,
               sqi.changesperweek = sqi.changesperweek + x.changesperweek,
               sqi.maxfreeinv = sqi.maxfreeinv + x.maxfreeinv,
               sqi.freeissuedcircinv = sqi.freeissuedcircinv + x.freeissuedcircinv,
               sqi.cogcircinv = sqi.cogcircinv + x.cogcircinv,
               sqi.freeseasoncircinv = sqi.freeseasoncircinv + x.freeseasoncircinv,
               sqi.beyondlifetimecirc = sqi.beyondlifetimecirc + x.beyondlifetimecirc,
               sqi.qtyrentedperpiecepool = sqi.qtyrentedperpiecepool + x.qtyrentedperpiecepool,
               sqi.qtyassigned = sqi.qtyassigned + x.qtyassigned,
               sqi.qtyrentedperpiece = sqi.qtyrentedperpiece + x.qtyrentedperpiece,
               sqi.qtyrentedother = sqi.qtyrentedother + x.qtyrentedother,
               sqi.qtysubstitute = sqi.qtysubstitute + x.qtysubstitute,
               sqi.qtyrentemblem = sqi.qtyrentemblem + case
                                      when (x.emblemtemplate_id is null or x.qtycustomerrentstop > 0) then
                                       0
                                       when (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv - x.beyondlifetimecirc - x.cogcircinv)<0 then
                                       0
                                      else
                                       (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv - x.beyondlifetimecirc - x.cogcircinv)
                                    end,
               sqi.qtyreplacement = sqi.qtyreplacement + x.qtyreplacement,
               sqi.qtycustomerrentstop = sqi.qtycustomerrentstop + x.qtycustomerrentstop,
               sqi.qtyrentstop = sqi.qtyrentstop + x.qtyrentstop,
               sqi.qtyfullyamortized = sqi.qtyfullyamortized + x.qtyfullyamortized,
               sqi.qtyrenteddepositstock = sqi.qtyrenteddepositstock + x.qtyrenteddepositstock,
               sqi.emblemtemplate_id = x.emblemtemplate_id,
               sqi.systemuser_id = fp_systemuserid, sqi.timestamp = sysdate
      when not matched then
        insert
          (sqitemincirculation_id, statusquoheader_id, customer_link_id, department_link_id,
           distributionpoint_link_id, weareremployment_link_id, product_link_id, sizedefinition_link_id,
           finishingmethod_id, maxinv, totalcircinv, changesperweek, maxfreeinv, freeissuedcircinv,
           cogcircinv, freeseasoncircinv, beyondlifetimecirc, variationmaxinv, variationtotalcircinv,
           variationchangesperweek, variationmaxfreeinv, variationrentedperpiece,
           variationfreeissuedcircinv, variationcogcircinv, variationfreeseasoncircinv,
           variationbeyondlifetimecirc, systemuser_id, timestamp, qtyrentedperpiece, qtyrentedother,
           variationrentedother, qtycustomerrentstop, variationqtycustomerrentstop, qtyrentstop,
           variationqtyrentstop, emblemtemplate_id, qtyrentemblem, variationqtyrentemblem,
           qtyreplacement, variationqtyreplacement, qtyassigned, variationqtyassigned,
           qtyrenteddepositstock, variationrenteddepositstock, qtysubstitute, variationqtysubstitute,
           chargeafterdepreciation, yearweek, qtyrentedperpiecepool, variationrentedperpiecepool,
           wearerinvoicecategory_id, qtyfullyamortized, variationqtyfullyamortized, qtyrentedreturnrent,
           variationqtyrentedreturnrent, qtyrentedminrent, variationqtyrentedminrent)
        values
          (seq_sqitemincirculation.nextval, gv_sqheaderid, x.customer_id, x.department_id,
           x.distributionpoint_id, x.weareremployment_id, x.product_id, x.sizedefinition_id,
           x.finishingmethod_id, x.maxinventory, x.totalcircinv, x.changesperweek, x.maxfreeinv,
           x.freeissuedcircinv, x.cogcircinv, x.freeseasoncircinv, x.beyondlifetimecirc, 0
           /*variationmaxinv*/, 0 /*variationtotalcircinv*/, 0 /*variationchangesperweek*/, 0
           /*variationmaxfreeinv*/, 0 /*variationrentedperpiece*/, 0 /*variationfreeissuedcircinv*/, 0
           /*variationcogcircinv*/, 0 /*variationfreeseasoncircinv*/, 0 /*variationbeyondlifetimecirc*/,
           fp_systemuserid, sysdate /*timestamp*/, x.qtyrentedperpiece, x.qtyrentedother, 0
           /*variationrentedother*/, x.qtycustomerrentstop, 0 /*variationqtycustomerrentstop*/,
           x.qtyrentstop, 0 /*variationqtyrentstop*/, x.emblemtemplate_id,
           case
              when (x.emblemtemplate_id is null or x.qtycustomerrentstop > 0) then
               0
              when (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv - x.beyondlifetimecirc - x.cogcircinv)<0 then
               0
              else
               (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv - x.beyondlifetimecirc - x.cogcircinv)
            end /*qtyrentemblem*/, 0 /*variationqtyrentemblem*/, x.qtyreplacement, 0
           /*variationqtyreplacement*/, x.qtyassigned, 0 /*variationqtyassigned*/, 0
           /*qtyrenteddepositstock*/, 0 /*variationrenteddepositstock*/, x.qtysubstitute, 0
           /*variationqtysubstitute*/, nvl(x.chargeafterdepreciation, 'N'),
           (fp_sqyear * 100 + fp_sqweek)
           /*yearweek*/, x.qtyrentedperpiecepool, 0 /*variationrentedperpiecepool*/, null
           /*wearerinvoicecategory_id*/, x.qtyfullyamortized, 0 /*variationqtyfullyamortized*/, 0
           /*qtyrentedreturnrent*/, 0 /*variationqtyrentedreturnrent*/, 0 /*qtyrentedminrent*/, 0
           /*variationqtyrentedminrent*/);
    end add_uniqueitem;

    procedure add_uniquepoolitem is
    begin
      --add_uniquepoolitem
      gv_message := 'add_uniquepoolitem';
      merge into sqitemincirculation sqi
      using (select a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                    a.product_id, a.sizedefinition_id, a.finishingmethod_id,
                    sum(a.maxinventory) maxinventory, sum(a.totalcircinv) totalcircinv,
                    sum(a.changesperweek) changesperweek, sum(a.maxfreeinv) maxfreeinv,
                    max(a.emblemtemplate_id) emblemtemplate_id, sum(a.qtyassigned) qtyassigned,
                    sum(a.cogcircinv) cogcircinv, sum(a.freeissuedcircinv) freeissuedcircinv,
                    sum(case
                     when (a.qtycustomerrentstop = 0) then
                       a.qtyrentstop
                       else
                         0
                         end) qtyrentstop,
                    sum(a.qtycustomerrentstop) qtycustomerrentstop,
                    sum(a.freeseasoncircinv) freeseasoncircinv,
                    sum(a.beyondlifetimecirc) beyondlifetimecirc, sum(a.qtyrentedother) qtyrentedother,
                    sum(a.qtyreplacement) qtyreplacement, sum(a.qtysubstitute) qtysubstitute,
                    max(a.chargeafterdepreciation) chargeafterdepreciation,
                    sum(case
                     when (a.qtycustomerrentstop = 0) then
                       a.qtyrentedperpiecepool
                       else
                         0
                         end) qtyrentedperpiecepool,
                    sum(a.qtyfullyamortized) qtyfullyamortized
             from   (select t.customer_id, t.department_id, dp.distributionpoint_id,
                             null weareremployment_id, u.product_id, u.sizedefinition_id,
                             u.finishingmethod_id, 0 maxinventory, 0 totalcircinv, 0 changesperweek,
                             0 maxfreeinv, coalesce(l.billingmethod, ls.billingmethod, -1) billingmethod,
                             max(coalesce(l.emblemtemplate_id, ls.emblemtemplate_id)) emblemtemplate_id,
                             0 qtyassigned, 0 cogcircinv, 0 freeissuedcircinv,
                             sum(coalesce((select 1
                                           from   standarddeliveryline y
                                           join   productlistperdistribpoint plpdp
                                           on     plpdp.productlistperdistribpoint_id =
                                                  y.productlistperdistribpoint_id
                                           where  plpdp.distributionpoint_id = u.distributionpoint_id
                                           and    plpdp.product_id = u.product_id
                                           and    plpdp.sizedefinition_id = u.sizedefinition_id
                                           and    plpdp.finishingmethod_id = u.finishingmethod_id
                                           and    exists
                                            (select tds.standarddeliveryline_id
                                                   from   temporarydeliverystop tds
                                                   where  tds.standarddeliveryline_id =
                                                          y.standarddeliveryline_id
                                                   and    ((tds.tempstoprentforweek = 'Y' and
                                                         (fp_sqweek between tds.temporarystopstartweek and
                                                         tds.temporarystopendweek) or
                                                         (tds.temporarystopstartweek >
                                                         tds.temporarystopendweek and
                                                         ((fp_sqweek <= tds.temporarystopendweek and
                                                         0 < fp_sqweek) or
                                                         (temporarystopstartweek <= fp_sqweek and
                                                         fp_sqweek <= 53)))) or
                                                         (tds.tempstoprentforyearweek = 'Y' and
                                                         f_isinyearweeklifespan(tds.temporarystopstartyear,
                                                                                   tds.tempstopstartweekforyear,
                                                                                   fp_sqyear, fp_sqweek,
                                                                                   tds.temporarystopendyear,
                                                                                   tds.tempstopendweekforyear) = 1) or
                                                         (tds.tempstoprentfordate = 'Y' and
                                                         (tds.startdate <= sysdate and
                                                         sysdate <= tds.enddate))))), 0)) qtyrentstop,
                             sum((case
                                   when u.status_id = gv_statusincirculation and exists
                                    (select 1
                                         from   temporarygarmentrentstop trs
                                         where  trs.customer_id = t.customer_id
                                         and    ((trs.endyear <> 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek and fp_sqyear*100+fp_sqweek <= trs.endyear*100 + trs.endweek)
                                                or (trs.endyear = 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek))) then
                                    1
                                   else
                                    0
                                 end)) qtycustomerrentstop, 0 freeseasoncircinv, 0 beyondlifetimecirc,
                             0 qtyrentedother, 0 qtyreplacement, 0 qtysubstitute,
                             'N' chargeafterdepreciation, count(u.uniqueitem_id) qtyrentedperpiecepool,
                             0 qtyfullyamortized
                      from   uniqueitem u
                      join   uniqueitemfixedinfo uf
                      on     uf.uniqueitem_id = u.uniqueitem_id
                      join   product p
                      on     p.product_id = u.product_id
                      join   productgroup pg
                      on     pg.productgroup_id = p.productgroup_id
                      join   distributionpoint dp
                      on     dp.distributionpoint_id = u.distributionpoint_id
                      join   department t
                      on     t.department_id = dp.department_id
                      join   customer c
                      on     c.customer_id = t.customer_id
                      left   outer join productlistpercustomer l
                      on     (l.customer_id = t.customer_id and l.product_id = u.product_id and
                             l.sizedefinition_id = u.sizedefinition_id and
                             l.finishingmethod_id = u.finishingmethod_id and
                             fp_sqdate between l.dateactive and l.dateinactive)
                      left   outer join productlistpercustomer ls
                      on     (ls.customer_id = t.customer_id and ls.product_id = u.product_id and
                             ls.sizedefinition_id = gv_sizestarid and
                             ls.finishingmethod_id = u.finishingmethod_id and
                             fp_sqdate between ls.dateactive and ls.dateinactive)
                      where  u.status_id in (gv_statusincirculation, gv_statusassigned)
                      and    u.poolitem <> 0 --not on stock
                      and    u.finishingmethod_id is not null --must exist for sqitems
                      and    coalesce(l.chargerentnoreturnpoolafterwks, ls.chargerentnoreturnpoolafterwks,
                                      0) > 0
                      and    trunc(u.lastoutscandate) <
                             trunc(sysdate) -
                             7 * coalesce(l.chargerentnoreturnpoolafterwks,
                                           ls.chargerentnoreturnpoolafterwks, 0)
                      and    (coalesce(l.billingmethod, ls.billingmethod, -1) <> -1 or
                            fp_inactiveplpc <> 2)
                      and    u.businessunit_id = fp_processbuid
                      and    exists
                       (select 1
                              from   customeractivities ca
                              where  ca.customer_id = t.customer_id
                              and    ca.processbusinessunit_id = fp_processbuid
                              and    ca.activity_id = pg.activity_id
                              and    (fp_checkinvoicebu = 0 or ca.invoicebusinessunit_id = fp_invoicebuid))
                      and    not exists (select 1
                              from   uniqueitemloss uil
                              where  uil.uniqueitem_link_id = u.uniqueitem_id
                              and    (uil.lossstatus = 0 or uil.lossstatus = 1)
                              and    u.lastoutscandate = uil.outscandate)
                      group  by t.customer_id, t.department_id, dp.distributionpoint_id, u.product_id,
                                u.sizedefinition_id, u.finishingmethod_id,
                                coalesce(l.billingmethod, ls.billingmethod, -1)) a
             group  by a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                       a.product_id, a.sizedefinition_id, a.finishingmethod_id) x
      on (sqi.statusquoheader_id = gv_sqheaderid and sqi.distributionpoint_link_id = x.distributionpoint_id and (sqi.weareremployment_link_id = x.weareremployment_id or (sqi.weareremployment_link_id is null and x.weareremployment_id is null)) and sqi.product_link_id = x.product_id and sqi.sizedefinition_link_id = x.sizedefinition_id and sqi.finishingmethod_id = x.finishingmethod_id)
      when matched then
        update
        set    sqi.qtycustomerrentstop = sqi.qtycustomerrentstop + x.qtycustomerrentstop,
               sqi.qtyrentedperpiecepool = sqi.qtyrentedperpiecepool + x.qtyrentedperpiecepool  -
                                           x.qtyrentstop,
               sqi.qtyrentstop = sqi.qtyrentstop + x.qtyrentstop,
               sqi.emblemtemplate_id = nvl(sqi.emblemtemplate_id, x.emblemtemplate_id),
               sqi.qtyrentemblem = sqi.qtyrentemblem + case
                                      when (x.emblemtemplate_id is null or x.qtycustomerrentstop > 0) then
                                       0
                                      else
                                       (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
                                    end,
               sqi.systemuser_id = fp_systemuserid, sqi.timestamp = sysdate
      when not matched then
        insert
          (sqitemincirculation_id, statusquoheader_id, customer_link_id, department_link_id,
           distributionpoint_link_id, weareremployment_link_id, product_link_id, sizedefinition_link_id,
           finishingmethod_id, maxinv, totalcircinv, changesperweek, maxfreeinv, freeissuedcircinv,
           cogcircinv, freeseasoncircinv, beyondlifetimecirc, variationmaxinv, variationtotalcircinv,
           variationchangesperweek, variationmaxfreeinv, variationrentedperpiece,
           variationfreeissuedcircinv, variationcogcircinv, variationfreeseasoncircinv,
           variationbeyondlifetimecirc, systemuser_id, timestamp, qtyrentedperpiece, qtyrentedother,
           variationrentedother, qtycustomerrentstop, variationqtycustomerrentstop, qtyrentstop,
           variationqtyrentstop, emblemtemplate_id, qtyrentemblem, variationqtyrentemblem,
           qtyreplacement, variationqtyreplacement, qtyassigned, variationqtyassigned,
           qtyrenteddepositstock, variationrenteddepositstock, qtysubstitute, variationqtysubstitute,
           chargeafterdepreciation, yearweek, qtyrentedperpiecepool, variationrentedperpiecepool,
           wearerinvoicecategory_id, qtyfullyamortized, variationqtyfullyamortized, qtyrentedreturnrent,
           variationqtyrentedreturnrent, qtyrentedminrent, variationqtyrentedminrent)
        values
          (seq_sqitemincirculation.nextval, gv_sqheaderid, x.customer_id, x.department_id,
           x.distributionpoint_id, x.weareremployment_id, x.product_id, x.sizedefinition_id,
           x.finishingmethod_id, x.maxinventory, x.totalcircinv, x.changesperweek, x.maxfreeinv,
           x.freeissuedcircinv, x.cogcircinv, x.freeseasoncircinv, x.beyondlifetimecirc, 0
           /*variationmaxinv*/, 0 /*variationtotalcircinv*/, 0 /*variationchangesperweek*/, 0
           /*variationmaxfreeinv*/, 0 /*variationrentedperpiece*/, 0 /*variationfreeissuedcircinv*/, 0
           /*variationcogcircinv*/, 0 /*variationfreeseasoncircinv*/, 0 /*variationbeyondlifetimecirc*/,
           fp_systemuserid, sysdate /*timestamp*/,
           case
             when x.qtycustomerrentstop = 0 then
                  (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
             else
               0
           end /*qtyrentedperpiece*/, x.qtyrentedother, 0 /*variationrentedother*/, x.qtycustomerrentstop, 0
           /*variationqtycustomerrentstop*/, x.qtyrentstop, 0 /*variationqtyrentstop*/,
           x.emblemtemplate_id,
           case
              when (x.emblemtemplate_id is null or x.qtycustomerrentstop > 0) then
               0
              else
               (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
            end /*qtyrentemblem*/, 0 /*variationqtyrentemblem*/, x.qtyreplacement, 0
           /*variationqtyreplacement*/, x.qtyassigned, 0 /*variationqtyassigned*/, 0
           /*qtyrenteddepositstock*/, 0 /*variationrenteddepositstock*/, x.qtysubstitute, 0
           /*variationqtysubstitute*/, nvl(x.chargeafterdepreciation, 'N'),
           (fp_sqyear * 100 + fp_sqweek)
           /*yearweek*/, x.qtyrentedperpiecepool, 0 /*variationrentedperpiecepool*/, null
           /*wearerinvoicecategory_id*/, x.qtyfullyamortized, 0 /*variationqtyfullyamortized*/, 0
           /*qtyrentedreturnrent*/, 0 /*variationqtyrentedreturnrent*/, 0 /*qtyrentedminrent*/, 0
           /*variationqtyrentedminrent*/);
    end add_uniquepoolitem;

    procedure add_uniqueitemreturnrent is
    begin
      --createSQItemInCirc based on Unique Item Return Rent
      if (fp_userentbasedonreturnweeks = 1 and fp_settlementactive = 0) then
        begin
          --add_uniqueitemreturnrent
          gv_message := 'add_uniqueitemreturnrent';
          merge into sqitemincirculation sqi
          using (select sum((case
                              when uirr.returnrenttype = 1 then
                               1
                              else
                               0
                            end)) variationqtyrentedminrent,
                        sum((case
                              when uirr.returnrenttype = 2 then
                               1
                              else
                               0
                            end)) qtyrentedminrent, uirr.customer_link_id, dp.department_id,
                        we.distributionpoint_id,
                        case fp_sqonwearerlevel
                           when 1 then
                            uirr.weareremployment_link_id
                           else
                            null
                         end weareremployment_id, uirr.product_link_id, uirr.sizedefinition_link_id,
                        uirr.finishingmethod_id,
                        sum((case
                              when exists (select 1
                                    from   temporarygarmentrentstop trs
                                    where  trs.customer_id = d.customer_id
                                    and    ((trs.endyear <> 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek and fp_sqyear*100+fp_sqweek <= trs.endyear*100 + trs.endweek)
                                           or (trs.endyear = 0 and trs.startyear * 100 + trs.startweek <= fp_sqyear*100+fp_sqweek))) then
                               1
                              else
                               0
                            end)) qtycustomerrentstop
                 from   uniqueitemreturnrent uirr
                 join   weareremployment we
                 on     we.weareremployment_id = uirr.weareremployment_link_id
                 join   distributionpoint dp
                 on     dp.distributionpoint_id = we.distributionpoint_id
                 join   department d
                 on     d.department_id = dp.department_id
                 where  uirr.returnrenttype in (1, 2)
                 and    uirr.rentyear = fp_sqyear
                 and    uirr.rentweek = fp_sqweek
                 and    exists (select productlistpercustomer_id
                         from   productlistpercustomer plpc
                         where  plpc.customer_id = uirr.customer_link_id
                         and    plpc.product_id = uirr.product_link_id
                         and    (plpc.sizedefinition_id = uirr.sizedefinition_link_id or
                               plpc.sizedefinition_id = gv_sizestarid)
                         and    plpc.finishingmethod_id = uirr.finishingmethod_id
                         and    fp_sqdate between plpc.dateactive and plpc.dateinactive
                         and    plpc.billingmethod = 3
                         and    plpc.inventorybillingtype in (1, 2))
                 and    exists (select sqitemincirculation_id
                         from   sqitemincirculation sqi
                         where  sqi.statusquoheader_id = gv_sqheaderid
                         and    sqi.customer_link_id = uirr.customer_link_id
                         and    sqi.product_link_id = uirr.product_link_id
                         and    sqi.totalcircinv > 0)
                 group  by uirr.customer_link_id, dp.department_id, we.distributionpoint_id,
                           case fp_sqonwearerlevel
                             when 1 then
                              uirr.weareremployment_link_id
                             else
                              null
                           end, uirr.product_link_id, uirr.sizedefinition_link_id, uirr.finishingmethod_id) x
          on (sqi.statusquoheader_id = gv_sqheaderid and sqi.distributionpoint_link_id = x.distributionpoint_id and (sqi.weareremployment_link_id = x.weareremployment_id or (sqi.weareremployment_link_id is null and x.weareremployment_id is null)) and sqi.product_link_id = x.product_link_id and sqi.sizedefinition_link_id = x.sizedefinition_link_id and sqi.finishingmethod_id = x.finishingmethod_id)
          when matched then
            update
            set    sqi.variationqtyrentedminrent = sqi.variationqtyrentedminrent + case
                                                      when qtycustomerrentstop = 0 then
                                                       x.variationqtyrentedminrent
                                                      else
                                                       0
                                                    end,
                   sqi.qtyrentedminrent = sqi.qtyrentedminrent + case
                                             when qtycustomerrentstop = 0 then
                                              x.qtyrentedminrent
                                             else
                                              0
                                           end, sqi.systemuser_id = fp_systemuserid, sqi.timestamp = sysdate;
        end;
      end if;
    end add_uniqueitemreturnrent;

    procedure finalize is
      lv_totalquantity number;
    begin
      --finalize
      gv_message := 'finalize, update statusquoheader';
      update statusquoheader sqh
      set    sqh.totalquantity = nvl((select sum(sqi.totalcircinv)
                                      from   sqitemincirculation sqi
                                      where  sqi.statusquoheader_id = sqh.statusquoheader_id), 0)
      where  statusquoheader_id = gv_sqheaderid
      returning totalquantity into lv_totalquantity;
      commit;
      --return variable
      fp_sqheaderid := gv_sqheaderid;
      --write log
      write_log('Ready SQIemincirculation ' || lv_totalquantity ||
                ' totalcircinv, for statusquoheader_id ' || fp_sqheaderid, 1);
    end finalize;

    procedure update_plpc is
    begin
      --update_plpc
      gv_message := 'update_plpc';
      update productlistpercustomer l
      set    l.totalincirculation =
              (select sum(sqi.totalcircinv)
               from   statusquoheader sqh
               join   sqitemincirculation sqi
               on     sqi.statusquoheader_id = sqh.statusquoheader_id
               where  sqh.statusquoheader_id = gv_sqheaderid
               and    sqi.customer_link_id = l.customer_id
               and    sqi.product_link_id = l.product_id
               and    (sqi.sizedefinition_link_id = l.sizedefinition_id or
                     l.sizedefinition_id = gv_sizestarid)
               and    l.finishingmethod_id = sqi.finishingmethod_id
               and    sqh.statusquodate between l.dateactive and l.dateinactive),
             l.totalincirculationcharged =
              (select sum(sqi.qtyrentedperpiece) + sum(sqi.qtyrentedother) +
                       sum(sqi.qtyrenteddepositstock) + sum(case sqi.chargeafterdepreciation
                                                              when 'Y' then
                                                               sqi.beyondlifetimecirc
                                                              else
                                                               0
                                                            end) totalincirculationcharged
               from   statusquoheader sqh
               join   sqitemincirculation sqi
               on     sqi.statusquoheader_id = sqh.statusquoheader_id
               where  sqh.statusquoheader_id = gv_sqheaderid
               and    sqi.customer_link_id = l.customer_id
               and    sqi.product_link_id = l.product_id
               and    (sqi.sizedefinition_link_id = l.sizedefinition_id or
                     l.sizedefinition_id = gv_sizestarid)
               and    l.finishingmethod_id = sqi.finishingmethod_id
               and    sqh.statusquodate between l.dateactive and l.dateinactive)
      where  exists (select 1
              from   statusquoheader sqh
              join   sqitemincirculation sqi
              on     sqi.statusquoheader_id = sqh.statusquoheader_id
              where  sqh.statusquoheader_id = gv_sqheaderid
              and    sqi.customer_link_id = l.customer_id
              and    sqi.product_link_id = l.product_id
              and    (sqi.sizedefinition_link_id = l.sizedefinition_id or
                    l.sizedefinition_id = gv_sizestarid)
              and    l.finishingmethod_id = sqi.finishingmethod_id
              and    sqh.statusquodate between l.dateactive and l.dateinactive);
      --commit
      commit;
    end update_plpc;
  begin
    --Main program part createsqitemsincirculation
    --initialize
    initialize;
    --Create SQ Header
    create_sq_header;
    --Add_NON_uniqueitem
    add_non_uniqueitem;
    --Add_uniqueitem
    add_uniqueitem;
    --Add_uniquepoolitem
    add_uniquepoolitem;
    --add_uniqueitemreturnrent
    add_uniqueitemreturnrent;
    --finalize
    finalize;
    --update_plpc
    update_plpc;
  exception
    when no_data_found then
      begin
        rollback;
        fp_sqheaderid := null;
        write_log('No data found ' || gv_message || ' ' || sqlerrm, 3);
      end;
    when others then
      begin
        rollback;
        fp_sqheaderid := null;
        write_log(gv_message || ' ' || sqlerrm, 3);
      end;
  end createsqitemsincirculation;

  procedure check_duplicate_plpc is
    gv_separator varchar2(1) := ';';
    gv_counter   number := 0;

    --interal procedures
    procedure write_log(fp_message in varchar2, fp_priority in number) is
    begin
      /* writes logs into database.
      priority
      1 = Message
      2 = Warning
      3 = Error
      4 = Stack trace
      5 = Debug info  */
      abslogwrite.abslog_write(5, 'Pack_SQItemInCirculation', null, fp_priority,
                               'check_duplicate_plpc ' || fp_message);
      begin
        dbms_output.put_line(fp_message);
      exception
        when others then
          null;
      end;
    end write_log;
  begin
    --check_duplicate_plpc
    for zz in (select l.productlistpercustomer_id, c.customernumber, p.code productcode,
                      s.code sizecode, f.code finishingmethod, l.dateactive, l.dateinactive
               from   productlistpercustomer l
               join   customer c
               on     c.customer_id = l.customer_id
               join   product p
               on     p.product_id = l.product_id
               join   sizedefinition s
               on     s.sizedefinition_id = l.sizedefinition_id
               join   finishingmethod f
               on     f.finishingmethod_id = l.finishingmethod_id
               where  exists (select 1
                       from   productlistpercustomer x
                       where  x.customer_id = l.customer_id
                       and    x.product_id = l.product_id
                       and    x.sizedefinition_id = l.sizedefinition_id
                       and    x.finishingmethod_id = l.finishingmethod_id
                       and    x.productlistpercustomer_id <> l.productlistpercustomer_id
                       and    (x.dateactive between l.dateactive and l.dateinactive or
                             x.dateinactive between l.dateactive and l.dateinactive))
               order  by c.customernumber, p.code, s.code, f.code, l.productlistpercustomer_id) loop
      begin
        --
        if gv_counter = 0 then
          begin
            --output Header
            write_log('Productlistpercustomer_id' || gv_separator || 'Customernumber' ||
                      gv_separator || 'Productcode' || gv_separator || 'Sizecode' || gv_separator ||
                      'Finishingmethod' || gv_separator || 'Dateactive' || gv_separator ||
                      'Dateinactive' || gv_separator, 3);
          end;
        end if;
        --output duplicate PLPC's
        write_log(zz.productlistpercustomer_id || gv_separator || zz.customernumber ||
                  gv_separator || zz.productcode || gv_separator || zz.sizecode || gv_separator ||
                  zz.finishingmethod || gv_separator || to_char(zz.dateactive, 'dd-mm-yyyy') ||
                  gv_separator || to_char(zz.dateinactive, 'dd-mm-yyyy') || gv_separator, 3);
        --count duplicates
        gv_counter := gv_counter + 1;
      end;
    end loop;
    if gv_counter > 0 then
      begin
        write_log('Error ' || gv_counter || ' duplicate PLPC line(s)!', 3);
      end;
    else
      begin
        write_log('All ok, no duplicate PLPC lines', 1);
      end;
    end if;
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 3);
      end;
  end check_duplicate_plpc;

end pack_sqitemsincirculation;
/
create or replace package pack_sqitemsincirculation_new is

  /****************************************************************************************************\
  * New version 08-dec-2017                                                                            *
  * Version 2.1e  Pack_SQItemsInCirculation                                                            *
  * Updated:                                                                                           *
  *   08-Dec-2017 totally new version ABS-55074 Rework PACKAGE pack_sqitemsincirculation from scratch  *
  *   12-Mar-2018 updates the PLPC fields totalincirculation totalincirculationcharged as well         *
  *   20-Mar-2018 take into account fp_inactiveplpc also inactive customers                            *
  \****************************************************************************************************/

  --Main procedure createsqitemsincirculation
  procedure createsqitemsincirculation(fp_sqheaderid                out nocopy statusquoheader.statusquoheader_id%type,
                                       fp_processbuid               in businessunit.businessunit_id%type,
                                       fp_invoicebuid               in businessunit.businessunit_id%type,
                                       fp_sqdate                    in date,
                                       fp_sqyear                    in int,
                                       fp_sqweek                    in int,
                                       fp_sqmonth                   in int,
                                       fp_sqsubtype                 in int,
                                       fp_systemuserid              in systemuser.systemuser_id%type,
                                       fp_checkinvoicebu            in int,
                                       fp_userentonstock            in int,
                                       fp_inactiveplpc              in int,
                                       fp_plantid                   in plant.plant_id%type,
                                       fp_invoicereplacements       in int,
                                       fp_invoicesubstitutes        in int,
                                       fp_sqonwearerlevel           in int,
                                       fp_userentbasedonreturnweeks in int,
                                       fp_settlementactive          in int,
                                       fp_chargereplacedproduct     in int,
                                       fp_abslogprocessjob          in int);

  --Check_Duplicate_PLPC make sure there are no duplicate PLPC's
  procedure check_duplicate_plpc;

end pack_sqitemsincirculation_new;

/
create or replace package body pack_sqitemsincirculation_new is
  --external procedure
  procedure createsqitemsincirculation(fp_sqheaderid                out nocopy statusquoheader.statusquoheader_id%type,
                                       fp_processbuid               in businessunit.businessunit_id%type,
                                       fp_invoicebuid               in businessunit.businessunit_id%type,
                                       fp_sqdate                    in date,
                                       fp_sqyear                    in int,
                                       fp_sqweek                    in int,
                                       fp_sqmonth                   in int,
                                       fp_sqsubtype                 in int,
                                       fp_systemuserid              in systemuser.systemuser_id%type,
                                       fp_checkinvoicebu            in int,
                                       fp_userentonstock            in int,
                                       fp_inactiveplpc              in int,
                                       fp_plantid                   in plant.plant_id%type,
                                       fp_invoicereplacements       in int,
                                       fp_invoicesubstitutes        in int,
                                       fp_sqonwearerlevel           in int,
                                       fp_userentbasedonreturnweeks in int,
                                       fp_settlementactive          in int,
                                       fp_chargereplacedproduct     in int,
                                       fp_abslogprocessjob          in int) is
    --global variables
    /*Parameter fp_inactiveplpc
     This setting is applicable both for SQ items in circulation and SQ mats in circulation.
       0 = All items are processed, also with inactive PLPC.
           When PLPC is inactive the billing method from the last (last dateinactive) PLPC is taken.
       1 = All items are processed, also with inactive PLPC.
       2 = Process only items with active PLPC.
    In case of mats in circulation option 0 and 1 are the same.
    */
    gv_message                  abslog.message%type;
    gv_sizestarid               sizedefinition.sizedefinition_id%type;
    gv_flagsubstituteid         flag.flag_id%type;
    gv_flagreplacementid        flag.flag_id%type;
    gv_statusidforuniqueinstock status.status_id%type;
    gv_statusincirculation      status.status_id%type;
    gv_statusassigned           status.status_id%type;
    gv_underusemethodss         systemsetting.value%type;
    gv_bm3maxinvreducedepositss systemsetting.value%type;
    gv_staydepositstockid       stay.stay_id%type;
    gv_sqheaderid               statusquoheader.statusquoheader_id%type;

    --interal procedures
    procedure write_log(fp_message in varchar2, fp_priority in number) is
    begin
      /* writes logs into database.
      priority
      1 = Message
      2 = Warning
      3 = Error
      4 = Stack trace
      5 = Debug info  */
      abslogwrite.abslog_write(5, 'Pack_SQItemInCirculation', null, fp_priority, fp_message,
                               fp_systemuserid);
      begin
        dbms_output.put_line(fp_message);
      exception
        when others then
          null;
      end;
    end write_log;

    procedure initialize is
    begin
      --initialize
      -- size *
      gv_message := 'get size *';
      select sizedefinition_id into gv_sizestarid from sizedefinition where code = '*';
      --automaticflag substitute
      gv_message := 'automaticflag substitute (12)';
      select af.flag_id
      into   gv_flagsubstituteid
      from   automaticflag af 
      where  af.automaticflag_id = 12;
      --automaticflag replacement
      gv_message := 'automaticflag replacement (4)';
      select af.flag_id
      into   gv_flagreplacementid
      from   automaticflag af
      where  af.automaticflag_id = 4;
      --status_id for UI Assigned
      gv_message := 'get status UI, 30';
      select st.status_id
      into   gv_statusassigned
      from   status st
      where  st.statustype = 'UI'
      and    st.code = '30';
      --status_id for UI In circulation
      gv_message := 'get status UI, 20';
      select st.status_id
      into   gv_statusincirculation
      from   status st
      where  st.statustype = 'UI'
      and    st.code = '20';
      --status_id for UI In stock (used for createSQItemInCircOnUniqueRent )
      gv_message := 'get status UI, 10';
      select st.status_id
      into   gv_statusidforuniqueinstock
      from   status st
      where  st.statustype = 'UI'
      and    st.code = '10';
      --gv_staydepositstockid
      select st.stay_id
      into   gv_staydepositstockid
      from   stay st
      where  st.staytype = 1
      and    st.staynr = 37;
      --system setting underuseMethodSS
      gv_message := 'UNDERUSEMETHOD for plant id ' || fp_plantid;
      select ss.value
      into   gv_underusemethodss
      from   systemsetting ss
      where  upper(ss.name) like upper('UNDERUSEMETHOD')
      and    ss.groupname = 'Billing'
      and    ss.plant_id = fp_plantid;
      --system setting bm3MaxInvReduceDepositSS
      gv_message := 'BM3MAXINVREDUCEDEPOSIT for plant id ' || fp_plantid;
      select ss.value
      into   gv_bm3maxinvreducedepositss
      from   systemsetting ss
      where  upper(ss.name) like upper('BM3MAXINVREDUCEDEPOSIT')
      and    ss.groupname = 'Billing'
      and    ss.plant_id = fp_plantid;
    end initialize;

    procedure create_sq_header is
    begin
      --cleanup old sq
      gv_message := 'cleanup old sq';
      delete statusquoheader sh
      where  sh.year = fp_sqyear
      and    sh.week = fp_sqweek
      and    sh.processbusinessunit_id = fp_processbuid
      and    sh.invoicebusinessunit_id = fp_invoicebuid
      and    sh.statusquotype = 1
      and    sh.totalquantity = 0;
      --create_sq_header
      gv_message := 'create_sq_header';
      insert into statusquoheader
        (statusquoheader_id, processbusinessunit_id, invoicebusinessunit_id, statusquodate,
         statusquotype, totalquantity, year, week, month, subtype, abslogprocessjob_id,
         systemuser_id, timestamp)
      values
        (seq_statusquoheader.nextval, fp_processbuid, fp_invoicebuid, fp_sqdate, 1, 0, fp_sqyear,
         fp_sqweek, fp_sqmonth, fp_sqsubtype, fp_abslogprocessjob, fp_systemuserid, sysdate)
      returning statusquoheader_id into gv_sqheaderid;
    end create_sq_header;

    procedure add_non_uniqueitem is
    begin
      --Add_NON_uniqueitem
      gv_message := 'Add_NON_uniqueitem';
      insert into sqitemincirculation
        (sqitemincirculation_id, statusquoheader_id, customer_link_id, department_link_id,
         distributionpoint_link_id, weareremployment_link_id, product_link_id,
         sizedefinition_link_id, finishingmethod_id, maxinv, totalcircinv, changesperweek,
         maxfreeinv, freeissuedcircinv, cogcircinv, freeseasoncircinv, beyondlifetimecirc,
         variationmaxinv, variationtotalcircinv, variationchangesperweek, variationmaxfreeinv,
         variationrentedperpiece, variationfreeissuedcircinv, variationcogcircinv,
         variationfreeseasoncircinv, variationbeyondlifetimecirc, systemuser_id, timestamp,
         qtyrentedperpiece, qtyrentedother, variationrentedother, qtycustomerrentstop,
         variationqtycustomerrentstop, qtyrentstop, variationqtyrentstop, emblemtemplate_id,
         qtyrentemblem, variationqtyrentemblem, qtyreplacement, variationqtyreplacement, qtyassigned,
         variationqtyassigned, qtyrenteddepositstock, variationrenteddepositstock, qtysubstitute,
         variationqtysubstitute, chargeafterdepreciation, yearweek, qtyrentedperpiecepool,
         variationrentedperpiecepool, wearerinvoicecategory_id, qtyfullyamortized,
         variationqtyfullyamortized, qtyrentedreturnrent, variationqtyrentedreturnrent,
         qtyrentedminrent, variationqtyrentedminrent)
        select seq_sqitemincirculation.nextval, gv_sqheaderid, x.customer_id, x.department_id,
               x.distributionpoint_id, x.weareremployment_id, x.product_id, x.sizedefinition_id,
               x.finishingmethod_id, x.maxinventory, x.totalcircinv, x.changesperweek,
               x.maxfreeofcharge, x.freeissuedcircinv, 0 /*cogcircinv*/, x.freeseasoncircinv, 0
               /*beyondlifetimecirc*/, 0 /*variationmaxinv*/, 0 /*variationtotalcircinv*/, 0
               /*variationchangesperweek*/, 0 /*variationmaxfreeinv*/, 0 /*variationrentedperpiece*/,
               0 /*variationfreeissuedcircinv*/, 0 /*variationcogcircinv*/, 0
               /*variationfreeseasoncircinv*/, 0 /*variationbeyondlifetimecirc*/, fp_systemuserid,
               sysdate /*timestamp*/, x.qtyrentedperpiece /*qtyrentedperpiece*/, x.qtyrentedother, 0
               /*variationrentedother*/, x.qtycustomerrentstop, 0 /*variationqtycustomerrentstop*/,
               x.qtyrentstop, 0 /*variationqtyrentstop*/, x.emblemtemplate_id, x.qtyrentemblem, 0
               /*variationqtyrentemblem*/, x.qtyreplacement, 0 /*variationqtyreplacement*/,
               x.qtyassigned, 0 /*variationqtyassigned*/, 0 /*qtyrenteddepositstock*/, 0
               /*variationrenteddepositstock*/, x.qtysubstitute, 0 /*variationqtysubstitute*/,
               x.chargeafterdepreciation, (fp_sqyear * 100 + fp_sqweek) /*yearweek*/, 0
               /*qtyrentedperpiecepool*/, 0 /*variationrentedperpiecepool*/, null
               /*wearerinvoicecategory_id*/, 0 /*qtyfullyamortized*/, 0
               /*variationqtyfullyamortized*/, 0 /*qtyrentedreturnrent*/, 0
               /*variationqtyrentedreturnrent*/, 0 /*qtyrentedminrent*/, 0 /*variationqtyrentedminrent*/
        from   (select a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                        a.product_id, a.sizedefinition_id, a.finishingmethod_id,
                        sum(case
                              when (fp_sqdate between wi.dateactive and wi.dateinactive and
                                   wi.circinventory > 0 and a.qtyrentstop = 0) then
                               wi.maxinventory
                              else
                               0
                            end) maxinventory, sum(a.totalcircinv) totalcircinv,
                        sum(wi.changesperweek) changesperweek, sum(wi.maxfreeofcharge) maxfreeofcharge,
                        sum(a.freeissuedcircinv) freeissuedcircinv,
                        sum(a.freeseasoncircinv) freeseasoncircinv,
                        sum(a.qtycustomerrentstop) qtycustomerrentstop, sum(a.qtyrentstop) qtyrentstop,
                        max(a.emblemtemplate_id) emblemtemplate_id,
                        sum(a.qtyreplacement) qtyreplacement, sum(a.qtyassigned) qtyassigned,
                        sum(a.qtysubstitute) qtysubstitute,
                        max(a.chargeafterdepreciation) chargeafterdepreciation,
                        sum((case
                              when (a.billingmethod = 3 or
                                   (gv_underusemethodss = 4 and a.billingmethod = 2)) then
                               (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                               a.freeseasoncircinv - a.qtysubstitute - a.qtyreplacement)
                              else
                               0
                            end)) qtyrentedperpiece,
                        sum((case a.billingmethod
                               when 3 then
                                0
                               else
                                (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                                a.freeseasoncircinv)
                             end)) qtyrentedother,
                        sum((case
                              when a.emblemtemplate_id is null then
                               0
                              else
                               (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                               a.freeseasoncircinv)
                            end)) qtyrentemblem
                 from   (select t.customer_id, t.department_id, dp.distributionpoint_id,
                                 case fp_sqonwearerlevel
                                    when 1 then
                                     wi.weareremployment_id
                                    else
                                     null
                                  end weareremployment_id, wi.product_id, wi.sizedefinition_id,
                                 wi.finishingmethod_id, count(non.nonuniqueitem_id) totalcircinv,
                                 wi.wearerinventory_id,
                                 sum((case
                                       when non.freeitem = 'Y' then
                                        1
                                       else
                                        0
                                     end)) freeissuedcircinv,
                                 sum((case
                                       when (coalesce(l.seasonalrent, ls.seasonalrent, -1) in (0, 1) and
                                            non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                            wi.season_id is not null and not exists
                                             (select sw.season_id
                                              from   seasonweek sw
                                              where  sw.season_id = wi.season_id
                                              and    sw.weeknumber = fp_sqweek)) then
                                        1
                                       else
                                        0
                                     end)) freeseasoncircinv,
                                 sum((case
                                       when (non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            exists
                                             (select 1
                                              from   temporarygarmentrentstop trs
                                              where  trs.customer_id = t.customer_id
                                              and    (trs.startyear < fp_sqyear and fp_sqyear < trs.endyear)
                                              or     (trs.startyear = fp_sqyear and
                                                    trs.startweek <= fp_sqweek and fp_sqyear < trs.endyear)
                                              or     (trs.startyear < fp_sqyear and fp_sqyear = endyear and
                                                    fp_sqweek <= trs.endweek)
                                              or     (trs.startyear = fp_sqyear and
                                                    trs.startweek <= fp_sqweek and fp_sqyear = trs.endyear and
                                                    fp_sqweek <= trs.endweek))) then
                                        1
                                       else
                                        0
                                     end)) qtycustomerrentstop,
                                 sum((case
                                       when (non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1))) then
                                        1
                                       else
                                        0
                                     end)) qtyrentstop,
                                 max(coalesce(l.emblemtemplate_id, ls.emblemtemplate_id)) emblemtemplate_id,
                                 sum((case
                                       when fp_invoicereplacements <> 1 and
                                            non.flag_id = gv_flagreplacementid and
                                            non.flagstartdate <= fp_sqdate and
                                            non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) then
                                        1
                                       else
                                        0
                                     end)) qtyreplacement,
                                 sum((case
                                       when non.startrentdate > fp_sqdate then
                                        1
                                       else
                                        0
                                     end)) qtyassigned,
                                 sum((case
                                       when fp_invoicesubstitutes <> 1 and non.flag_id = gv_flagsubstituteid and
                                            non.flagstartdate <= fp_sqdate and
                                            non.startrentdate <= fp_sqdate and not (non.freeitem = 'Y') and
                                            (fp_sqdate not between
                                            nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                            nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) then
                                        1
                                       else
                                        0
                                     end)) qtysubstitute,
                                 max((case
                                       when coalesce(l.percentageafterdepreciation,
                                                     ls.percentageafterdepreciation) > 0 and
                                            coalesce(l.billingmethod, ls.billingmethod, -1) = 3 then
                                        'Y'
                                       else
                                        'N'
                                     end)) chargeafterdepreciation,
                                 coalesce(l.billingmethod, ls.billingmethod, -1) billingmethod
                          from   wearerinventory wi
                          left   outer join nonuniqueitem non
                          on     non.wearerinventory_id = wi.wearerinventory_id
                          join   weareremployment we
                          on     we.weareremployment_id = wi.weareremployment_id
                          join   wearer w
                          on     w.wearer_id = we.wearer_id
                          join   product p
                          on     p.product_id = wi.product_id
                          join   productgroup pg
                          on     pg.productgroup_id = p.productgroup_id
                          join   distributionpoint dp
                          on     dp.distributionpoint_id = we.distributionpoint_id
                          join   department t
                          on     t.department_id = dp.department_id
                          left   outer join productlistpercustomer l
                          on     (l.customer_id = t.customer_id and l.product_id = wi.product_id and
                                 l.sizedefinition_id = wi.sizedefinition_id and
                                 l.finishingmethod_id = wi.finishingmethod_id and
                                 fp_sqdate between l.dateactive and l.dateinactive)
                          left   outer join productlistpercustomer ls
                          on     (ls.customer_id = t.customer_id and ls.product_id = wi.product_id and
                                 ls.sizedefinition_id = gv_sizestarid and
                                 ls.finishingmethod_id = wi.finishingmethod_id and
                                 fp_sqdate between ls.dateactive and ls.dateinactive)
                          where  (coalesce(l.billingmethod, ls.billingmethod, -1) <> -1 or
                                 fp_inactiveplpc <> 2)
                          and    exists (select 1
                                  from   customeractivities ca
                                  where  ca.customer_id = t.customer_id
                                  and    ca.processbusinessunit_id = fp_processbuid
                                  and    ca.activity_id = pg.activity_id
                                  and    (fp_checkinvoicebu = 0 or
                                        ca.invoicebusinessunit_id = fp_invoicebuid))
                          group  by wi.wearerinventory_id, t.customer_id, t.department_id,
                                    dp.distributionpoint_id,
                                    case fp_sqonwearerlevel
                                      when 1 then
                                       wi.weareremployment_id
                                      else
                                       null
                                    end, wi.product_id, wi.sizedefinition_id, wi.finishingmethod_id,
                                    coalesce(l.billingmethod, ls.billingmethod, -1)) a
                 join   wearerinventory wi
                 on     wi.wearerinventory_id = a.wearerinventory_id
                 group  by a.customer_id, a.department_id, a.distributionpoint_id,
                           a.weareremployment_id, a.product_id, a.sizedefinition_id,
                           a.finishingmethod_id) x;
    end add_non_uniqueitem;

    procedure add_uniqueitem is
    begin
      --Add_uniqueitem
      gv_message := 'Add_uniqueitem';
      merge into sqitemincirculation sqi
      using (select a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                    a.product_id, a.sizedefinition_id, a.finishingmethod_id,
                    sum(a.maxinventory) maxinventory, sum(a.totalcircinv) totalcircinv,
                    sum(a.changesperweek) changesperweek, sum(a.maxfreeinv) maxfreeinv,
                    max(a.emblemtemplate_id) emblemtemplate_id, sum(a.qtyassigned) qtyassigned,
                    sum(a.cogcircinv) cogcircinv, sum(a.freeissuedcircinv) freeissuedcircinv,
                    sum(a.qtyrentstop) qtyrentstop, sum(a.qtycustomerrentstop) qtycustomerrentstop,
                    sum(a.freeseasoncircinv) freeseasoncircinv,
                    sum(a.beyondlifetimecirc) beyondlifetimecirc,
                    sum(case
                          when (a.billingmethod = 3 or (gv_underusemethodss = 4 and a.billingmethod = 2)) then
                           (a.qtyrentedother)
                          else
                           case
                             when (a.totalcircinv - a.qtyassigned - a.cogcircinv - a.qtyrentedother -
                                  a.freeissuedcircinv - a.qtyrentstop - a.freeseasoncircinv -
                                  a.qtyfullyamortized) > 0 then
                              (a.totalcircinv - a.qtyassigned - a.cogcircinv - a.qtyrentedother -
                              a.freeissuedcircinv - a.qtyrentstop - a.freeseasoncircinv - a.qtyfullyamortized)
                             else
                              0
                           end
                        end) qtyrentedother, sum(a.qtyreplacement) qtyreplacement,
                    sum(a.qtysubstitute) qtysubstitute,
                    max(a.chargeafterdepreciation) chargeafterdepreciation,
                    sum(a.qtyrentedperpiecepool) qtyrentedperpiecepool,
                    sum(a.qtyfullyamortized) qtyfullyamortized,
                    sum(a.qtyrenteddepositstock) qtyrenteddepositstock,
                    sum((case
                          when (a.billingmethod = 3 or (gv_underusemethodss = 4 and a.billingmethod = 2) and
                               (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv -
                               a.qtyrentstop - a.freeseasoncircinv - a.qtysubstitute -
                               a.qtyreplacement - a.beyondlifetimecirc) > 0) then
                           (a.totalcircinv - a.qtyassigned - a.freeissuedcircinv - a.qtyrentstop -
                           a.freeseasoncircinv - a.qtysubstitute - a.qtyreplacement - a.beyondlifetimecirc -
                           a.qtyrenteddepositstock)
                          else
                           0
                        end)) qtyrentedperpiece
             from   (select t.customer_id, t.department_id, dp.distributionpoint_id,
                             case fp_sqonwearerlevel
                                when 1 then
                                 wi.weareremployment_id
                                else
                                 null
                              end weareremployment_id, wi.product_id, wi.sizedefinition_id,
                             wi.finishingmethod_id, 0 maxinventory, count(u.uniqueitem_id) totalcircinv,
                             0 changesperweek, max(wi.maxfreeofcharge) maxfreeinv,
                             coalesce(l.billingmethod, ls.billingmethod, -1) billingmethod,
                             max(coalesce(l.emblemtemplate_id, ls.emblemtemplate_id)) emblemtemplate_id,
                             sum((case
                                   when u.status_id = gv_statusassigned then
                                    1
                                   else
                                    0
                                 end)) qtyassigned,
                             sum((case
                                   when u.status_id = gv_statusincirculation and u.customerowned = 'Y' then
                                    1
                                   else
                                    0
                                 end)) cogcircinv,
                             sum((case
                                   when u.status_id = gv_statusincirculation and nvl(u.leaseweeks, 0) = 0 and
                                        nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                        un.freeextragarment = 'Y' and u.customerowned <> 'Y' then
                                    1
                                   else
                                    0
                                 end)) freeissuedcircinv,
                             sum((case
                                   when u.status_id = gv_statusincirculation and nvl(u.leaseweeks, 0) = 0 and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        fp_sqdate between wi.temporaryrentstopstartdate and
                                        wi.temporaryrentstopenddate then
                                    1
                                   else
                                    0
                                 end)) qtyrentstop,
                             sum((case
                                   when u.status_id = gv_statusincirculation and exists
                                    (select 1
                                         from   temporarygarmentrentstop trs
                                         where  trs.customer_id = t.customer_id
                                         and    (trs.startyear < fp_sqyear and fp_sqyear < trs.endyear)
                                         or     (trs.startyear = fp_sqyear and trs.startweek <= fp_sqweek and
                                               fp_sqyear < trs.endyear)
                                         or     (trs.startyear < fp_sqyear and fp_sqyear = endyear and
                                               fp_sqweek <= trs.endweek)
                                         or     (trs.startyear = fp_sqyear and trs.startweek <= fp_sqweek and
                                               fp_sqyear = trs.endyear and fp_sqweek <= trs.endweek)) then
                                    1
                                   else
                                    0
                                 end)) qtycustomerrentstop,
                             sum((case
                                   when u.status_id = gv_statusincirculation and
                                        (coalesce(l.seasonalrent, ls.seasonalrent, -1) in (0, 1)  and
                                        nvl(u.leaseweeks, 0) = 0 and not (u.customerowned = 'Y') and
                                        not (un.freeextragarment = 'Y' and
                                         nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate) and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        wi.season_id is not null and not exists
                                         (select sw.season_id
                                          from   seasonweek sw
                                          where  sw.season_id = wi.season_id
                                          and    sw.weeknumber = fp_sqweek)) then
                                    1
                                   else
                                    0
                                 end)) freeseasoncircinv,
                             sum((case
                                   when nvl(u.leaseweeks, 0) = 0 and u.status_id = gv_statusincirculation and
                                        uf.enddatefullrent < fp_sqdate and
                                        not (un.freeextragarment = 'Y' and
                                             (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate)) and
                                        (fp_sqdate < nvl(wi.temporaryrentstopstartdate, fp_sqdate + 1) or
                                         fp_sqdate > nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        (nvl(wi.season_id, 0) = 0 or
                                         (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 and exists
                                          (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) and not (u.customerowned = 'Y') then
                                    1
                                   else
                                    0
                                 end)) beyondlifetimecirc,
                             sum((case
                                   when (u.status_id = gv_statusincirculation and u.leaseweeks is not null) then
                                    1
                                   else
                                    0
                                 end)) qtyrentedother,
                             sum((case
                                   when fp_invoicereplacements <> 1 and u.status_id = gv_statusincirculation and
                                        nvl(u.leaseweeks, 0) = 0 and not uf.enddatefullrent < fp_sqdate and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        (nvl(wi.season_id, 0) = 0 or
                                        (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 and exists
                                         (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) and exists
                                    (select 1
                                         from   uniqueitemflag ff
                                         where  ff.uniqueitem_id = u.uniqueitem_id
                                         and    ff.flag_id = gv_flagreplacementid
                                         and    ff.startdate <= fp_sqdate) then
                                    1
                                   else
                                    0
                                 end)) qtyreplacement,
                             sum((case
                                   when fp_invoicesubstitutes <> 1 and u.status_id = gv_statusincirculation and
                                        nvl(u.leaseweeks, 0) = 0 and not uf.enddatefullrent < fp_sqdate and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) and
                                        (nvl(wi.season_id, 0) = 0 or
                                        (coalesce(l.seasontype_id, ls.seasontype_id, -1) <> -1 and exists
                                         (select sw.season_id
                                           from   seasonweek sw
                                           where  sw.season_id = wi.season_id
                                           and    sw.weeknumber = fp_sqweek))) and not exists
                                    (select 1
                                         from   uniqueitemflag ff
                                         where  ff.uniqueitem_id = u.uniqueitem_id
                                         and    ff.flag_id = gv_flagreplacementid
                                         and    ff.startdate <= fp_sqdate) and exists
                                    (select 1
                                         from   uniqueitemflag ff
                                         where  ff.uniqueitem_id = u.uniqueitem_id
                                         and    ff.flag_id = gv_flagsubstituteid
                                         and    ff.startdate <= fp_sqdate) then
                                    1
                                   else
                                    0
                                 end)) qtysubstitute,
                             max((case
                                   when coalesce(l.percentageafterdepreciation, ls.percentageafterdepreciation,
                                                 0) > 0 and coalesce(l.billingmethod, ls.billingmethod, -1) = 3 then
                                    'Y'
                                   else
                                    'N'
                                 end)) chargeafterdepreciation,
                             sum((case
                                   when u.status_id = gv_statusincirculation and
                                        trunc(u.lastoutscandate) <
                                        trunc(fp_sqdate) -
                                        7 * coalesce(l.chargerentnoreturnpoolafterwks,
                                                     ls.chargerentnoreturnpoolafterwks) and
                                        coalesce(l.billingmethod, ls.billingmethod, -1) = 3 and
                                        coalesce(l.inventorybillingtype, ls.inventorybillingtype, -1) = 4 and
                                        coalesce(l.chargerentnotreturned, ls.chargerentnotreturned, -1) <> 0 and
                                        coalesce(l.chargerentnoreturnpoolafterwks,
                                                 ls.chargerentnoreturnpoolafterwks, -1) > 0 and
                                        coalesce(l.codeuniquely, ls.codeuniquely, 'N') = 'Y' and
                                        u.stay_id in (select st.stay_id
                                                      from   stay st
                                                      where  st.staytype = 1
                                                      and    st.staynr in (20, 27, 28)) then
                                    1
                                   else
                                    0
                                 end)) qtyrentedperpiecepool,
                             sum((case
                                   when c.chargeamortizeduniqueitems = 0 and u.residualvalueamount = 0 and
                                        u.status_id = gv_statusincirculation and nvl(u.leaseweeks, 0) = 0 and
                                        uf.enddatefullrent >= fp_sqdate and
                                        not (nvl(un.enddatefreeextra, fp_sqdate + 1) > fp_sqdate and
                                         un.freeextragarment = 'Y') and u.customerowned <> 'Y' and
                                        (fp_sqdate not between
                                        nvl(wi.temporaryrentstopstartdate, fp_sqdate - 1) and
                                        nvl(wi.temporaryrentstopenddate, fp_sqdate - 1)) then
                                    1
                                   else
                                    0
                                 end)) qtyfullyamortized,
                             sum(case
                                   when 
                                     u.stay_id = gv_staydepositstockid and
                                     u.status_id = gv_statusincirculation and
                                     u.BUSINESSUNIT_ID = fp_processbuid and
                                     nvl(u.leaseweeks, 0) = 0 and
                                     NOT (un.freeextragarment = 'Y' AND
                                       (un.enddatefreeextra > fp_sqdate OR
                                        nvl(un.enddatefreeextra, to_date('01/01/0001','dd/mm/yyyy')) =
                                           to_date('01/01/0001','dd/mm/yyyy'))) and
                                     NOT (u.customerowned = 'Y') and 
                                     NOT (uf.enddatefullrent < fp_sqdate) and
                                     ((fp_sqdate < wi.temporaryrentstopstartdate OR
                                        fp_sqdate > temporaryrentstopenddate) OR
                                        (nvl(wi.temporaryrentstopstartdate,
                                        to_date('01/01/0001', 'dd/mm/yyyy')) = to_date('01/01/0001','dd/mm/yyyy') AND
                                        nvl(wi.temporaryrentstopenddate, to_date('01/01/0001','dd/mm/yyyy')) =
                                         to_date('01/01/0001', 'dd/mm/yyyy'))) and
                                    NOT EXISTS (SELECT r.uniqueitem_id
                                       FROM uniqueitemflag r
                                         WHERE r.uniqueitem_id = u.uniqueitem_id
                                            AND r.flag_id = gv_flagreplacementid
                                            AND r.startdate <= fp_sqdate) and
                                    NOT EXISTS (SELECT r.uniqueitem_id
                                       FROM uniqueitemflag r
                                         WHERE r.uniqueitem_id = u.uniqueitem_id
                                           AND r.flag_id = gv_flagSubstituteID
                                           AND r.startdate <= fp_sqdate)
                                    then
                                    1
                                   else 0
                                 end) qtyrenteddepositstock, 
                             un.wearerinventory_id,
                             coalesce(l.productlistpercustomer_id, ls.productlistpercustomer_id, -1) plpc_id
                      from   uniqueitem u
                      join   uniqueitemnonpool un
                      on     un.uniqueitem_id = u.uniqueitem_id
                      left   outer join uniqueitemfixedinfo uf
                      on     uf.uniqueitem_id = u.uniqueitem_id
                      join   weareremployment we
                      on     we.weareremployment_id = un.weareremployment_id
                      join   wearerinventory wi
                      on     wi.wearerinventory_id = un.wearerinventory_id
                      join   distributionpoint dp
                      on     dp.distributionpoint_id = we.distributionpoint_id
                      join   department t
                      on     t.department_id = dp.department_id
                      join   customer c
                      on     c.customer_id = t.customer_id
                      join   product p
                      on     p.product_id = wi.product_id
                      join   productgroup pg
                      on     pg.productgroup_id = p.productgroup_id
                      left   outer join productlistpercustomer l
                      on     (l.customer_id = t.customer_id and l.product_id = wi.product_id and
                             l.sizedefinition_id = wi.sizedefinition_id and
                             l.finishingmethod_id = wi.finishingmethod_id and
                             fp_sqdate between l.dateactive and l.dateinactive)
                      left   outer join productlistpercustomer ls
                      on     (ls.customer_id = t.customer_id and ls.product_id = wi.product_id and
                             ls.sizedefinition_id = gv_sizestarid and
                             ls.finishingmethod_id = wi.finishingmethod_id and
                             fp_sqdate between ls.dateactive and ls.dateinactive)
                      where  (coalesce(l.billingmethod, ls.billingmethod, -1) <> -1 or
                             fp_inactiveplpc <> 2)
                      and    exists
                       (select 1
                              from   customeractivities ca
                              where  ca.customer_id = t.customer_id
                              and    ca.processbusinessunit_id = fp_processbuid
                              and    ca.activity_id = pg.activity_id
                              and    (fp_checkinvoicebu = 0 or ca.invoicebusinessunit_id = fp_invoicebuid))
                      group  by t.customer_id, t.department_id, dp.distributionpoint_id,
                                case fp_sqonwearerlevel
                                  when 1 then
                                   wi.weareremployment_id
                                  else
                                   null
                                end, un.wearerinventory_id, wi.product_id, wi.sizedefinition_id,
                                wi.finishingmethod_id, coalesce(l.billingmethod, ls.billingmethod, -1),
                                coalesce(l.productlistpercustomer_id, ls.productlistpercustomer_id, -1)) a
             group  by a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                       a.product_id, a.sizedefinition_id, a.finishingmethod_id) x
      on (sqi.statusquoheader_id = gv_sqheaderid and sqi.distributionpoint_link_id = x.distributionpoint_id and (sqi.weareremployment_link_id = x.weareremployment_id or (sqi.weareremployment_link_id is null and x.weareremployment_id is null)) and sqi.product_link_id = x.product_id and sqi.sizedefinition_link_id = x.sizedefinition_id and sqi.finishingmethod_id = x.finishingmethod_id)
      when matched then
        update
        set    sqi.maxinv = sqi.maxinv + x.maxinventory,
               sqi.totalcircinv = sqi.totalcircinv + x.totalcircinv,
               sqi.changesperweek = sqi.changesperweek + x.changesperweek,
               sqi.maxfreeinv = sqi.maxfreeinv + x.maxfreeinv,
               sqi.freeissuedcircinv = sqi.freeissuedcircinv + x.freeissuedcircinv,
               sqi.cogcircinv = sqi.cogcircinv + x.cogcircinv,
               sqi.freeseasoncircinv = sqi.freeseasoncircinv + x.freeseasoncircinv,
               sqi.beyondlifetimecirc = sqi.beyondlifetimecirc + x.beyondlifetimecirc,
               sqi.qtyrentedperpiecepool = sqi.qtyrentedperpiecepool + x.qtyrentedperpiecepool,
               sqi.qtyassigned = sqi.qtyassigned + x.qtyassigned,
               sqi.qtyrentedperpiece = sqi.qtyrentedperpiece + x.qtyrentedperpiece,
               sqi.qtyrentedother = sqi.qtyrentedother + x.qtyrentedother,
               sqi.qtysubstitute = sqi.qtysubstitute + x.qtysubstitute,
               sqi.qtyrentemblem = sqi.qtyrentemblem + case
                                      when x.emblemtemplate_id is null then
                                       0
                                      else
                                       (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
                                    end,
               sqi.qtyreplacement = sqi.qtyreplacement + x.qtyreplacement,
               sqi.qtycustomerrentstop = sqi.qtycustomerrentstop + x.qtycustomerrentstop,
               sqi.qtyrentstop = sqi.qtyrentstop + x.qtyrentstop,
               sqi.qtyfullyamortized = sqi.qtyfullyamortized + x.qtyfullyamortized,
               sqi.qtyrenteddepositstock = sqi.qtyrenteddepositstock + x.qtyrenteddepositstock,
               sqi.emblemtemplate_id = nvl(sqi.emblemtemplate_id, x.emblemtemplate_id),
               sqi.systemuser_id = fp_systemuserid, sqi.timestamp = sysdate
      when not matched then
        insert
          (sqitemincirculation_id, statusquoheader_id, customer_link_id, department_link_id,
           distributionpoint_link_id, weareremployment_link_id, product_link_id, sizedefinition_link_id,
           finishingmethod_id, maxinv, totalcircinv, changesperweek, maxfreeinv, freeissuedcircinv,
           cogcircinv, freeseasoncircinv, beyondlifetimecirc, variationmaxinv, variationtotalcircinv,
           variationchangesperweek, variationmaxfreeinv, variationrentedperpiece,
           variationfreeissuedcircinv, variationcogcircinv, variationfreeseasoncircinv,
           variationbeyondlifetimecirc, systemuser_id, timestamp, qtyrentedperpiece, qtyrentedother,
           variationrentedother, qtycustomerrentstop, variationqtycustomerrentstop, qtyrentstop,
           variationqtyrentstop, emblemtemplate_id, qtyrentemblem, variationqtyrentemblem,
           qtyreplacement, variationqtyreplacement, qtyassigned, variationqtyassigned,
           qtyrenteddepositstock, variationrenteddepositstock, qtysubstitute, variationqtysubstitute,
           chargeafterdepreciation, yearweek, qtyrentedperpiecepool, variationrentedperpiecepool,
           wearerinvoicecategory_id, qtyfullyamortized, variationqtyfullyamortized, qtyrentedreturnrent,
           variationqtyrentedreturnrent, qtyrentedminrent, variationqtyrentedminrent)
        values
          (seq_sqitemincirculation.nextval, gv_sqheaderid, x.customer_id, x.department_id,
           x.distributionpoint_id, x.weareremployment_id, x.product_id, x.sizedefinition_id,
           x.finishingmethod_id, x.maxinventory, x.totalcircinv, x.changesperweek, x.maxfreeinv,
           x.freeissuedcircinv, x.cogcircinv, x.freeseasoncircinv, x.beyondlifetimecirc, 0
           /*variationmaxinv*/, 0 /*variationtotalcircinv*/, 0 /*variationchangesperweek*/, 0
           /*variationmaxfreeinv*/, 0 /*variationrentedperpiece*/, 0 /*variationfreeissuedcircinv*/, 0
           /*variationcogcircinv*/, 0 /*variationfreeseasoncircinv*/, 0 /*variationbeyondlifetimecirc*/,
           fp_systemuserid, sysdate /*timestamp*/, x.qtyrentedperpiece, x.qtyrentedother, 0
           /*variationrentedother*/, x.qtycustomerrentstop, 0 /*variationqtycustomerrentstop*/,
           x.qtyrentstop, 0 /*variationqtyrentstop*/, x.emblemtemplate_id,
           case
              when x.emblemtemplate_id is null then
               0
              else
               (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
            end /*qtyrentemblem*/, 0 /*variationqtyrentemblem*/, x.qtyreplacement, 0
           /*variationqtyreplacement*/, x.qtyassigned, 0 /*variationqtyassigned*/, 0
           /*qtyrenteddepositstock*/, 0 /*variationrenteddepositstock*/, x.qtysubstitute, 0
           /*variationqtysubstitute*/, nvl(x.chargeafterdepreciation, 'N'),
           (fp_sqyear * 100 + fp_sqweek)
           /*yearweek*/, x.qtyrentedperpiecepool, 0 /*variationrentedperpiecepool*/, null
           /*wearerinvoicecategory_id*/, x.qtyfullyamortized, 0 /*variationqtyfullyamortized*/, 0
           /*qtyrentedreturnrent*/, 0 /*variationqtyrentedreturnrent*/, 0 /*qtyrentedminrent*/, 0
           /*variationqtyrentedminrent*/);
    end add_uniqueitem;

    procedure add_uniquepoolitem is
    begin
      --add_uniquepoolitem
      gv_message := 'add_uniquepoolitem';
      merge into sqitemincirculation sqi
      using (select a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                    a.product_id, a.sizedefinition_id, a.finishingmethod_id,
                    sum(a.maxinventory) maxinventory, sum(a.totalcircinv) totalcircinv,
                    sum(a.changesperweek) changesperweek, sum(a.maxfreeinv) maxfreeinv,
                    max(a.emblemtemplate_id) emblemtemplate_id, sum(a.qtyassigned) qtyassigned,
                    sum(a.cogcircinv) cogcircinv, sum(a.freeissuedcircinv) freeissuedcircinv,
                    sum(a.qtyrentstop) qtyrentstop, sum(a.qtycustomerrentstop) qtycustomerrentstop,
                    sum(a.freeseasoncircinv) freeseasoncircinv,
                    sum(a.beyondlifetimecirc) beyondlifetimecirc, sum(a.qtyrentedother) qtyrentedother,
                    sum(a.qtyreplacement) qtyreplacement, sum(a.qtysubstitute) qtysubstitute,
                    max(a.chargeafterdepreciation) chargeafterdepreciation,
                    sum(a.qtyrentedperpiecepool) qtyrentedperpiecepool,
                    sum(a.qtyfullyamortized) qtyfullyamortized
             from   (select t.customer_id, t.department_id, dp.distributionpoint_id,
                             null weareremployment_id, u.product_id, u.sizedefinition_id,
                             u.finishingmethod_id, 0 maxinventory, 0 totalcircinv, 0 changesperweek,
                             0 maxfreeinv, coalesce(l.billingmethod, ls.billingmethod, -1) billingmethod,
                             max(coalesce(l.emblemtemplate_id, ls.emblemtemplate_id)) emblemtemplate_id,
                             0 qtyassigned, 0 cogcircinv, 0 freeissuedcircinv,
                             sum(coalesce((select 1
                                           from   standarddeliveryline y
                                           join   productlistperdistribpoint plpdp
                                           on     plpdp.productlistperdistribpoint_id =
                                                  y.productlistperdistribpoint_id
                                           where  plpdp.distributionpoint_id = u.distributionpoint_id
                                           and    plpdp.product_id = u.product_id
                                           and    plpdp.sizedefinition_id = u.sizedefinition_id
                                           and    plpdp.finishingmethod_id = u.finishingmethod_id
                                           and    exists
                                            (select tds.standarddeliveryline_id
                                                   from   temporarydeliverystop tds
                                                   where  tds.standarddeliveryline_id =
                                                          y.standarddeliveryline_id
                                                   and    ((tds.tempstoprentforweek = 'Y' and
                                                         (fp_sqweek between tds.temporarystopstartweek and
                                                         tds.temporarystopendweek) or
                                                         (tds.temporarystopstartweek >
                                                         tds.temporarystopendweek and
                                                         ((fp_sqweek <= tds.temporarystopendweek and
                                                         0 < fp_sqweek) or
                                                         (temporarystopstartweek <= fp_sqweek and
                                                         fp_sqweek <= 53)))) or
                                                         (tds.tempstoprentforyearweek = 'Y' and
                                                         f_isinyearweeklifespan(tds.temporarystopstartyear,
                                                                                   tds.tempstopstartweekforyear,
                                                                                   fp_sqyear, fp_sqweek,
                                                                                   tds.temporarystopendyear,
                                                                                   tds.tempstopendweekforyear) = 1) or
                                                         (tds.tempstoprentfordate = 'Y' and
                                                         (tds.startdate <= sysdate and
                                                         sysdate <= tds.enddate))))), 0)) qtyrentstop,
                             sum((case
                                   when u.status_id = gv_statusincirculation and exists
                                    (select 1
                                         from   temporarygarmentrentstop trs
                                         where  trs.customer_id = t.customer_id
                                         and    (trs.startyear < fp_sqyear and fp_sqyear < trs.endyear)
                                         or     (trs.startyear = fp_sqyear and trs.startweek <= fp_sqweek and
                                               fp_sqyear < trs.endyear)
                                         or     (trs.startyear < fp_sqyear and fp_sqyear = endyear and
                                               fp_sqweek <= trs.endweek)
                                         or     (trs.startyear = fp_sqyear and trs.startweek <= fp_sqweek and
                                               fp_sqyear = trs.endyear and fp_sqweek <= trs.endweek)) then
                                    1
                                   else
                                    0
                                 end)) qtycustomerrentstop, 0 freeseasoncircinv, 0 beyondlifetimecirc,
                             0 qtyrentedother, 0 qtyreplacement, 0 qtysubstitute,
                             'N' chargeafterdepreciation, count(u.uniqueitem_id) qtyrentedperpiecepool,
                             0 qtyfullyamortized
                      from   uniqueitem u
                      join   uniqueitemfixedinfo uf
                      on     uf.uniqueitem_id = u.uniqueitem_id
                      join   product p
                      on     p.product_id = u.product_id
                      join   productgroup pg
                      on     pg.productgroup_id = p.productgroup_id
                      join   distributionpoint dp
                      on     dp.distributionpoint_id = u.distributionpoint_id
                      join   department t
                      on     t.department_id = dp.department_id
                      join   customer c
                      on     c.customer_id = t.customer_id
                      left   outer join productlistpercustomer l
                      on     (l.customer_id = t.customer_id and l.product_id = u.product_id and
                             l.sizedefinition_id = u.sizedefinition_id and
                             l.finishingmethod_id = u.finishingmethod_id and
                             fp_sqdate between l.dateactive and l.dateinactive)
                      left   outer join productlistpercustomer ls
                      on     (ls.customer_id = t.customer_id and ls.product_id = u.product_id and
                             ls.sizedefinition_id = gv_sizestarid and
                             ls.finishingmethod_id = u.finishingmethod_id and
                             fp_sqdate between ls.dateactive and ls.dateinactive)
                      where  u.status_id in (gv_statusincirculation, gv_statusassigned)
                      and    u.poolitem <> 0 --not on stock
                      and    u.finishingmethod_id is not null --must exist for sqitems
                      and    coalesce(l.chargerentnoreturnpoolafterwks, ls.chargerentnoreturnpoolafterwks,
                                      0) > 0
                      and    trunc(u.lastoutscandate) <
                             trunc(sysdate) -
                             7 * coalesce(l.chargerentnoreturnpoolafterwks,
                                           ls.chargerentnoreturnpoolafterwks, 0)
                      and    (coalesce(l.billingmethod, ls.billingmethod, -1) <> -1 or
                            fp_inactiveplpc <> 2)
                      and    exists
                       (select 1
                              from   customeractivities ca
                              where  ca.customer_id = t.customer_id
                              and    ca.processbusinessunit_id = fp_processbuid
                              and    ca.activity_id = pg.activity_id
                              and    (fp_checkinvoicebu = 0 or ca.invoicebusinessunit_id = fp_invoicebuid))
                      and    not exists (select 1
                              from   uniqueitemloss uil
                              where  uil.uniqueitem_link_id = u.uniqueitem_id
                              and    (uil.lossstatus = 0 or uil.lossstatus = 1)
                              and    u.lastoutscandate = uil.outscandate)
                      group  by t.customer_id, t.department_id, dp.distributionpoint_id, u.product_id,
                                u.sizedefinition_id, u.finishingmethod_id,
                                coalesce(l.billingmethod, ls.billingmethod, -1)) a
             group  by a.customer_id, a.department_id, a.distributionpoint_id, a.weareremployment_id,
                       a.product_id, a.sizedefinition_id, a.finishingmethod_id) x
      on (sqi.statusquoheader_id = gv_sqheaderid and sqi.distributionpoint_link_id = x.distributionpoint_id and (sqi.weareremployment_link_id = x.weareremployment_id or (sqi.weareremployment_link_id is null and x.weareremployment_id is null)) and sqi.product_link_id = x.product_id and sqi.sizedefinition_link_id = x.sizedefinition_id and sqi.finishingmethod_id = x.finishingmethod_id)
      when matched then
        update
        set    sqi.qtycustomerrentstop = sqi.qtycustomerrentstop + x.qtycustomerrentstop,
               sqi.qtyrentedperpiecepool = sqi.qtyrentedperpiecepool + x.qtyrentedperpiecepool -
                                            x.qtyrentstop,
               sqi.qtyrentstop = sqi.qtyrentstop + x.qtyrentstop,
               sqi.emblemtemplate_id = nvl(sqi.emblemtemplate_id, x.emblemtemplate_id),
               sqi.qtyrentemblem = sqi.qtyrentemblem + case
                                      when x.emblemtemplate_id is null then
                                       0
                                      else
                                       (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
                                    end,
               sqi.systemuser_id = fp_systemuserid, sqi.timestamp = sysdate
      when not matched then
        insert
          (sqitemincirculation_id, statusquoheader_id, customer_link_id, department_link_id,
           distributionpoint_link_id, weareremployment_link_id, product_link_id, sizedefinition_link_id,
           finishingmethod_id, maxinv, totalcircinv, changesperweek, maxfreeinv, freeissuedcircinv,
           cogcircinv, freeseasoncircinv, beyondlifetimecirc, variationmaxinv, variationtotalcircinv,
           variationchangesperweek, variationmaxfreeinv, variationrentedperpiece,
           variationfreeissuedcircinv, variationcogcircinv, variationfreeseasoncircinv,
           variationbeyondlifetimecirc, systemuser_id, timestamp, qtyrentedperpiece, qtyrentedother,
           variationrentedother, qtycustomerrentstop, variationqtycustomerrentstop, qtyrentstop,
           variationqtyrentstop, emblemtemplate_id, qtyrentemblem, variationqtyrentemblem,
           qtyreplacement, variationqtyreplacement, qtyassigned, variationqtyassigned,
           qtyrenteddepositstock, variationrenteddepositstock, qtysubstitute, variationqtysubstitute,
           chargeafterdepreciation, yearweek, qtyrentedperpiecepool, variationrentedperpiecepool,
           wearerinvoicecategory_id, qtyfullyamortized, variationqtyfullyamortized, qtyrentedreturnrent,
           variationqtyrentedreturnrent, qtyrentedminrent, variationqtyrentedminrent)
        values
          (seq_sqitemincirculation.nextval, gv_sqheaderid, x.customer_id, x.department_id,
           x.distributionpoint_id, x.weareremployment_id, x.product_id, x.sizedefinition_id,
           x.finishingmethod_id, x.maxinventory, x.totalcircinv, x.changesperweek, x.maxfreeinv,
           x.freeissuedcircinv, x.cogcircinv, x.freeseasoncircinv, x.beyondlifetimecirc, 0
           /*variationmaxinv*/, 0 /*variationtotalcircinv*/, 0 /*variationchangesperweek*/, 0
           /*variationmaxfreeinv*/, 0 /*variationrentedperpiece*/, 0 /*variationfreeissuedcircinv*/, 0
           /*variationcogcircinv*/, 0 /*variationfreeseasoncircinv*/, 0 /*variationbeyondlifetimecirc*/,
           fp_systemuserid, sysdate /*timestamp*/,
           (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
           /*qtyrentedperpiece*/, x.qtyrentedother, 0 /*variationrentedother*/, x.qtycustomerrentstop, 0
           /*variationqtycustomerrentstop*/, x.qtyrentstop, 0 /*variationqtyrentstop*/,
           x.emblemtemplate_id,
           case
              when x.emblemtemplate_id is null then
               0
              else
               (x.totalcircinv - x.qtyassigned - x.freeissuedcircinv - x.qtyrentstop - x.freeseasoncircinv)
            end /*qtyrentemblem*/, 0 /*variationqtyrentemblem*/, x.qtyreplacement, 0
           /*variationqtyreplacement*/, x.qtyassigned, 0 /*variationqtyassigned*/, 0
           /*qtyrenteddepositstock*/, 0 /*variationrenteddepositstock*/, x.qtysubstitute, 0
           /*variationqtysubstitute*/, nvl(x.chargeafterdepreciation, 'N'),
           (fp_sqyear * 100 + fp_sqweek)
           /*yearweek*/, x.qtyrentedperpiecepool, 0 /*variationrentedperpiecepool*/, null
           /*wearerinvoicecategory_id*/, x.qtyfullyamortized, 0 /*variationqtyfullyamortized*/, 0
           /*qtyrentedreturnrent*/, 0 /*variationqtyrentedreturnrent*/, 0 /*qtyrentedminrent*/, 0
           /*variationqtyrentedminrent*/);
    end add_uniquepoolitem;

    procedure add_uniqueitemreturnrent is
    begin
      --createSQItemInCirc based on Unique Item Return Rent
      if (fp_userentbasedonreturnweeks = 1 and fp_settlementactive = 0) then
        begin
          --add_uniqueitemreturnrent
          gv_message := 'add_uniqueitemreturnrent';
          merge into sqitemincirculation sqi
          using (select sum((case
                              when uirr.returnrenttype = 1 then
                               1
                              else
                               0
                            end)) variationqtyrentedminrent,
                        sum((case
                              when uirr.returnrenttype = 2 then
                               1
                              else
                               0
                            end)) qtyrentedminrent, uirr.customer_link_id, dp.department_id,
                        we.distributionpoint_id,
                        case fp_sqonwearerlevel
                           when 1 then
                            uirr.weareremployment_link_id
                           else
                            null
                         end weareremployment_id, uirr.product_link_id, uirr.sizedefinition_link_id,
                        uirr.finishingmethod_id,
                        sum((case
                              when exists (select 1
                                    from   temporarygarmentrentstop trs
                                    where  trs.customer_id = d.customer_id
                                    and    (trs.startyear < fp_sqyear and fp_sqyear < trs.endyear)
                                    or     (trs.startyear = fp_sqyear and trs.startweek <= fp_sqweek and
                                          fp_sqyear < trs.endyear)
                                    or     (trs.startyear < fp_sqyear and fp_sqyear = endyear and
                                          fp_sqweek <= trs.endweek)
                                    or     (trs.startyear = fp_sqyear and trs.startweek <= fp_sqweek and
                                          fp_sqyear = trs.endyear and fp_sqweek <= trs.endweek)) then
                               1
                              else
                               0
                            end)) qtycustomerrentstop
                 from   uniqueitemreturnrent uirr
                 join   weareremployment we
                 on     we.weareremployment_id = uirr.weareremployment_link_id
                 join   distributionpoint dp
                 on     dp.distributionpoint_id = we.distributionpoint_id
                 join   department d
                 on     d.department_id = dp.department_id
                 where  uirr.returnrenttype in (1, 2)
                 and    uirr.rentyear = fp_sqyear
                 and    uirr.rentweek = fp_sqweek
                 and    exists (select productlistpercustomer_id
                         from   productlistpercustomer plpc
                         where  plpc.customer_id = uirr.customer_link_id
                         and    plpc.product_id = uirr.product_link_id
                         and    (plpc.sizedefinition_id = uirr.sizedefinition_link_id or
                               plpc.sizedefinition_id = gv_sizestarid)
                         and    plpc.finishingmethod_id = uirr.finishingmethod_id
                         and    fp_sqdate between plpc.dateactive and plpc.dateinactive
                         and    plpc.billingmethod = 3
                         and    plpc.inventorybillingtype in (1, 2))
                 and    exists (select sqitemincirculation_id
                         from   sqitemincirculation sqi
                         where  sqi.statusquoheader_id = gv_sqheaderid
                         and    sqi.customer_link_id = uirr.customer_link_id
                         and    sqi.product_link_id = uirr.product_link_id
                         and    sqi.totalcircinv > 0)
                 group  by uirr.customer_link_id, dp.department_id, we.distributionpoint_id,
                           case fp_sqonwearerlevel
                             when 1 then
                              uirr.weareremployment_link_id
                             else
                              null
                           end, uirr.product_link_id, uirr.sizedefinition_link_id, uirr.finishingmethod_id) x
          on (sqi.statusquoheader_id = gv_sqheaderid and sqi.distributionpoint_link_id = x.distributionpoint_id and (sqi.weareremployment_link_id = x.weareremployment_id or (sqi.weareremployment_link_id is null and x.weareremployment_id is null)) and sqi.product_link_id = x.product_link_id and sqi.sizedefinition_link_id = x.sizedefinition_link_id and sqi.finishingmethod_id = x.finishingmethod_id)
          when matched then
            update
            set    sqi.variationqtyrentedminrent = sqi.variationqtyrentedminrent + case
                                                      when qtycustomerrentstop = 0 then
                                                       x.variationqtyrentedminrent
                                                      else
                                                       0
                                                    end,
                   sqi.qtyrentedminrent = sqi.qtyrentedminrent + case
                                             when qtycustomerrentstop = 0 then
                                              x.qtyrentedminrent
                                             else
                                              0
                                           end, sqi.systemuser_id = fp_systemuserid, sqi.timestamp = sysdate;
        end;
      end if;
    end add_uniqueitemreturnrent;

    procedure finalize is
      lv_totalquantity number;
    begin
      --finalize
      gv_message := 'finalize, update statusquoheader';
      update statusquoheader sqh
      set    sqh.totalquantity = nvl((select sum(sqi.totalcircinv)
                                      from   sqitemincirculation sqi
                                      where  sqi.statusquoheader_id = sqh.statusquoheader_id), 0)
      where  statusquoheader_id = gv_sqheaderid
      returning totalquantity into lv_totalquantity;
      commit;
      --return variable
      fp_sqheaderid := gv_sqheaderid;
      --write log
      write_log('Ready SQIemincirculation ' || lv_totalquantity ||
                ' totalcircinv, for statusquoheader_id ' || fp_sqheaderid, 1);
    end finalize;

    procedure update_plpc is
    begin
      --update_plpc
      gv_message := 'update_plpc';
      update productlistpercustomer l
      set    l.totalincirculation =
              (select sum(sqi.totalcircinv)
               from   statusquoheader sqh
               join   sqitemincirculation sqi
               on     sqi.statusquoheader_id = sqh.statusquoheader_id
               where  sqh.statusquoheader_id = gv_sqheaderid
               and    sqi.customer_link_id = l.customer_id
               and    sqi.product_link_id = l.product_id
               and    (sqi.sizedefinition_link_id = l.sizedefinition_id or
                     l.sizedefinition_id = gv_sizestarid)
               and    l.finishingmethod_id = sqi.finishingmethod_id
               and    sqh.statusquodate between l.dateactive and l.dateinactive),
             l.totalincirculationcharged =
              (select sum(sqi.qtyrentedperpiece) + sum(sqi.qtyrentedother) +
                       sum(sqi.qtyrenteddepositstock) + sum(case sqi.chargeafterdepreciation
                                                              when 'Y' then
                                                               sqi.beyondlifetimecirc
                                                              else
                                                               0
                                                            end) totalincirculationcharged
               from   statusquoheader sqh
               join   sqitemincirculation sqi
               on     sqi.statusquoheader_id = sqh.statusquoheader_id
               where  sqh.statusquoheader_id = gv_sqheaderid
               and    sqi.customer_link_id = l.customer_id
               and    sqi.product_link_id = l.product_id
               and    (sqi.sizedefinition_link_id = l.sizedefinition_id or
                     l.sizedefinition_id = gv_sizestarid)
               and    l.finishingmethod_id = sqi.finishingmethod_id
               and    sqh.statusquodate between l.dateactive and l.dateinactive)
      where  exists (select 1
              from   statusquoheader sqh
              join   sqitemincirculation sqi
              on     sqi.statusquoheader_id = sqh.statusquoheader_id
              where  sqh.statusquoheader_id = gv_sqheaderid
              and    sqi.customer_link_id = l.customer_id
              and    sqi.product_link_id = l.product_id
              and    (sqi.sizedefinition_link_id = l.sizedefinition_id or
                    l.sizedefinition_id = gv_sizestarid)
              and    l.finishingmethod_id = sqi.finishingmethod_id
              and    sqh.statusquodate between l.dateactive and l.dateinactive);
      --commit
      commit;
    end update_plpc;
  begin
    --Main program part createsqitemsincirculation
    --initialize
    initialize;
    --Create SQ Header
    create_sq_header;
    --Add_NON_uniqueitem
    add_non_uniqueitem;
    --Add_uniqueitem
    add_uniqueitem;
    --Add_uniquepoolitem
    add_uniquepoolitem;
    --add_uniqueitemreturnrent
    add_uniqueitemreturnrent;
    --finalize
    finalize;
    --update_plpc
    update_plpc;
  exception
    when no_data_found then
      begin
        rollback;
        fp_sqheaderid := null;
        write_log('No data found ' || gv_message || ' ' || sqlerrm, 3);
      end;
    when others then
      begin
        rollback;
        fp_sqheaderid := null;
        write_log(gv_message || ' ' || sqlerrm, 3);
      end;
  end createsqitemsincirculation;

  procedure check_duplicate_plpc is
    gv_separator varchar2(1) := ';';
    gv_counter   number := 0;

    --interal procedures
    procedure write_log(fp_message in varchar2, fp_priority in number) is
    begin
      /* writes logs into database.
      priority
      1 = Message
      2 = Warning
      3 = Error
      4 = Stack trace
      5 = Debug info  */
      abslogwrite.abslog_write(5, 'Pack_SQItemInCirculation', null, fp_priority,
                               'check_duplicate_plpc ' || fp_message);
      begin
        dbms_output.put_line(fp_message);
      exception
        when others then
          null;
      end;
    end write_log;
  begin
    --check_duplicate_plpc
    for zz in (select l.productlistpercustomer_id, c.customernumber, p.code productcode,
                      s.code sizecode, f.code finishingmethod, l.dateactive, l.dateinactive
               from   productlistpercustomer l
               join   customer c
               on     c.customer_id = l.customer_id
               join   product p
               on     p.product_id = l.product_id
               join   sizedefinition s
               on     s.sizedefinition_id = l.sizedefinition_id
               join   finishingmethod f
               on     f.finishingmethod_id = l.finishingmethod_id
               where  exists (select 1
                       from   productlistpercustomer x
                       where  x.customer_id = l.customer_id
                       and    x.product_id = l.product_id
                       and    x.sizedefinition_id = l.sizedefinition_id
                       and    x.finishingmethod_id = l.finishingmethod_id
                       and    x.productlistpercustomer_id <> l.productlistpercustomer_id
                       and    (x.dateactive between l.dateactive and l.dateinactive or
                             x.dateinactive between l.dateactive and l.dateinactive))
               order  by c.customernumber, p.code, s.code, f.code, l.productlistpercustomer_id) loop
      begin
        --
        if gv_counter = 0 then
          begin
            --output Header
            write_log('Productlistpercustomer_id' || gv_separator || 'Customernumber' ||
                      gv_separator || 'Productcode' || gv_separator || 'Sizecode' || gv_separator ||
                      'Finishingmethod' || gv_separator || 'Dateactive' || gv_separator ||
                      'Dateinactive' || gv_separator, 3);
          end;
        end if;
        --output duplicate PLPC's
        write_log(zz.productlistpercustomer_id || gv_separator || zz.customernumber ||
                  gv_separator || zz.productcode || gv_separator || zz.sizecode || gv_separator ||
                  zz.finishingmethod || gv_separator || to_char(zz.dateactive, 'dd-mm-yyyy') ||
                  gv_separator || to_char(zz.dateinactive, 'dd-mm-yyyy') || gv_separator, 3);
        --count duplicates
        gv_counter := gv_counter + 1;
      end;
    end loop;
    if gv_counter > 0 then
      begin
        write_log('Error ' || gv_counter || ' duplicate PLPC line(s)!', 3);
      end;
    else
      begin
        write_log('All ok, no duplicate PLPC lines', 1);
      end;
    end if;
  exception
    when others then
      begin
        rollback;
        write_log(sqlerrm, 3);
      end;
  end check_duplicate_plpc;

end pack_sqitemsincirculation_new;

/
create or replace PACKAGE pack_sqitemsincirculation_OLD IS

  SQ_ITEMS_IN_CIRCULATION    statusquoheader.statusquotype%TYPE := 1;
  AUTOMATICFLAG_SUBSTITUTE   automaticflag.automaticflag_id%TYPE := 12;
  AUTOMATICFLAG_REPLACEMENT  automaticflag.automaticflag_id%TYPE := 4;
  BILL_CIRCULATING_INVENTORY productlistpercustomer.billingmethod%TYPE := 3;
  BILL_RENT_BASED_MINIMUM    productlistpercustomer.billingmethod%TYPE := 2;
  TYPEOFMERCHANDISE_GARMENT  product.typeofmerchandise%TYPE := 2;
  STAY_TYPE_GARMENT          stay.staytype%TYPE := 1;
  STAY_NR_DEPOSITSTOCK       stay.staynr%TYPE := 37;
  underuseMethodSS           numeric := 0;
  INVENTORY_BILLING_TYPE_MAX productlistpercustomer.inventorybillingtype%TYPE := 2;
  bm3MaxInvReduceDepositSS   numeric := 0;

  PROCEDURE createSqItemsInCirculation(sqHeaderID          OUT statusquoheader.statusquoheader_id%TYPE,
                                       processBuID         businessunit.businessunit_id%TYPE,
                                       invoiceBuID         businessunit.businessunit_id%TYPE,
                                       sqDate              DATE,
                                       sqYear              INT,
                                       sqWeek              INT,
                                       sqMonth             INT,
                                       sqSubType           INT,
                                       systemUserID        systemuser.systemuser_id%TYPE,
                                       checkInvoiceBu      INT,
                                       useRentOnStock      INT,
                                       inactivePLPC        INT,
                                       plantID             plant.plant_id%TYPE,
                                       invoiceReplacements INT,
                                       invoiceSubstitutes  INT,
                                       sqOnWearerLevel     INT,
                                       useRentBasedOnReturnWeeks INT,
                                       settlementActive          INT,
                                       chargeReplacedProduct INT,
                                       abslogprocessjob    INT);

  PROCEDURE createSqItemInCircOnWearerInv(sqHeaderID          statusquoheader.statusquoheader_id%TYPE,
                                          processBuID         businessunit.businessunit_id%TYPE,
                                          invoiceBuID         businessunit.businessunit_id%TYPE,
                                          checkInvoiceBu      INT,
                                          inactivePLPC        INT,
                                          sizeStarID          sizedefinition.sizedefinition_id%TYPE,
                                          flagsubstituteid    flag.flag_id%TYPE,
                                          flagreplacementid   flag.flag_id%TYPE,
                                          invoiceReplacements INT,
                                          invoiceSubstitutes  INT,
                                          chargeReplacedProduct INT,
                                          sqOnWearerLevel     INT);
  FUNCTION getOldMaxInventory(wearerinventoryID     wearerinventory.wearerinventory_id%TYPE,
                              oldMaxInv             OUT INT) RETURN BOOLEAN;

  PROCEDURE createOrStoreOnSqForWearerInv(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                          inactivePLPC          INT,
                                          sqOnWearerLevel       INT,
                                          wearerInventoryID     wearerinventory.wearerinventory_id%TYPE,
                                          customerID            customer.customer_id%TYPE,
                                          departmentID          department.department_id%TYPE,
                                          distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                          productID             product.product_id%TYPE,
                                          sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                          finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                          wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                          changesperweek        wearerinventory.changesperweek%TYPE,
                                          maxfreeofcharge       wearerinventory.maxfreeofcharge%TYPE,
                                          emblemtemplateid      IN OUT emblemtemplate.emblemtemplate_id%TYPE,
                                          sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                                          flagsubstituteid      flag.flag_id%TYPE,
                                          flagreplacementid     flag.flag_id%TYPE,
                                          invoiceReplacements   INT,
                                          invoiceSubstitutes    INT,
                                          repl_ToBeCharged      wearerinventory.repl_stilltobecharged%TYPE,
                                          sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE);

  FUNCTION getPLPC(customerID            customer.customer_id%TYPE,
                   productID             product.product_id%TYPE,
                   sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                   finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                   sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                   inactivePLPC          INT,
                   sqonwearerlevel       INT,
                   v_billingMethod       OUT productlistpercustomer.billingMethod%TYPE,
                   seasontypeID          OUT seasontype.seasontype_id%TYPE,
                   emblemTemplateID      IN OUT emblemtemplate.emblemtemplate_id%TYPE,
                   v_depositStockAllowed OUT productlistpercustomer.depositStockAllowed%TYPE,
                   v_percAfterDeprec     OUT productlistpercustomer.percentageafterdepreciation%TYPE,
                   plpcID                OUT productlistpercustomer.productlistpercustomer_id%TYPE,
                   isActive              OUT BOOLEAN,
                   v_inventoryBillingType OUT productlistpercustomer.inventoryBillingType%TYPE,
                   v_seasonalRent        OUT productlistpercustomer.seasonalrent%TYPE) RETURN BOOLEAN;

  PROCEDURE insertValuesIntoSqItemInCirc(sqItemInCirculationID    IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                         sqHeaderID               statusquoheader.statusquoheader_id%TYPE,
                                         customerID               customer.customer_id%TYPE,
                                         departmentID             department.department_id%TYPE,
                                         distributionPointID      distributionpoint.distributionpoint_id%TYPE,
                                         wearerEmploymentID       weareremployment.weareremployment_id%TYPE,
                                         productID                product.product_id%TYPE,
                                         sizeDefinitionID         sizedefinition.sizedefinition_id%TYPE,
                                         finishingMethodID        finishingmethod.finishingmethod_id%TYPE,
                                         v_maxinv                 wearerinventory.maxinventory%TYPE,
                                         v_qtytotal               sqitemincirculation.totalcircinv%TYPE,
                                         v_changesPerWeek         wearerinventory.changesPerWeek%TYPE,
                                         v_maxFreeOfCharge        wearerinventory.maxFreeOfCharge%TYPE,
                                         v_qtyfree                sqitemincirculation.freeissuedcircinv%TYPE,
                                         v_cogcircinv             sqitemincirculation.cogcircinv%TYPE,
                                         v_qtyfreeseason          sqitemincirculation.freeseasoncircinv%TYPE,
                                         v_beyondlifetypecirc     sqitemincirculation.beyondlifetimecirc%TYPE,
                                         v_qtyrentedperpiece      sqitemincirculation.qtyrentedperpiece%TYPE,
                                         v_qtyrentother           sqitemincirculation.qtyrentedother%TYPE,
                                         v_qtycustrentstop        sqitemincirculation.qtycustomerrentstop%TYPE,
                                         v_qtyrentstop            sqitemincirculation.qtyrentstop%TYPE,
                                         emblemTemplateID         emblemtemplate.emblemtemplate_id%TYPE,
                                         v_qtyrentemblem          sqitemincirculation.qtyrentemblem%TYPE,
                                         v_qtyreplacement         sqitemincirculation.qtyreplacement%TYPE,
                                         v_qtyassigned            sqitemincirculation.qtyassigned%TYPE,
                                         v_qtyrenteddepositstock  sqitemincirculation.qtyrenteddepositstock%TYPE,
                                         v_qtysubstitute          sqitemincirculation.qtysubstitute%TYPE,
                                         v_chargeafterdepreciation VARCHAR2,
                                         v_qtyrentedperpiecepool  sqitemincirculation.qtyrentedperpiecepool%TYPE,
                                         v_qtyrentedreturnrent    sqitemincirculation.qtyrentedreturnrent %TYPE,
                                         v_qtyrentedminrent       sqitemincirculation.qtyrentedminrent%TYPE,
                                         v_qtyfullyamortized      sqitemincirculation.qtyfullyamortized%TYPE);

  --PROCEDURE initializePLPC;

  PROCEDURE updatePLPC(plpcid                productlistpercustomer.productlistpercustomer_id%TYPE,
                       qtytotalcircinv       sqitemincirculation.totalcircinv%TYPE,
                       qtyrentedperpiece     sqitemincirculation.qtyrentedperpiece%TYPE,
                       qtyrentother          sqitemincirculation.qtyrentedother%TYPE,
                       qtyrenteddepositstock sqitemincirculation.qtyrenteddepositstock%TYPE,
						chargeafterdepreciation sqitemincirculation.chargeafterdepreciation%TYPE,
                       qtybeyondlifetimecirc sqitemincirculation.beyondlifetimecirc%TYPE);

  PROCEDURE createSQItemInCircOnUniqueItem(sqHeaderID          statusquoheader.statusquoheader_id%TYPE,
                                           processBUID         businessunit.businessunit_id%TYPE,
                                           invoiceBUID         businessunit.businessunit_id%TYPE,
                                           sizeStarID          sizedefinition.sizedefinition_id%TYPE,
                                           checkInvoiceBu      INT,
                                           sqonwearerlevel     INT,
                                           inactiveplpc        INT,
                                           flagSubstituteID    INT,
                                           flagReplacementID   INT,
                                           stayDepositStockID  INT,
                                           invoicereplacements INT,
                                           invoicesubstitutes  INT);

  FUNCTION getStatusID(vstatustype status.statustype %TYPE,
                       vstatuscode status.code%TYPE)
    RETURN status.status_id%TYPE;

  PROCEDURE createSqItemInCircOnUniqueRent(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                           processBuID                  businessunit.businessunit_id%TYPE,
                                           invoiceBuID                  businessunit.businessunit_id%TYPE,
                                           statusidforuniqueiteminstock status.status_id%TYPE,
                                           sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                           checkInvoiceBu               INT,
                                           sqOnWearerLevel              INT,
                                           inactivePLPC                 INT);

  FUNCTION getSqItemInCircOnUiRentForStmt(sqHeaderID          statusquoheader.statusquoheader_id%TYPE,
                                          distributionPointID weareremployment.distributionpoint_id%TYPE,
                                          wearerEmploymentID  weareremployment.weareremployment_id%TYPE,
                                          productID           uniqueitem.product_id%TYPE,
                                          sizeDefinitionID    uniqueitem.sizedefinition_id%TYPE,
                                          finishingMethodID   INT)
    RETURN sqitemincirculation.sqitemincirculation_id%TYPE;

  PROCEDURE createOrStoreOnSqForUiRent(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                       customerID            customer.customer_id%TYPE,
                                       departmentID          department.department_id%TYPE,
                                       distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                       productID             product.product_id%TYPE,
                                       sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                       finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                       wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                       sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                       noOfUniqueItems       INT,
                                       inactivePLPC          INT,
                                       sizeStarID            sizedefinition.sizedefinition_id%TYPE);

  FUNCTION getStayID(vStayType stay.staytype %TYPE,
                     vStayNr   stay.staynr%TYPE) RETURN stay.stay_id%TYPE;

  PROCEDURE createOrStoreOnSQforUniqueItem(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                           inactivePLPC          INT,
                                           customerID            customer.customer_id%TYPE,
                                           departmentID          department.department_id%TYPE,
                                           distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                           productID             product.product_id%TYPE,
                                           sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                           finishingMethodID     IN OUT finishingmethod.finishingmethod_id%TYPE,
                                           wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                           emblemTemplateID      IN OUT emblemtemplate.emblemtemplate_id%TYPE,
                                           sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                                           invoiceReplacements   INT,
                                           invoiceSubstitutes    INT,
                                           sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                           sqOnWearerLevel       INT,
                                           qtyTotal              IN OUT sqitemincirculation.totalcircinv%TYPE, --countNUI
                                           qtyCOG                IN OUT sqitemincirculation.cogcircinv%TYPE, --countCustomerOwnedUI
                                           qtyAssigned           IN OUT sqitemincirculation.qtyassigned%TYPE, --countQtyAssigned
                                           qtyFree               IN OUT sqitemincirculation.freeissuedcircinv%TYPE, --countExtraGarmentUI
                                           qtyCustRentStop       IN OUT sqitemincirculation.qtycustomerrentstop%TYPE, --countCustomerRentStop
                                           qtyRentStop           IN OUT sqitemincirculation.qtyrentstop%TYPE, --countWearerInvRentStop
                                           qtyFreeSeason         IN OUT sqitemincirculation.freeseasoncircinv%TYPE, --countQtyFreeSeason
                                           qtyReplacement        IN OUT sqitemincirculation.qtyreplacement%TYPE, --countQtyReplacement
                                           qtySubstitute         IN OUT sqitemincirculation.qtysubstitute%TYPE, --countQtySubstitute
                                           qtyDepositStock       IN OUT sqitemincirculation.qtyrenteddepositstock%TYPE, -- countQtyRentDepositStock
                                           qtyBeyondLifeTime     IN OUT sqitemincirculation.beyondlifetimecirc%TYPE, --countFullRentUI
                                           qtyLease              IN OUT sqitemincirculation.qtyrentedother%TYPE, --countQtyLease
                                           qtyFullyAmortized     IN OUT sqitemincirculation.qtyfullyamortized%TYPE, --countQtyFullyAmortized
                                           qtyRentedPerPiecePool IN OUT sqitemincirculation.qtyrentedperpiecepool%TYPE);

  FUNCTION getFinMethodFromWearerInv(distributionPointID distributionpoint.distributionpoint_id%TYPE,
                                     productID           product.product_id%TYPE,
                                     sizeDefinitionID    sizedefinition.sizedefinition_id%TYPE,
                                     wearerEmploymentID  weareremployment.weareremployment_id%TYPE,
                                     sqonwearerlevel     INT)
    RETURN finishingmethod.finishingmethod_id%TYPE;

  FUNCTION getWearerEmploymentLinkID(wearerEmploymentID weareremployment.weareremployment_id%TYPE)
    RETURN weareremployment.weareremployment_id%TYPE;

  PROCEDURE createOrStoreOnSqForPoolItems(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                       customerID            customer.customer_id%TYPE,
                                       departmentID          department.department_id%TYPE,
                                       distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                       wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                       productID             product.product_id%TYPE,
                                       sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                       finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                       sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                       noOfUniqueItems       INT,
                                       qtyRentStop INT);

  PROCEDURE createSqItemInCircForPoolItems(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                           processBuID                  businessunit.businessunit_id%TYPE,
                                           invoiceBuID                  businessunit.businessunit_id%TYPE,
                                           sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                           checkInvoiceBu               INT);
  PROCEDURE createSqItemInCircForPoolDummy(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                               processBuID                  businessunit.businessunit_id%TYPE,
                                               invoiceBuID                  businessunit.businessunit_id%TYPE,
                                               sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                               checkInvoiceBu               INT);
  PROCEDURE createSqItemInCircOnReturnRent(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                           sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                           sqonwearerlevel              INT,
                                           inactivePLPC                 INT);
  PROCEDURE createOrStoreOnSqOnReturnRent(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                         inactivePLPC          INT,
                                         customerID            customer.customer_id%TYPE,
                                         departmentID          department.department_id%TYPE,
                                         distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                         wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                         productID             product.product_id%TYPE,
                                         sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                         sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                         finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                         sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                         noOfUniqueItems       INT,
                                         returnrenttype        INT);


END pack_sqitemsincirculation_OLD;

/
create or replace PACKAGE BODY pack_sqitemsincirculation_OLD IS
  sq_systemUserid systemUser.systemUser_id%TYPE;
  sq_date         DATE;
  sq_year         INT;
  sq_week         INT;
  sq_plantId      plant.plant_id%TYPE;

PROCEDURE write_log(fp_err_msg  IN VARCHAR2,
                      fp_priority IN NUMBER DEFAULT 1) IS
  BEGIN
    /* writes logs into database.
    priority
    1 = Message
    2 = Warning
    3 = Error
    4 = Stack trace
    5 = Debug info  */
    abslogwrite.abslog_write(5,
                             'Pack_SQItemInCirculation',
                             NULL,
                             fp_priority,
                             fp_err_msg,
                             sq_systemUserid);
  END write_log;

  PROCEDURE createSqItemsInCirculation(sqHeaderID          OUT statusquoheader.statusquoheader_id%TYPE,
                                       processBuID         businessunit.businessunit_id%TYPE,
                                       invoiceBuID         businessunit.businessunit_id%TYPE,
                                       sqDate              DATE,
                                       sqYear              INT,
                                       sqWeek              INT,
                                       sqMonth             INT,
                                       sqSubType           INT,
                                       systemUserID        systemUser.systemUser_id%TYPE,
                                       checkInvoiceBu      INT,
                                       useRentOnStock      INT,
                                       inactivePLPC        INT,
                                       plantID             plant.plant_id%TYPE,
                                       invoiceReplacements INT,
                                       invoiceSubstitutes  INT,
                                       sqOnWearerLevel     INT,
                                       useRentBasedOnReturnWeeks INT,
                                       settlementActive          INT,
                                       chargeReplacedProduct     INT,
                                       abslogprocessjob INT) IS

    sizeStarID                   sizedefinition.sizedefinition_id%TYPE;
    flagSubstituteID             flag.flag_id%TYPE;
    flagReplacementID            flag.flag_id%TYPE;
    flagEvent                    VARCHAR(1000);
    statusIDforUniqueItemInStock status.status_id%TYPE;
    stayDepositStockID           stay.stay_id%TYPE;

  BEGIN

    sq_systemUserid := systemUserID;
    sq_date         := sqDate;
    sq_year         := sqYear;
    sq_week         := sqWeek;
    sq_plantId      := plantID;

    -- size *
    SELECT sizedefinition_id
      INTO sizeStarID
      FROM sizedefinition
     WHERE code = '*';

    --autoflag substitute
    SELECT a.event
      INTO flagEvent
      FROM automaticflag a
     WHERE a.automaticflag_id = automaticflag_substitute;
    SELECT af.flag_id
      INTO flagSubstituteID
      FROM automaticflag af
     WHERE af.event = flagEvent;
		 
    --autoflag replacement
    SELECT a.event
      INTO flagEvent
      FROM automaticflag a
     WHERE a.automaticflag_id = automaticflag_replacement;
    SELECT af.flag_id
      INTO flagEvent
      FROM automaticflag af
     WHERE af.event = flagEvent;

    --status_id for UI In stock (used for createSQItemInCircOnUniqueRent )
    statusIDforUniqueItemInStock := getStatusID('UI',
                                                '10');

    stayDepositStockID := getStayID(STAY_TYPE_GARMENT,
                                    STAY_NR_DEPOSITSTOCK);

    --system setting underuseMethodSS
    select ss.value
    into underuseMethodSS
    from systemsetting ss
    where upper(ss.name) like upper( 'UNDERUSEMETHOD')
    and ss.groupname = 'Billing'
    and ss.plant_id = plantID;

    --system setting bm3MaxInvReduceDepositSS
    select ss.value
    into bm3MaxInvReduceDepositSS
    from systemsetting ss
    where upper(ss.name) like upper( 'BM3MAXINVREDUCEDEPOSIT')
    and ss.groupname = 'Billing'
    and ss.plant_id = plantID;

    -- StatusQuoHeader

BEGIN
     delete statusquoheader sh
     where sh.year = sqYear
     and sh.week = sqWeek
     and sh.processbusinessunit_id = processBuID
     and sh.invoicebusinessunit_id = invoiceBuID
     and sh.STATUSQUOTYPE = 1
     and sh.totalquantity = 0;
    INSERT INTO statusquoheader
      (statusquoheader_id,
       processbusinessunit_id,
       invoicebusinessunit_id,
       statusquodate,
       statusquotype,
       totalquantity,
       YEAR,
       week,
       MONTH,
       SUBTYPE,
       abslogprocessjob_id,
       systemUser_id,
       TIMESTAMP)
    VALUES
      (seq_statusquoheader.NEXTVAL,
       processBuID,
       invoiceBuID,
       sqDate,
       SQ_ITEMS_IN_CIRCULATION,
       0,
       sqYear,
       sqWeek,
       sqMonth,
       sqSubType,
       decode (abslogprocessjob, 0 , null, abslogprocessjob),
       sq_systemUserid,
       SYSDATE)
    RETURNING statusquoheader_id INTO sqHeaderID;
EXCEPTION
WHEN OTHERS THEN
write_log ('Creating a new statusquoheader record for processed BU' || processBuID  || ' , invoiced BU' || invoiceBuID ||' , statusquodate ' || sqDate || ' and system user '|| sq_systemUserid || '  has failed! Please check your data! ', 3);
commit;
raise DUP_VAL_ON_INDEX;
END;

   --initialize plpc with 0
   --initializePLPC(); --initialization is done in Java Code

    -- createSQItemInCirc based on Wearer Inventory
    createSqItemInCircOnWearerInv(sqHeaderID,
                                  processBuID,
                                  invoiceBuID,
                                  checkInvoiceBu,
                                  inactivePLPC,
                                  sizeStarID,
                                  flagSubstituteID,
                                  flagReplacementID,
                                  invoiceReplacements,
                                  invoiceSubstitutes,
                                  chargeReplacedProduct,
                                  sqOnWearerLevel);

    -- createSQItemInCirc based on Unique Items
    createSQItemInCircOnUniqueItem(sqHeaderID,
                                   processBUID,
                                   invoiceBUID,
                                   sizeStarID,
                                   checkInvoiceBu,
                                   sqOnWearerLevel,
                                   inactiveplpc,
                                   flagSubstituteID,
                                   flagReplacementID,
                                   stayDepositStockID,
                                   invoicereplacements,
                                   invoicesubstitutes);

    -- createSQItemInCirc based on Unique Item (for Pool items)
  createSqItemInCircForPoolItems(sqHeaderID,
                                     processBuID,
                                     invoiceBuID,
                                     sizeStarID,
                                     checkInvoiceBu);
    -- createSQItemInCirc based on Unique Item (for Non Pool items - based on Wearer Dummy for Pool)
    createSqItemInCircForPoolDummy(sqHeaderID,
                                     processBuID,
                                     invoiceBuID,
                                     sizeStarID,
                                     checkInvoiceBu);

    -- createSQItemInCirc based on Unique Item for Rent
    IF (useRentOnStock = 1) THEN
      --useRentOnStock = true
      createSqItemInCircOnUniqueRent(sqHeaderID,
                                     processBuID,
                                     invoiceBuID,
                                     statusIDforUniqueItemInStock,
                                     sizeStarID,
                                     checkInvoiceBu,
                                     sqOnWearerLevel,
                                     inactivePLPC);
    END IF;

    -- createSQItemInCirc based on Unique Item Return Rent
    IF (useRentBasedOnReturnWeeks = 1 AND settlementActive = 0) THEN
        createSqItemInCircOnReturnRent(sqHeaderID,
                                     sizeStarID,
                                     sqOnWearerLevel,
                                     inactiveplpc);

    END IF;

    -- update StatusQuoHeader.totalquantity
BEGIN
    UPDATE statusquoheader
       SET totalquantity = (SELECT nvl(SUM(sqitemincirculation.totalcircinv),
                                       0)
                              FROM sqitemincirculation
                             WHERE sqitemincirculation.statusquoheader_id =
                                   statusquoheader.statusquoheader_id)
     WHERE statusquoheader_id = sqHeaderID;

     COMMIT;

EXCEPTION
WHEN OTHERS THEN
write_log(' Totalquantity in statusquoheader table for statusquoheader id '|| sqHeaderID|| '  was not updated correctly. Please check! ' );
commit;
END;

  END createSqItemsInCirculation;

 FUNCTION getPLPC(customerID            customer.customer_id%TYPE,
                   productID             product.product_id%TYPE,
                   sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                   finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                   sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                   inactivePLPC          INT,
                   sqOnWearerLevel       INT,
                   v_billingMethod       OUT productlistpercustomer.billingMethod%TYPE,
                   seasontypeID          OUT seasontype.seasontype_id%TYPE,
                   emblemTemplateID      IN OUT emblemtemplate.emblemtemplate_id%TYPE,
                   v_depositStockAllowed OUT productlistpercustomer.depositStockAllowed%TYPE,
                   v_percAfterDeprec     OUT productlistpercustomer.percentageafterdepreciation%TYPE,
                   plpcID                OUT productlistpercustomer.productlistpercustomer_id%TYPE,
                   isActive              OUT BOOLEAN,
                   v_inventoryBillingType OUT productlistpercustomer.inventoryBillingType%TYPE,
                   v_seasonalRent         OUT productlistpercustomer.seasonalrent%TYPE) RETURN BOOLEAN IS
    v_dateInactive DATE;
    customerNr     customer.customernumber%TYPE;
    productCode    product.code%TYPE;
    sizeCode       sizedefinition.code%TYPE;
    finmethCode    finishingmethod.code%TYPE;
    v_emblemTemplateID emblemtemplate.emblemtemplate_id%TYPE:= -1;

  BEGIN
    BEGIN
      IF inactivePLPC <> 2 THEN
        SELECT x1.billingMethod,
               nvl(x1.emblemtemplate_id, -1),
               x1.depositStockAllowed,
               x1.percentageafterdepreciation,
               x1.dateinactive,
               x1.productlistpercustomer_id,
               x1.inventoryBillingType,
               x1.seasonalrent
         INTO  v_billingMethod,
               v_emblemTemplateID,
               v_depositStockAllowed,
               v_percAfterDeprec,
               v_dateInactive,
               plpcID,
               v_inventoryBillingType,
               v_seasonalRent
          FROM productlistpercustomer x1
         WHERE x1.productlistpercustomer_id =(
             select coalesce((select x.productlistpercustomer_id
                      FROM productlistpercustomer x
                         WHERE x.customer_id = customerID
                           AND x.product_id = productID
                           AND x.sizedefinition_id = sizeDefinitionID
                           AND x.finishingmethod_id = finishingMethodID
                           AND x.dateactive <= sq_date
                           AND x.dateinactive > sq_date)
                  ,
                      (select x.productlistpercustomer_id
                          FROM productlistpercustomer x, sizedefinition sz
                             WHERE x.customer_id = customerID
                               AND x.product_id = productID
                               and x.sizedefinition_id = sz.sizedefinition_id
                               AND x.sizedefinition_id = sizeStarID
                               AND x.finishingmethod_id = finishingMethodID
                               AND x.dateactive <= sq_date
                               AND x.dateinactive > sq_date)
                   ,
                      (select x.productlistpercustomer_id
                      FROM productlistpercustomer x
                         WHERE x.customer_id = customerID
                           AND x.product_id = productID
                           AND x.sizedefinition_id = sizeDefinitionID
                           AND x.finishingmethod_id = finishingMethodID
                           AND x.dateactive <= sq_date
                           AND x.dateinactive =  (SELECT MAX(productlistpercustomer.dateinactive)
                                                  FROM productlistpercustomer
                                                 WHERE customer_id = customerID
                                                   AND product_id = productID
                                                   AND sizedefinition_id = sizeDefinitionID
                                                   AND finishingmethod_id = finishingMethodID
                                                   AND productlistpercustomer.dateactive <= sq_date))
                  ,
                      (select x.productlistpercustomer_id
                          FROM productlistpercustomer x, sizedefinition sz
                             WHERE x.customer_id = customerID
                               AND x.product_id = productID
                               and x.sizedefinition_id = sz.sizedefinition_id
                               AND x.sizedefinition_id = sizeStarID
                               AND x.finishingmethod_id = finishingMethodID
                               AND x.dateactive <= sq_date
                               AND x.dateinactive =  (SELECT MAX(productlistpercustomer.dateinactive)
                                                      FROM productlistpercustomer
                                                     WHERE customer_id = customerID
                                                       AND product_id = productID
                                                       AND sizedefinition_id = sizeStarID
                                                       AND finishingmethod_id = finishingMethodID
                                                       AND productlistpercustomer.dateactive <= sq_date))

                    ) from dual);
      ELSE
        SELECT x1.billingMethod,
               nvl(x1.emblemtemplate_id, -1),
               x1.depositStockAllowed,
               x1.percentageafterdepreciation,
               x1.dateinactive,
               x1.productlistpercustomer_id,
               x1.inventoryBillingType,
               x1.seasonalrent
          INTO v_billingMethod,
               v_emblemTemplateID,
               v_depositStockAllowed,
               v_percAfterDeprec,
               v_dateInactive,
               plpcID,
               v_inventoryBillingType,
               v_seasonalRent
          FROM productlistpercustomer x1/*, sizedefinition sz
             WHERE x.customer_id = customerID
               AND x.product_id = productID
               and x.sizedefinition_id = sz.sizedefinition_id
               AND (x.sizedefinition_id = sizeDefinitionID or
                   x.sizedefinition_id = sizeStarID)
               AND x.finishingmethod_id = finishingMethodID
               AND x.dateactive <= sq_date
               AND x.dateinactive >= sq_date
               order by sz.code desc*/
                WHERE x1.productlistpercustomer_id =(
             select coalesce((select x.productlistpercustomer_id
                      FROM productlistpercustomer x
                         WHERE x.customer_id = customerID
                           AND x.product_id = productID
                           AND x.sizedefinition_id = sizeDefinitionID
                           AND x.finishingmethod_id = finishingMethodID
                           AND x.dateactive <= sq_date
                           AND x.dateinactive > sq_date)
                  ,
                      (select x.productlistpercustomer_id
                          FROM productlistpercustomer x
                             WHERE x.customer_id = customerID
                               AND x.product_id = productID
                               AND x.sizedefinition_id = sizeStarID
                               AND x.finishingmethod_id = finishingMethodID
                               AND x.dateactive <= sq_date
                               AND x.dateinactive > sq_date))
                  from dual);
      END IF;

      IF (sqOnWearerLevel = 0 and v_emblemTemplateID > 0) THEN
        emblemTemplateID := v_emblemTemplateID;
      END IF;
      IF (v_dateInactive > sq_date) THEN
        isActive := TRUE;
      ELSE
        isActive := FALSE;
      END IF;
    EXCEPTION
      WHEN no_data_found THEN
        BEGIN
         -- out parameters, set up with default values
          v_billingMethod       := -1;
          seasontypeID          := -1;
          v_depositStockAllowed := 'N';
          v_percAfterDeprec     := 0;
          plpcID                := -1;
          isActive              := FALSE;
          v_inventoryBillingType  := -1;
          emblemTemplateID      := -1;
          v_seasonalRent        := 0;
          SELECT cu.customernumber
            INTO customerNr
            FROM customer cu
           WHERE cu.customer_id = customerID;
          SELECT pr.code
            INTO productCode
            FROM product pr
           WHERE pr.product_id = productID;
          SELECT sz.code
            INTO sizeCode
            FROM sizedefinition sz
           WHERE sz.sizedefinition_id = sizeDefinitionID;
          SELECT fm.code
            INTO finmethCode
            FROM finishingmethod fm
           WHERE fm.finishingmethod_id = finishingMethodID;
          /*write_log('No active PLPC was found for customer ' || customerNr ||
                    ' productCode ' || productCode || ' sizeCode ' ||
                    sizeCode || ' finmeth ' || finmethCode || ' in date ' ||
                    sq_date || ' . Inactive date for PLPC is ' ||
                    v_dateInactive,
                    3);*/
          RETURN FALSE;
        END;
    END;
    BEGIN
      SELECT a.seasontype_id
        INTO seasontypeID
        FROM seasontype a, productlistpercustomer plpc
       WHERE a.seasontype_id = plpc.seasontype_id
             AND plpc.productlistpercustomer_id = plpcID
             AND a.active = 'Y'
            /* AND NOT EXISTS (SELECT b.seasontype_id
                FROM season b, seasonweek c
               WHERE a.seasontype_id = b.seasontype_id
                     AND b.season_id = c.season_id
                     AND c.weeknumber = sq_week)*/;
    EXCEPTION
      WHEN no_data_found THEN
        seasontypeID := -1;
    END;
    RETURN TRUE;
  END getPLPC;

  /*
   PROCEDURE initializePLPC IS
    CURSOR stmt IS
      SELECT plpc.productlistpercustomer_id
        FROM product                p,
             productgroup           pg,
             customeractivities     ca,
             businessunit           bu,
             productlistpercustomer plpc
       WHERE p.product_id = plpc.product_id
             AND pg.productgroup_id = p.productgroup_id
             AND pg.activity_id = ca.activity_id
             AND ca.customer_id = plpc.customer_id
             AND ca.processbusinessunit_id = bu.businessunit_id
             AND p.typeofmerchandise = TYPEOFMERCHANDISE_GARMENT
             AND bu.plant_id = sq_plantID;
  BEGIN
    FOR rs IN stmt LOOP
      UPDATE productlistpercustomer plpc
         SET plpc.totalincirculation        = 0,
             plpc.totalincirculationcharged = 0,
             plpc.timestamp = sysdate,
             plpc.systemuser_id = sq_systemUserid
       WHERE plpc.productlistpercustomer_id = rs.productlistpercustomer_id;
    END LOOP;
  END initializePLPC;
*/

  PROCEDURE updatePLPC(plpcID                productlistpercustomer.productlistpercustomer_id%TYPE,
                       qtytotalcircinv       sqitemincirculation.totalcircinv%TYPE,
                       qtyrentedperpiece     sqitemincirculation.qtyrentedperpiece%TYPE,
                       qtyrentother          sqitemincirculation.qtyrentedother%TYPE,
                       qtyrenteddepositstock sqitemincirculation.qtyrenteddepositstock%TYPE,
					   chargeafterdepreciation sqitemincirculation.chargeafterdepreciation%TYPE,
                       qtybeyondlifetimecirc sqitemincirculation.beyondlifetimecirc%TYPE) IS
  BEGIN

BEGIN
    UPDATE productlistpercustomer plpc
       SET plpc.totalincirculation        = nvl(plpc.totalincirculation,
                                                0) +
                                            qtytotalcircinv,
           plpc.totalincirculationcharged = nvl(plpc.totalincirculationcharged,
                                                0) +
                                            qtyrentedperpiece +
                                            qtyrentother +
                                            qtyrenteddepositstock +
											decode(chargeafterdepreciation , 'Y', qtybeyondlifetimecirc,0)
           --plpc.timestamp = sysdate,
           --plpc.systemuser_id = sq_systemUserid
     WHERE plpc.productlistpercustomer_id = plpcID;

    COMMIT;

EXCEPTION
WHEN OTHERS THEN
write_log('Please check plpcID '|| plpcID || '  An error has occured and the information was not updated correctly! ');
commit;
END;

  END updatePLPC;

  -- createSQItemInCirc based on Unique Items
  PROCEDURE createSqItemInCircOnWearerInv(sqHeaderID          statusquoheader.statusquoheader_id%TYPE,
                                          processBuID         businessunit.businessunit_id%TYPE,
                                          invoiceBuID         businessunit.businessunit_id%TYPE,
                                          checkInvoiceBu      INT,
                                          inactivePLPC        INT,
                                          sizeStarID          sizedefinition.sizedefinition_id%TYPE,
                                          flagSubstituteID    flag.flag_id%TYPE,
                                          flagReplacementID   flag.flag_id%TYPE,
                                          invoiceReplacements INT,
                                          invoiceSubstitutes  INT,
                                          chargeReplacedProduct INT,
                                          sqOnWearerLevel     INT) IS

    prevcustomerID          customer.customer_id%TYPE := -1;
    prevdepartmentID        department.department_id%TYPE := -1;
    prevdistributionPointID distributionpoint.distributionpoint_id%TYPE := -1;
    prevproductID           product.product_id%TYPE := -1;
    prevsizeDefinitionID    sizedefinition.sizedefinition_id%TYPE := -1;
    prevfinishingMethodID   finishingmethod.finishingmethod_id%TYPE := -1;
    sqItemInCirculationID   sqitemincirculation.sqitemincirculation_id%TYPE := -1;

    CURSOR stmtAcheckbu IS
      SELECT a.wearerinventory_id,
             d.department_id,
             c.distributionpoint_id,
             CASE sqOnWearerLevel
               WHEN 1 THEN
                nvl(b.weareremployment_id,
                    -1)
               ELSE
                -1
             END weareremploymentID,
             a.product_id,
             a.sizedefinition_id,
             a.finishingmethod_id,
             d.customer_id,
             CASE sqOnWearerLevel
               WHEN 1 THEN
                nvl(a.emblemtemplate_id,
                    -1)
               ELSE
                -1
             END emblemtemplateID,
             a.changesPerWeek,
             a.maxFreeOfCharge,
             CASE chargeReplacedProduct
               WHEN 1 THEN
                 nvl(a.repl_stilltobecharged, 'Y')
               ELSE
                 'N'
             END repl_stilltobecharged
        FROM wearerinventory    a,
             weareremployment   b,
             distributionpoint  c,
             department         d,
             product            e,
             productgroup       f,
             customeractivities g
       WHERE a.weareremployment_id = b.weareremployment_id
             AND b.distributionpoint_id = c.distributionpoint_id
             AND c.department_id = d.department_id
             AND a.product_id = e.product_id
             AND e.productgroup_id = f.productgroup_id
             AND abs(f.activity_id) = abs(g.activity_id)
             AND d.customer_id = g.customer_id
             AND g.processbusinessunit_id = processBuID
             AND
             (checkinvoicebu = 0 OR g.invoicebusinessunit_id = invoiceBuID)
       ORDER BY d.customer_id,
                c.distributionpoint_id,
                a.product_id,
                a.sizedefinition_id,
                a.finishingmethod_id,
                d.department_id;

  BEGIN
    --  IF (checkInvoiceBu = 1) THEN
    FOR rs IN stmtAcheckbu LOOP
      IF (sqOnWearerLevel = 1 OR
         NOT (prevcustomerID = rs.customer_id AND
          prevdepartmentID = rs.department_id AND
          prevdistributionPointID = rs.distributionpoint_id AND
          prevproductID = rs.product_id AND
          prevfinishingMethodID = rs.finishingmethod_id AND
          prevsizeDefinitionID = rs.sizedefinition_id)) THEN
        sqItemInCirculationID := -1;
      END IF;
      createOrStoreOnSqForWearerInv(sqHeaderID,
                                    inactivePLPC,
                                    sqOnWearerLevel,
                                    rs.wearerinventory_id,
                                    rs.customer_id,
                                    rs.department_id,
                                    rs.distributionpoint_id,
                                    rs.product_id,
                                    rs.sizedefinition_id,
                                    rs.finishingmethod_id,
                                    rs.weareremploymentID,
                                    rs.changesPerWeek,
                                    rs.maxFreeOfCharge,
                                    rs.emblemtemplateID,
                                    sizeStarID,
                                    flagSubstituteID,
                                    flagReplacementID,
                                    invoiceReplacements,
                                    invoiceSubstitutes,
                                    rs.repl_stilltobecharged,
                                    sqItemInCirculationID);
    END LOOP;
    /* ELSE
      FOR rs IN stmtA LOOP
        IF (sqOnWearerLevel = 1 OR
           NOT (prevcustomerID = rs.customer_id AND
            prevdepartmentID = rs.department_id AND
            prevdistributionPointID = rs.distributionpoint_id AND
            prevproductID = rs.product_id AND
            prevfinishingMethodID = rs.finishingmethod_id AND
            prevsizeDefinitionID = rs.sizedefinition_id)) THEN
          sqItemInCirculationID := -1;
        END IF;
        createOrStoreOnSqForWearerInv(sqHeaderID,
                                      inactivePLPC,
                                      rs.wearerinventory_id,
                                      rs.customer_id,
                                      rs.department_id,
                                      rs.distributionpoint_id,
                                      rs.product_id,
                                      rs.sizedefinition_id,
                                      rs.finishingmethod_id,
                                      rs.weareremploymentID,
                                      rs.changesPerWeek,
                                      rs.maxFreeOfCharge,
                                      rs.emblemtemplateID,
                                      sizeStarID,
                                      flagSubstituteID,
                                      flagReplacementID,
                                      invoiceReplacements,
                                      invoiceSubstitutes,
                                      sqItemInCirculationID);
      END LOOP;
    END IF; */

  END createSqItemInCircOnWearerInv;

  PROCEDURE createOrStoreOnSqForWearerInv(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                          inactivePLPC          INT,
                                          sqOnWearerLevel       INT,
                                          wearerinventoryID     wearerinventory.wearerinventory_id%TYPE,
                                          customerID            customer.customer_id%TYPE,
                                          departmentID          department.department_id%TYPE,
                                          distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                          productID             product.product_id%TYPE,
                                          sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                          finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                          wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                          changesPerWeek        wearerinventory.changesPerWeek%TYPE,
                                          maxFreeOfCharge       wearerinventory.maxFreeOfCharge%TYPE,
                                          emblemTemplateID      IN OUT emblemtemplate.emblemtemplate_id%TYPE,
                                          sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                                          flagSubstituteID      flag.flag_id%TYPE,
                                          flagReplacementID     flag.flag_id%TYPE,
                                          invoiceReplacements   INT,
                                          invoiceSubstitutes    INT,
                                          repl_ToBeCharged      wearerinventory.repl_stilltobecharged%TYPE,
                                          sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE) IS

    maxinv                 wearerinventory.maxinventory%TYPE := 0;
    qtytotal               sqitemincirculation.totalcircinv%TYPE := 0; --countNUI
    qtytotalcircinv        sqitemincirculation.totalcircinv%TYPE := 0;
    qtyassigned            sqitemincirculation.qtyassigned%TYPE := 0; --countQtyAssigned
    qtyfree                sqitemincirculation.freeissuedcircinv%TYPE := 0; --countFreeNUI
    qtycustrentstop        sqitemincirculation.qtycustomerrentstop%TYPE := 0; --countCustomerRentStop
    qtyrentstop            sqitemincirculation.qtyrentstop%TYPE := 0; --countWearerInvRentStop
    qtyfreeseason          sqitemincirculation.freeseasoncircinv%TYPE := 0; --countQtyFreeSeason
    qtyreplacement         sqitemincirculation.qtyreplacement%TYPE := 0; --countQtyReplacement
    qtysubstitute          sqitemincirculation.qtysubstitute%TYPE := 0; --countQtySubstitute
    foundplpc              BOOLEAN;
    billingMethod          productlistpercustomer.billingMethod%TYPE := -1;
    seasontypeid           seasontype.seasontype_id%TYPE := -1;
    depositStockAllowed    productlistpercustomer.depositStockAllowed%TYPE;
    percafterdeprec        productlistpercustomer.percentageafterdepreciation%TYPE := 0;
    plpcID                 productlistpercustomer.productlistpercustomer_id%TYPE := -1;
    isActive               BOOLEAN := FALSE;
    qtyrentedperpiece      sqitemincirculation.qtyrentedperpiece%TYPE := 0;
    qtyrentother           sqitemincirculation.qtyrentedother%TYPE := 0;
    qtyrentemblem          sqitemincirculation.qtyrentemblem%TYPE := 0;
    chargeafterdepreciation VARCHAR2(1);
    typeOfMerchandise      product.typeofmerchandise%TYPE;
    qtyReplacement_used    sqitemincirculation.qtyreplacement%TYPE := 0; --countQtyReplacement
    qtySubstitute_used     sqitemincirculation.qtysubstitute%TYPE := 0; --countQtySubstitute
    inventoryBillingType   productlistpercustomer.inventoryBillingType%TYPE := -1;
    seasonalRent           productlistpercustomer.seasonalrent%TYPE := 0;
    oldmaxinv              wearerinventory.maxinventory%TYPE := 0;
    foundOldmaxinv         BOOLEAN;
  BEGIN
          --find plpc for statusQuo.Date
      BEGIN
          foundplpc := getPLPC(customerID,
                               productID,
                               sizeDefinitionID,
                               finishingMethodID,
                               sizeStarID,
                               inactivePLPC,
                               sqOnWearerLevel,
                               billingMethod,
                               seasontypeid,
                               emblemTemplateID,
                               depositStockAllowed,
                               percAfterDeprec,
                               plpcID,
                               isActive,
                               inventoryBillingType, seasonalRent);
      EXCEPTION
      WHEN OTHERS THEN
      /*write_log('No active PLPC was found for customerID ' || customerID ||
                          ' productID ' || productID || ' sizeDefinitionID ' ||
                          sizeDefinitionID || ' finishingMethodID ' || finishingMethodID || ' in date ' ||
                          sq_date,
                          3);*/
                          commit;
      END;

    --calculate fields
    BEGIN
      SELECT coalesce((SELECT wi.maxinventory
                        FROM wearerinventory  wi,
                             weareremployment we,
                             wearer           w
                       WHERE wi.wearerinventory_id = wearerinventoryid
                             AND wi.weareremployment_id =
                             we.weareremployment_id
                             AND we.wearer_id = w.wearer_id
                             AND sq_date BETWEEN wi.dateactive AND
                             wi.dateinactive
                             AND sq_date BETWEEN w.dateactive AND
                             w.dateinactive
                             AND wi.circinventory > 0
                             AND ((sq_date < wi.temporaryrentstopstartdate OR
                             sq_date > temporaryrentstopenddate) OR
                             (nvl(wi.temporaryrentstopstartdate,
                                       to_date('01/01/0001',
                                               'dd/mm/yyyy')) =
                             to_date('01/01/0001',
                                           'dd/mm/yyyy') AND
                             nvl(wi.temporaryrentstopenddate,
                                       to_date('01/01/0001',
                                               'dd/mm/yyyy')) =
                             to_date('01/01/0001',
                                           'dd/mm/yyyy')))),
                      0)
        INTO maxinv
        FROM dual;
    EXCEPTION
      WHEN no_data_found THEN
        maxinv := 0;
    END;

    BEGIN
      SELECT COUNT(x.wearerinventory_id)
        INTO qtytotal
        FROM nonuniqueitem x
       WHERE x.wearerinventory_id = wearerinventoryid;
      qtytotalcircinv := qtytotal;
    EXCEPTION
      WHEN no_data_found THEN
        qtytotal        := 0;
        qtytotalcircinv := 0;
    END;

    BEGIN
      SELECT COUNT(x.wearerinventory_id)
        INTO qtyassigned
        FROM nonuniqueitem x
       WHERE x.wearerinventory_id = wearerinventoryid
             AND x.startrentdate > sq_date;
    EXCEPTION
      WHEN no_data_found THEN
        qtyassigned := 0;
    END;

    BEGIN
      SELECT COUNT(x.nonuniqueitem_id)
        INTO qtyfree
        FROM wearerinventory wi, nonuniqueitem x
       WHERE wi.wearerinventory_id = wearerinventoryid
             AND x.startrentdate <= sq_date
             AND wi.wearerinventory_id = x.wearerinventory_id
             AND x.freeitem = 'Y';
    EXCEPTION
      WHEN no_data_found THEN
        qtyfree := 0;
    END;

    BEGIN
      SELECT COUNT(t.temporarygarmentrentstop_id)
        INTO qtycustrentstop
        FROM temporarygarmentrentstop t
       WHERE t.customer_id = customerID
             AND f_isinyearweeklifespan(startyear,
                                        startweek,
                                        sq_year,
                                        sq_week,
                                        endyear,
                                        endweek) = 1;
    EXCEPTION
      WHEN no_data_found THEN
        qtycustrentstop := 0;
    END;

    BEGIN
      SELECT COUNT(x.nonuniqueitem_id)
        INTO qtyrentstop
        FROM wearerinventory wi, nonuniqueitem x
       WHERE wi.wearerinventory_id = wearerinventoryid
             AND wi.wearerinventory_id = x.wearerinventory_id
             AND x.startrentdate <= sq_date
             AND NOT (x.freeitem = 'Y')
             AND sq_date BETWEEN wi.temporaryrentstopstartdate AND
             wi.temporaryrentstopenddate;
    EXCEPTION
      WHEN no_data_found THEN
        qtyrentstop := 0;
    END;

    BEGIN
      SELECT COUNT(x.nonuniqueitem_id)
        INTO qtyfreeseason
        FROM wearerinventory wi, nonuniqueitem x
       WHERE wi.wearerinventory_id = wearerinventoryid
             AND wi.wearerinventory_id = x.wearerinventory_id
             AND x.startrentdate <= sq_date
             AND NOT (x.freeitem = 'Y')
             AND ((sq_date < wi.temporaryrentstopstartdate OR
             sq_date > temporaryrentstopenddate) OR
             (nvl(wi.temporaryrentstopstartdate,
                       to_date('01/01/0001',
                               'dd/mm/yyyy')) =
             to_date('01/01/0001',
                           'dd/mm/yyyy') AND
             nvl(wi.temporaryrentstopenddate,
                       to_date('01/01/0001',
                               'dd/mm/yyyy')) =
             to_date('01/01/0001',
                           'dd/mm/yyyy')))
             AND wi.season_id IS NOT NULL
             AND seasontypeid <> -1
             AND NOT EXISTS
       (SELECT sw.season_id
                FROM seasonweek sw
               WHERE sw.season_id = wi.season_id
                     AND sw.weeknumber = sq_week);
    EXCEPTION
      WHEN no_data_found THEN
        qtyfreeseason := 0;
    END;

    BEGIN
      SELECT COUNT(x.nonuniqueitem_id)
        INTO qtyreplacement
        FROM wearerinventory wi, nonuniqueitem x
       WHERE wi.wearerinventory_id = wearerinventoryid
             AND wi.wearerinventory_id = x.wearerinventory_id
             AND x.startrentdate <= sq_date
             AND NOT (x.freeitem = 'Y')
             AND ((sq_date < wi.temporaryrentstopstartdate OR
             sq_date > temporaryrentstopenddate) OR
             (nvl(wi.temporaryrentstopstartdate,
                       to_date('01/01/0001',
                               'dd/mm/yyyy')) =
             to_date('01/01/0001',
                           'dd/mm/yyyy') AND
             nvl(wi.temporaryrentstopenddate,
                       to_date('01/01/0001',
                               'dd/mm/yyyy')) =
             to_date('01/01/0001',
                           'dd/mm/yyyy')))
             AND (nvl(wi.season_id,0) = 0 OR ((seasontypeid <> -1 AND EXISTS
              (SELECT sw.season_id
                     FROM seasonweek sw
                    WHERE sw.season_id = wi.season_id
                          AND sw.weeknumber = sq_week))))
             AND x.flag_id = flagReplacementID --flagReplacement
             AND x.flagstartdate <= sq_date;
    EXCEPTION
      WHEN no_data_found THEN
        qtyreplacement := 0;
    END;

    BEGIN
      SELECT COUNT(x.nonuniqueitem_id)
        INTO qtysubstitute
        FROM wearerinventory wi, nonuniqueitem x
       WHERE wi.wearerinventory_id = wearerinventoryid
             AND wi.wearerinventory_id = x.wearerinventory_id
             AND x.startrentdate <= sq_date
             AND NOT (x.freeitem = 'Y')
             AND ((sq_date < wi.temporaryrentstopstartdate OR
             sq_date > temporaryrentstopenddate) OR
             (nvl(wi.temporaryrentstopstartdate,
                       to_date('01/01/0001',
                               'dd/mm/yyyy')) =
             to_date('01/01/0001',
                           'dd/mm/yyyy') AND
             nvl(wi.temporaryrentstopenddate,
                       to_date('01/01/0001',
                               'dd/mm/yyyy')) =
             to_date('01/01/0001',
                           'dd/mm/yyyy')))
             AND (nvl(wi.season_id,
                      0) = 0 OR ((seasontypeid <> -1 AND EXISTS
              (SELECT sw.season_id
                     FROM seasonweek sw
                    WHERE sw.season_id = wi.season_id
                          AND sw.weeknumber = sq_week))))
             AND x.flag_id = flagSubstituteID --falgSubstitute
             AND x.flagstartdate <= sq_date;
    EXCEPTION
      WHEN no_data_found THEN
        qtysubstitute := 0;
    END;


    --checks
    IF (foundplpc) THEN
      IF (isActive = FALSE AND inactivePLPC = 2) THEN
        qtytotalcircinv := 0;
      END IF;

      IF (qtycustrentstop > 0) THEN
        qtycustrentstop   := qtytotal;
        qtyrentstop       := 0;
        qtyfreeseason     := 0;
        qtyreplacement    := 0;
        qtysubstitute     := 0;
        qtyrentedperpiece := 0;
        qtyrentother      := 0;
        qtyrentemblem     := 0;
        maxinv            := 0;
      ELSE
        qtyrentother := 0;
        IF ((billingMethod = bill_circulating_inventory OR
            (billingMethod = BILL_RENT_BASED_MINIMUM AND underuseMethodSS = 4))
           AND (isActive OR inactivePLPC = 0)) THEN
          IF (billingMethod = bill_circulating_inventory and inventoryBillingType = 2 and repl_ToBeCharged = 'Y') THEN
            foundOldmaxinv := getOldMaxInventory(wearerinventoryid, oldmaxinv);
            IF (foundOldmaxinv and oldmaxinv > 0) THEN
               maxinv := oldmaxinv;
            END IF;
          END IF;
          IF (invoiceReplacements = 1) THEN
            qtyReplacement_used := 0;
          END IF;
          IF (invoiceSubstitutes = 1) THEN
            qtySubstitute_used := 0;
          END IF;

          IF (seasontypeid <> -1 and seasonalRent = 2) THEN
            qtyfreeseason := 0;
          END IF;
          qtyrentedperpiece := qtytotal - qtyassigned - qtyfree -
                               qtyrentstop - qtyfreeseason -
                               qtyReplacement_used - qtySubstitute_used;
          IF (emblemTemplateID <>-1) THEN
            qtyrentemblem := qtytotal - qtyassigned - qtyfree - qtyrentstop -
                             qtyfreeseason;
          END IF;
        ELSE
          qtyreplacement    := 0;
          qtysubstitute     := 0;
          qtyrentedperpiece := 0;
          IF (isActive OR inactivePLPC = 1) THEN
            IF (seasontypeid <> -1 and seasonalRent = 2) THEN
               qtyfreeseason := 0;
            END IF;
            qtyrentother := qtytotal - qtyassigned - qtyfree - qtyrentstop -
                            qtyfreeseason;
            IF (emblemTemplateID <>-1) THEN
              qtyrentemblem := qtytotal - qtyassigned - qtyfree -
                               qtyrentstop - qtyfreeseason;
            END IF;
          END IF;
        END IF;
        IF (qtyrentstop > 0) THEN
          maxinv            := 0;
        END IF;
      END IF;
      chargeafterdepreciation := 'N';
      IF (billingMethod = bill_circulating_inventory) AND
         percafterdeprec > 0 THEN
        chargeafterdepreciation := 'Y';
      END IF;
      IF (qtyrentedperpiece < 0) THEN
        qtyrentedperpiece := 0;
      END IF;
      IF (qtyrentother < 0) THEN
        qtyrentother := 0;
      END IF;
      IF (emblemTemplateID = -1) THEN
         emblemTemplateID := null;
      END IF;
      --insertion/update
      insertValuesIntoSqItemInCirc(sqItemInCirculationID,
                                   sqHeaderID,
                                   customerID,
                                   departmentID,
                                   distributionPointID,
                                   wearerEmploymentID,
                                   productID,
                                   sizeDefinitionID,
                                   finishingMethodID,
                                   maxinv,
                                   qtytotalcircinv, --countNUI
                                   changesPerWeek,
                                   maxFreeOfCharge,
                                   qtyfree,
                                   0, --COGCIRCINV
                                   qtyfreeseason,
                                   0, --BEYONDLIFETIMECIRC
                                   qtyrentedperpiece,
                                   qtyrentother,
                                   qtycustrentstop,
                                   qtyrentstop,
                                   emblemTemplateID,
                                   qtyrentemblem,
                                   qtyreplacement,
                                   qtyassigned,
                                   0, --QTYRENTEDDEPOSITSTOCK
                                   qtysubstitute, --QTYSUBSTITUTE
                                   chargeafterdepreciation,
                                   0, --QtyRentedPerPiecePool
                                   0,
                                   0, 0);

      --update plpc
      SELECT pr.typeofmerchandise
        INTO typeOfMerchandise
        FROM product pr
       WHERE pr.product_id = productID;

     IF (typeofMerchandise = TYPEOFMERCHANDISE_Garment) THEN
        updatePLPC(plpcID,
                   qtytotalcircinv,
                   qtyrentedperpiece,
                   qtyrentother,
                   0,
				   chargeafterdepreciation,
				   0);
      END IF;

    END IF;

  END createOrStoreOnSqForWearerInv;

  FUNCTION getOldMaxInventory(wearerinventoryID     wearerinventory.wearerinventory_id%TYPE,
                              oldMaxInv             OUT INT) RETURN BOOLEAN IS

  --Check if there are any items in circulation for replacement WO. If NOT, old max inventory should be taken into account
  --Update WearerInventory since it should not be invoiced anymore
    noOfItemsInCirc INT;

    BEGIN
      noOfItemsInCirc := 0;
      oldMaxInv :=0;
      BEGIN
        select count(1) lvresult
         into noOfItemsInCirc
         from wearerinventory     wi,
               workorderline       wol,
               uniqueitemfixedinfo uinp,
               uniqueitem          ui,
               status              s
         where wi.wearerinventory_id = wearerinventoryID
           and wol.oldwearerinventory_id = wearerinventoryID
           and ((wol.product_link_id <> wi.product_id)
                or (wol.product_link_id = wi.product_id
                    and wol.sizedefinition_link_id <> wi.sizedefinition_id))
           and uinp.issuedbyworkorder_id = wol.workorder_id
           and ui.uniqueitem_id = uinp.uniqueitem_id
           and ui.product_id = wol.product_link_id
           and ui.sizedefinition_id = wol.sizedefinition_link_id
           and s.status_id = ui.status_id
           and s.code = '20';
      END;
      write_log ('noOfItemsInCirc ' || noOfItemsInCirc  || ' , wearerinventoryID ' || wearerinventoryID , 3);

      IF (noOfItemsInCirc > 0) THEN
        BEGIN
          UPDATE wearerinventory wi
             SET wi.repl_stilltobecharged = 'N'
          WHERE wi.wearerinventory_id = wearerinventoryID;
          COMMIT;

          EXCEPTION
          WHEN OTHERS THEN
          write_log('Please check wearerinventoryID '|| wearerinventoryID || '  An error has occured and the information was not updated correctly! ');
          commit;
        END;
        RETURN FALSE;
      ELSE
        BEGIN
          select nvl(wi.old_maxinventory, 0)
          into oldMaxInv
          from wearerinventory     wi
          where wi.wearerinventory_id = wearerinventoryID;
        END;
      END IF;
      write_log('oldMaxInv ' || oldMaxInv  || ' , wearerinventoryID ' || wearerinventoryID , 3);
      RETURN TRUE;
  END getOldMaxInventory;


  PROCEDURE insertValuesIntoSqItemInCirc(sqItemInCirculationID    IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                         sqHeaderID               statusquoheader.statusquoheader_id%TYPE,
                                         customerID               customer.customer_id%TYPE,
                                         departmentID             department.department_id%TYPE,
                                         distributionPointID      distributionpoint.distributionpoint_id%TYPE,
                                         wearerEmploymentID       weareremployment.weareremployment_id%TYPE,
                                         productID                product.product_id%TYPE,
                                         sizeDefinitionID         sizedefinition.sizedefinition_id%TYPE,
                                         finishingMethodID        finishingmethod.finishingmethod_id%TYPE,
                                         v_maxinv                 wearerinventory.maxinventory%TYPE,
                                         v_qtytotal               sqitemincirculation.totalcircinv%TYPE,
                                         v_changesPerWeek         wearerinventory.changesPerWeek%TYPE,
                                         v_maxFreeOfCharge        wearerinventory.maxFreeOfCharge%TYPE,
                                         v_qtyfree                sqitemincirculation.freeissuedcircinv%TYPE,
                                         v_cogcircinv             sqitemincirculation.cogcircinv%TYPE,
                                         v_qtyfreeseason          sqitemincirculation.freeseasoncircinv%TYPE,
                                         v_beyondlifetypecirc     sqitemincirculation.beyondlifetimecirc%TYPE,
                                         v_qtyrentedperpiece      sqitemincirculation.qtyrentedperpiece%TYPE,
                                         v_qtyrentother           sqitemincirculation.qtyrentedother%TYPE,
                                         v_qtycustrentstop        sqitemincirculation.qtycustomerrentstop%TYPE,
                                         v_qtyrentstop            sqitemincirculation.qtyrentstop%TYPE,
                                         emblemTemplateID         emblemtemplate.emblemtemplate_id%TYPE,
                                         v_qtyrentemblem          sqitemincirculation.qtyrentemblem%TYPE,
                                         v_qtyreplacement         sqitemincirculation.qtyreplacement%TYPE,
                                         v_qtyassigned            sqitemincirculation.qtyassigned%TYPE,
                                         v_qtyrenteddepositstock  sqitemincirculation.qtyrenteddepositstock%TYPE,
                                         v_qtysubstitute          sqitemincirculation.qtysubstitute%TYPE,
                                         v_chargeafterdepreciation VARCHAR2,
                                         v_qtyrentedperpiecepool  sqitemincirculation.qtyrentedperpiecepool%TYPE,
                                         v_qtyrentedreturnrent    sqitemincirculation.qtyrentedreturnrent %TYPE,
                                         v_qtyrentedminrent       sqitemincirculation.qtyrentedminrent%TYPE,
                                         v_qtyfullyamortized      sqitemincirculation.qtyfullyamortized%TYPE) IS
    v_wearerEmploymentID weareremployment.weareremployment_id%TYPE;

  BEGIN
    v_wearerEmploymentID := getWearerEmploymentLinkID(wearerEmploymentID);

    IF (sqItemInCirculationID = -1) THEN
      BEGIN
        INSERT INTO sqitemincirculation
          (sqitemincirculation_id,
           statusquoheader_id,
           customer_link_id,
           department_link_id,
           distributionpoint_link_id,
           weareremployment_link_id,
           product_link_id,
           sizedefinition_link_id,
           finishingmethod_id,
           maxinv,
           totalcircinv,
           changesPerWeek,
           maxfreeinv,
           freeissuedcircinv,
           cogcircinv,
           freeseasoncircinv,
           beyondlifetimecirc,
           variationmaxinv,
           variationtotalcircinv,
           variationchangesPerWeek,
           variationmaxfreeinv,
           variationrentedperpiece,
           variationfreeissuedcircinv,
           variationcogcircinv,
           variationfreeseasoncircinv,
           variationbeyondlifetimecirc,
           systemUser_id,
           TIMESTAMP,
           qtyrentedperpiece,
           qtyrentedother,
           variationrentedother,
           qtycustomerrentstop,
           variationqtycustomerrentstop,
           qtyrentstop,
           variationqtyrentstop,
           emblemtemplate_id,
           qtyrentemblem,
           variationqtyrentemblem,
           qtyreplacement,
           variationqtyreplacement,
           qtyassigned,
           variationqtyassigned,
           qtyrenteddepositstock,
           variationrenteddepositstock,
           qtysubstitute,
           variationqtysubstitute,
           qtyrentedperpiecepool,
           variationrentedperpiecepool,
           chargeafterdepreciation,
           yearweek,
           qtyrentedreturnrent,
           variationqtyrentedreturnrent,
           qtyrentedminrent,
           variationqtyrentedminrent,
           qtyfullyamortized,
           variationqtyfullyamortized)
        VALUES
          (seq_sqitemincirculation.NEXTVAL,
           sqHeaderID,
           customerID,
           departmentID,
           distributionPointID,
           v_wearerEmploymentID,
           productID,
           sizeDefinitionID,
           finishingMethodID,
           v_maxinv,
           v_qtytotal,
           v_changesPerWeek,
           v_maxFreeOfCharge,
           v_qtyfree,
           v_cogcircinv,
           v_qtyfreeseason,
           v_beyondlifetypecirc,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0,
           0, --variation will be updated afterwords
           sq_systemUserid,
           SYSDATE,
           v_qtyrentedperpiece,
           v_qtyrentother,
           0, --variation
           v_qtycustrentstop,
           0, --variation
           v_qtyrentstop,
           0, --variation
           emblemTemplateID,
           v_qtyrentemblem,
           0, --variation
           v_qtyreplacement,
           0, --variation
           v_qtyassigned,
           0, --variation
           v_qtyrenteddepositstock,
           0, --variation
           v_qtysubstitute,
           0, --variation
           v_qtyrentedperpiecepool,
           0, --variation
           v_chargeafterdepreciation,
           sq_year * 100 + sq_week,
           v_qtyrentedreturnrent,
           0, --variation
           v_qtyrentedminrent,
           0, --variation
           v_qtyfullyamortized,
           0)
        RETURNING sqitemincirculation_id INTO sqItemInCirculationID;

      EXCEPTION
        WHEN dup_val_on_index THEN

BEGIN
          UPDATE sqitemincirculation
             SET maxinv                = maxinv + v_maxinv,
                 totalcircinv          = totalcircinv + v_qtytotal,
                 changesPerWeek        = changesPerWeek + v_changesPerWeek,
                 freeissuedcircinv     = freeissuedcircinv + v_qtyfree,
                 cogcircinv            = cogcircinv + v_cogcircinv,
                 freeseasoncircinv     = freeseasoncircinv + v_qtyfreeseason,
                 beyondlifetimecirc    = beyondlifetimecirc +
                                         v_beyondlifetypecirc,
                 qtyrentedperpiece     = qtyrentedperpiece +
                                         v_qtyrentedperpiece,
                 qtyrentedother        = qtyrentedother + v_qtyrentother,
                 qtycustomerrentstop   = qtycustomerrentstop +
                                         v_qtycustrentstop,
                 qtyrentstop           = qtyrentstop + v_qtyrentstop,
                 qtyrentemblem         = qtyrentemblem + v_qtyrentemblem,
                 qtyreplacement        = qtyreplacement + v_qtyreplacement,
                 qtyassigned           = qtyassigned + v_qtyassigned,
                 qtyrenteddepositstock = qtyrenteddepositstock +
                                         v_qtyrenteddepositstock,
                 qtysubstitute         = qtysubstitute + v_qtysubstitute,
                 qtyrentedperpiecepool = qtyrentedperpiecepool + v_qtyrentedperpiecepool,
                 qtyrentedreturnrent   = qtyrentedreturnrent + v_qtyrentedreturnrent,
                 qtyrentedminrent      = qtyrentedminrent + v_qtyrentedminrent,
                 qtyfullyamortized     = qtyfullyamortized + v_qtyfullyamortized,
                 systemUser_id         = sq_systemUserid,
                 TIMESTAMP             = SYSDATE
           WHERE statusquoheader_id = sqHeaderID
                 AND customer_link_id = customerID
                 AND department_link_id = departmentID
                 AND distributionpoint_link_id = distributionPointID
                 AND (weareremployment_link_id = v_wearerEmploymentID OR weareremployment_link_id IS NULL)
                 AND product_link_id = productID
                 AND sizedefinition_link_id = sizeDefinitionID
                 AND finishingmethod_id = finishingMethodID;
EXCEPTION
WHEN OTHERS THEN
write_log('Update record in Sqitemincirculation table for sqItemInCirculationID ' || sqItemInCirculationID || ' has failed for statusquoheader_id: ' || sqHeaderID || '  customerID ' || customerID|| ', departmentID '|| departmentID|| ', distributionPointID'
||distributionPointID || ' ,wearerEmploymentID '|| wearerEmploymentID || ' , productID' || productID|| ' ,sizeDefinitionID' || sizeDefinitionID || ' ,finishingMethodID '|| finishingMethodID || ' Please check!');
commit;
END;
      END;
    ELSE
BEGIN
      UPDATE sqitemincirculation
         SET maxinv                = maxinv + v_maxinv,
             totalcircinv          = totalcircinv + v_qtytotal,
             freeissuedcircinv     = freeissuedcircinv + v_qtyfree,
             cogcircinv            = cogcircinv + v_cogcircinv,
             freeseasoncircinv     = freeseasoncircinv + v_qtyfreeseason,
             beyondlifetimecirc    = beyondlifetimecirc +
                                     v_beyondlifetypecirc,
             qtyrentedperpiece     = qtyrentedperpiece + v_qtyrentedperpiece,
             qtyrentedother        = qtyrentedother + v_qtyrentother,
             qtycustomerrentstop   = qtycustomerrentstop + v_qtycustrentstop,
             qtyrentstop           = qtyrentstop + v_qtyrentstop,
             qtyrentemblem         = qtyrentemblem + v_qtyrentemblem,
             qtyreplacement        = qtyreplacement + v_qtyreplacement,
             qtyassigned           = qtyassigned + v_qtyassigned,
             qtyrenteddepositstock = qtyrenteddepositstock +
                                     v_qtyrenteddepositstock,
             qtysubstitute         = qtysubstitute + v_qtysubstitute,
             qtyrentedperpiecepool = qtyrentedperpiecepool + v_qtyrentedperpiecepool,
             qtyrentedreturnrent   = qtyrentedreturnrent + v_qtyrentedreturnrent,
             qtyrentedminrent      = qtyrentedminrent + v_qtyrentedminrent,
             qtyfullyamortized     = qtyfullyamortized + v_qtyfullyamortized,
             systemUser_id         = sq_systemUserid,
             TIMESTAMP             = SYSDATE
       WHERE /*statusquoheader_id = sqHeaderID
                                 and customer_id = customerID
                                 and department_id = departmentID
                                 and distributionpoint_id = distributionpointID
                                 and weareremployment_id = weareremploymentID
                                 and product_link_id = productID
                           and sizedefinition_link_id = sizeID
                      and finishingmethod_id = finMethID*/
       sqitemincirculation_id = sqItemInCirculationID;
      --    COMMIT;
EXCEPTION
WHEN OTHERS THEN
write_log('Update record in Sqitemincirculation table for sqItemInCirculationID ' || sqItemInCirculationID || ' has failed. Please check!');
commit;
END;
    END IF;
  END insertValuesIntoSqItemInCirc;

  PROCEDURE createSQItemInCircOnUniqueItem(sqHeaderID          statusquoheader.statusquoheader_id%TYPE,
                                           processBUID         businessunit.businessunit_id%TYPE,
                                           invoiceBUID         businessunit.businessunit_id%TYPE,
                                           sizeStarID          sizedefinition.sizedefinition_id%TYPE,
                                           checkInvoiceBu      INT,
                                           sqonwearerlevel     INT,
                                           inactiveplpc        INT,
                                           flagSubstituteID    INT,
                                           flagReplacementID   INT,
                                           stayDepositStockID  INT,
                                           invoicereplacements INT,
                                           invoicesubstitutes  INT) IS

    -- declaration of variables
    emblemTemplateID      emblemtemplate.emblemtemplate_Id%TYPE := -1;
    sqItemInCirculationID sqitemincirculation.sqitemincirculation_id%TYPE := -1;

    --status_id for UI 'In Circulation' and 'Assigned' (used for createSQItemInCircOnUniqueItem)
    statusUIInCirculation status.status_id%TYPE := getstatusid('UI',
                                                               '20');
    statusAssignedID      status.status_id%TYPE := getstatusid('UI',
                                                               '30');
    v_qtyTotal   number := 0;
     v_qtyCOG   number:= 0;
     v_qtyAssigned   number:= 0;
     v_qtyFree   number:= 0;
     v_qtyCustRentStop   number:= 0;
     v_qtyRentStop   number:= 0;
     v_qtyFreeSeason   number:= 0;
     v_qtyReplacement   number:= 0;
     v_qtySubstitute   number:= 0;
     v_qtyDepositStock   number:= 0;
     v_qtyBeyondLifeTime   number:= 0;
     v_qtyLease              number:= 0;
     v_qtyRentedPerPiecePool  number := 0;
     v_qtyFullyAmortized      number := 0;
     seasontypeid           seasontype.seasontype_id%TYPE := -1;
   --  v_maxCust      customer.customer_id%type := 99000;
   -- i              number := 0;
   -- quantile       number := 4;


    CURSOR stmtBOnWearerLevel is
      SELECT /*+index(wi XAK1WEARERINVENTORY) index_ffs(a XAK2UNIQUEITEM) index_ffs(b XAK1UNIQUEITEMNONPOOL)*/
             e.department_id,
             d.distributionpoint_id,
             c.weareremployment_id,
             wi.product_id,
             wi.sizedefinition_id,
             nvl(wi.finishingmethod_id,
                 -1) finishingmethod_id,
             e.customer_id,
             i.customernumber,
             f.code,
             wi.emblemtemplate_id,
             i.ChargeAmortizedUniqueItems
        FROM uniqueitem         a,
             uniqueitemnonpool  b,
             weareremployment   c,
             distributionpoint  d,
             department         e,
             product            f,
             productgroup       g,
             customeractivities h,
             customer           i,
             wearerinventory    wi
       WHERE a.uniqueitem_id = b.uniqueitem_id
             AND b.weareremployment_id = c.weareremployment_id
             AND c.distributionpoint_id = d.distributionpoint_id
             AND d.department_id = e.department_id
             AND wi.product_id = f.product_id
             AND f.productgroup_id = g.productgroup_id
             AND abs(g.activity_id) = abs(h.activity_id)
             AND e.customer_id = h.customer_id
             AND e.customer_id = i.customer_id
             AND b.wearerinventory_id = wi.wearerinventory_id
             AND h.processbusinessunit_id = processBUID
             AND
             (checkinvoicebu = 0 OR h.invoicebusinessunit_id = invoiceBUID)
             AND abs(h.processbusinessunit_id) = abs(a.businessunit_id)
             AND a.status_id IN (statusUIInCirculation, statusAssignedID)
           GROUP BY e.customer_id,
                c.weareremployment_id,
                d.distributionpoint_id,
                e.department_id,
                wi.product_id,
                wi.sizedefinition_id,
                wi.finishingmethod_id,
                wi.emblemtemplate_id,
                i.customernumber,
                f.code,
                i.ChargeAmortizedUniqueItems;

  BEGIN

      FOR rs IN stmtBOnWearerLevel LOOP
        --   IF (sqItemInCirculationID = -1) THEN
        --search if exists an sqitemincircID
          BEGIN
            SELECT NVL((SELECT a.seasontype_id
                      FROM seasontype a, productlistpercustomer plpc
             WHERE a.seasontype_id = plpc.seasontype_id
               AND plpc.customer_id = rs.customer_id
               and plpc.product_id = rs.product_id
               and plpc.sizedefinition_id = rs.sizedefinition_id 
               and plpc.finishingmethod_id = rs.finishingmethod_id
               AND a.active = 'Y' ), 
               (SELECT a.seasontype_id
               FROM seasontype a, productlistpercustomer plpc
             WHERE a.seasontype_id = plpc.seasontype_id
               AND plpc.customer_id = rs.customer_id
               and plpc.product_id = rs.product_id
               and plpc.sizedefinition_id = sizeStarID
               and plpc.finishingmethod_id = rs.finishingmethod_id
               AND a.active = 'Y' ))
                INTO seasontypeID
              FROM DUAL;
          EXCEPTION
            WHEN no_data_found THEN
              seasontypeID := -1;
          END;
        BEGIN
          SELECT getsqitemincirconuirentforstmt(sqheaderid,
                                                rs.distributionpoint_id,
                                                case sqonwearerlevel when 1 then
                                                rs.weareremployment_ID
                                                else -1 end,
                                                rs.product_id,
                                                rs.sizedefinition_id,
                                                rs.finishingmethod_id)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;
        --   END IF;
SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyTotal
                   FROM uniqueitem x, uniqueitemnonpool b, wearerinventory w
                  WHERE x.uniqueitem_id = b.uniqueitem_id
                  and b.weareremployment_id = rs.weareremployment_id
                  and b.wearerinventory_id = w.wearerinventory_id
                  and w.product_id = rs.product_id
                  and w.finishingmethod_id = rs.finishingmethod_id
                  and w.sizedefinition_id = rs.sizedefinition_id
                  and x.status_id IN (statusUIInCirculation, statusAssignedID);

       SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyCOG
                   FROM uniqueitem x, uniqueitemnonpool b, wearerinventory w
                  WHERE x.uniqueitem_id = b.uniqueitem_id
                   AND x.status_id = statusUIInCirculation
                   AND x.customerowned = 'Y'
                   and b.weareremployment_id = rs.weareremployment_id
                  and b.wearerinventory_id = w.wearerinventory_id
                  and w.product_id = rs.product_id
                  and w.finishingmethod_id = rs.finishingmethod_id
                  and w.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyFree
                   FROM uniqueitem x, uniqueitemnonpool b, wearerinventory w
                  WHERE x.uniqueitem_id = b.uniqueitem_id
                       AND nvl(x.leaseweeks,
                                0) = 0
                        AND x.status_id = statusUIInCirculation
                        AND b.freeextragarment = 'Y'
                        AND (b.enddatefreeextra > sq_date OR
                        nvl(b.enddatefreeextra,
                                 to_date('01/01/0001',
                                         'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                     'dd/mm/yyyy'))
                        AND NOT (x.customerowned = 'Y')
                        and b.weareremployment_id = rs.weareremployment_id
                        and b.wearerinventory_id = w.wearerinventory_id
                        and w.product_id = rs.product_id
                        and w.finishingmethod_id = rs.finishingmethod_id
                        and w.sizedefinition_id = rs.sizedefinition_id;

             SELECT COUNT(t.temporarygarmentrentstop_id)
              into v_qtyCustRentStop
                   FROM temporarygarmentrentstop t
                  WHERE t.customer_id = rs.customer_id
                        AND f_isinyearweeklifespan(startyear,
                                                   startweek,
                                                   sq_year,
                                                   sq_week,
                                                   endyear,
                                                   endweek) = 1 ;

             SELECT nvl(sum(case when z.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyRentStop
                   FROM uniqueitemnonpool   x,
                        wearerinventory     wi,
                        uniqueitem          z,
                        uniqueitemfixedinfo zfi
                  WHERE x.wearerinventory_id = wi.wearerinventory_id
                        AND x.uniqueitem_id = z.uniqueitem_id
                        AND zfi.uniqueitem_id = z.uniqueitem_id
                        AND nvl(z.leaseweeks,
                                0) = 0
                        AND z.status_id = statusUIInCirculation
                        AND NOT (x.freeextragarment = 'Y' AND
                         (x.enddatefreeextra > sq_date OR
                         nvl(x.enddatefreeextra,
                                      to_date('01/01/0001',
                                              'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                          'dd/mm/yyyy')))
                        AND NOT (z.customerowned = 'Y')
                        AND sq_date BETWEEN wi.temporaryrentstopstartdate AND wi.temporaryrentstopenddate
                        and x.weareremployment_id = rs.weareremployment_id
                        and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyFreeSeason
                   FROM uniqueitem        x,
                        uniqueitemnonpool y,
                        wearerinventory   wi
                  WHERE  x.uniqueitem_id = y.uniqueitem_id
                        AND y.wearerinventory_id = wi.wearerinventory_id
                        AND wi.season_id IS NOT NULL
                        AND seasontypeid <> -1
                        AND NOT EXISTS
                  (SELECT sw.season_id
                           FROM seasonweek sw
                          WHERE sw.season_id = wi.season_id
                                AND sw.weeknumber = sq_week)
                        AND nvl(x.leaseweeks,
                                0) = 0
                        AND x.status_id = statusUIInCirculation
                        AND NOT ((y.freeextragarment = 'Y' AND
                         (y.enddatefreeextra > sq_date OR
                         nvl(y.enddatefreeextra,
                                       to_date('01/01/0001',
                                               'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                           'dd/mm/yyyy'))))
                        AND ((sq_date < wi.temporaryrentstopstartdate OR
                        sq_date > temporaryrentstopenddate) OR
                        (nvl(wi.temporaryrentstopstartdate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy') AND
                        nvl(wi.temporaryrentstopenddate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy')))
                        AND NOT (x.customerowned = 'Y')
                         and y.weareremployment_id = rs.weareremployment_id
                        and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                    into v_qtyBeyondLifeTime
                   FROM uniqueitem          x,
                        uniqueitemnonpool   y,
                        uniqueitemfixedinfo z,
                        wearerinventory     wi
                  WHERE x.uniqueitem_id = y.uniqueitem_id
                        AND x.uniqueitem_id = z.uniqueitem_id
                        AND y.wearerinventory_id = wi.wearerinventory_id
                        AND nvl(x.leaseweeks,
                                0) = 0
                        AND x.status_id = statusUIInCirculation
                        AND z.enddatefullrent < sq_date
                        AND NOT ((y.freeextragarment = 'Y' AND
                         (y.enddatefreeextra > sq_date OR
                         nvl(y.enddatefreeextra,
                                       to_date('01/01/0001',
                                               'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                           'dd/mm/yyyy'))))
                        AND ((sq_date < wi.temporaryrentstopstartdate OR
                        sq_date > temporaryrentstopenddate) OR
                        (nvl(wi.temporaryrentstopstartdate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy') AND
                        nvl(wi.temporaryrentstopenddate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy')))
                        AND (nvl(wi.season_id, 0) = 0 OR (  seasontypeid <> -1  AND EXISTS
                         (SELECT sw.season_id
                                FROM seasonweek sw
                               WHERE sw.season_id = wi.season_id
                                     AND sw.weeknumber = sq_week)))
                        AND NOT (x.customerowned = 'Y')
                        and y.weareremployment_id = rs.weareremployment_id
                        and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyAssigned
                   FROM uniqueitem x, uniqueitemnonpool b, wearerinventory wi
                  WHERE x.uniqueitem_id = b.uniqueitem_id
                        AND x.status_id = statusAssignedID
                         and b.weareremployment_id = rs.weareremployment_id
                         and b.wearerinventory_id = wi.wearerinventory_id
                        and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyLease
                   FROM uniqueitem x, uniqueitemnonpool b, wearerinventory wi
                  WHERE x.uniqueitem_id = b.uniqueitem_id
                        AND x.leaseweeks IS NOT NULL
                        AND x.status_id = statusUIInCirculation
                         and b.weareremployment_id = rs.weareremployment_id
                         and b.wearerinventory_id = wi.wearerinventory_id
                        and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when z.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyReplacement
                   FROM uniqueitemnonpool   x,
                        wearerinventory     wi,
                        uniqueitem          z,
                        uniqueitemfixedinfo zfi
                  WHERE x.wearerinventory_id = wi.wearerinventory_id
                        AND x.uniqueitem_id = z.uniqueitem_id
                        AND zfi.uniqueitem_id = z.uniqueitem_id
                        AND nvl(z.leaseweeks,
                                0) = 0
                        AND z.status_id = statusUIInCirculation
                        AND NOT (x.freeextragarment = 'Y' AND
                         (x.enddatefreeextra > sq_date OR
                         nvl(x.enddatefreeextra,
                                      to_date('01/01/0001',
                                              'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                          'dd/mm/yyyy')))
                        AND NOT (z.customerowned = 'Y')
                        AND NOT (zfi.enddatefullrent < sq_date)
                        AND ((sq_date < wi.temporaryrentstopstartdate OR
                        sq_date > temporaryrentstopenddate) OR
                        (nvl(wi.temporaryrentstopstartdate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy') AND
                        nvl(wi.temporaryrentstopenddate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy')))
                        AND (nvl(wi.season_id,
                                 0) = 0 OR (  seasontypeid <> -1 AND EXISTS
                         (SELECT sw.season_id
                                FROM seasonweek sw
                               WHERE sw.season_id = wi.season_id
                                     AND sw.weeknumber = sq_week)))
                        AND EXISTS
                  (SELECT r.uniqueitem_id
                           FROM uniqueitemflag r
                          WHERE r.uniqueitem_id = z.uniqueitem_id
                                AND r.flag_id = flagReplacementID
                                AND r.startdate <= sq_date)
                         and x.weareremployment_id = rs.weareremployment_id
                         and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;


             SELECT nvl(sum(case when z.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtySubstitute
                   FROM uniqueitemnonpool   x,
                        wearerinventory     wi,
                        uniqueitem          z,
                        uniqueitemfixedinfo zfi
                  WHERE x.wearerinventory_id = wi.wearerinventory_id
                        AND x.uniqueitem_id = z.uniqueitem_id
                        AND zfi.uniqueitem_id = z.uniqueitem_id
                        AND nvl(z.leaseweeks,
                                0) = 0
                        AND z.status_id = statusUIInCirculation
                        AND NOT (x.freeextragarment = 'Y' AND
                         (x.enddatefreeextra > sq_date OR
                         nvl(x.enddatefreeextra,
                                      to_date('01/01/0001',
                                              'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                          'dd/mm/yyyy')))
                        AND NOT (z.customerowned = 'Y')
                        AND NOT (zfi.enddatefullrent < sq_date)
                        AND ((sq_date < wi.temporaryrentstopstartdate OR
                        sq_date > temporaryrentstopenddate) OR
                        (nvl(wi.temporaryrentstopstartdate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy') AND
                        nvl(wi.temporaryrentstopenddate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy')))
                        AND (nvl(wi.season_id, 0) = 0 OR (  seasontypeid <> -1 AND EXISTS
                         (SELECT sw.season_id
                                FROM seasonweek sw
                               WHERE sw.season_id = wi.season_id
                                     AND sw.weeknumber = sq_week)))
                        AND NOT EXISTS
                  (SELECT r.uniqueitem_id
                           FROM uniqueitemflag r
                          WHERE r.uniqueitem_id = z.uniqueitem_id
                                AND r.flag_id = flagReplacementID
                                AND r.startdate <= sq_date)
                        AND EXISTS
                  (SELECT r.uniqueitem_id
                           FROM uniqueitemflag r
                          WHERE r.uniqueitem_id = z.uniqueitem_id
                                AND r.flag_id = flagSubstituteID
                                AND r.startdate <= sq_date)
                   and x.weareremployment_id = rs.weareremployment_id
                         and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

             SELECT nvl(sum(case when z.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
                   into v_qtyDepositStock
                   FROM uniqueitemnonpool   x,
                        wearerinventory     wi,
                        uniqueitem          z,
                        uniqueitemfixedinfo zfi
                  WHERE x.wearerinventory_id = wi.wearerinventory_id
                        AND x.uniqueitem_id = z.uniqueitem_id
                        AND zfi.uniqueitem_id = z.uniqueitem_id
                        AND nvl(z.leaseweeks,
                                0) = 0
                        AND z.stay_id = stayDepositStockID
                        AND z.status_id = statusUIInCirculation
                        AND NOT (x.freeextragarment = 'Y' AND
                         (x.enddatefreeextra > sq_date OR
                         nvl(x.enddatefreeextra,
                                      to_date('01/01/0001',
                                              'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                          'dd/mm/yyyy')))
                        AND NOT (z.customerowned = 'Y')
                        AND NOT (zfi.enddatefullrent < sq_date)
                        AND ((sq_date < wi.temporaryrentstopstartdate OR
                        sq_date > temporaryrentstopenddate) OR
                        (nvl(wi.temporaryrentstopstartdate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy') AND
                        nvl(wi.temporaryrentstopenddate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy')))
                        AND (nvl(wi.season_id,
                                 0) = 0 OR ( seasontypeid <> -1  AND EXISTS
                         (SELECT sw.season_id
                                FROM seasonweek sw
                               WHERE sw.season_id = wi.season_id
                                     AND sw.weeknumber = sq_week)))
                        AND NOT EXISTS
                  (SELECT r.uniqueitem_id
                           FROM uniqueitemflag r
                          WHERE r.uniqueitem_id = z.uniqueitem_id
                                AND r.flag_id = flagReplacementID
                                AND r.startdate <= sq_date)
                        AND NOT EXISTS
                  (SELECT r.uniqueitem_id
                           FROM uniqueitemflag r
                          WHERE r.uniqueitem_id = z.uniqueitem_id
                                AND r.flag_id = flagSubstituteID
                                AND r.startdate <= sq_date)
                  and x.weareremployment_id = rs.weareremployment_id
                         and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id;

        if (rs.ChargeAmortizedUniqueItems = 0) then
        SELECT nvl(sum(case when X.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
        into v_qtyFullyAmortized
                   FROM uniqueitem          x,
                        uniqueitemnonpool   y,
                        uniqueitemfixedinfo z,
                        wearerinventory     wi
                  WHERE  x.uniqueitem_id = y.uniqueitem_id
                        AND x.uniqueitem_id = z.uniqueitem_id
                        AND y.wearerinventory_id = wi.wearerinventory_id
                        and y.weareremployment_id = rs.weareremployment_id
                        and wi.product_id = rs.product_id
                        and wi.finishingmethod_id = rs.finishingmethod_id
                        and wi.sizedefinition_id = rs.sizedefinition_id
                        AND nvl(x.leaseweeks,
                                0) = 0
                        AND x.status_id = statusUIInCirculation
                        AND z.enddatefullrent >= sq_date
                        AND NOT ((y.freeextragarment = 'Y' AND
                         (y.enddatefreeextra > sq_date OR
                         nvl(y.enddatefreeextra,
                                       to_date('01/01/0001',
                                               'dd/mm/yyyy')) =
                         to_date('01/01/0001',
                                           'dd/mm/yyyy'))))
                        AND ((sq_date < wi.temporaryrentstopstartdate OR
                        sq_date > temporaryrentstopenddate) OR
                        (nvl(wi.temporaryrentstopstartdate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy') AND
                        nvl(wi.temporaryrentstopenddate,
                                  to_date('01/01/0001',
                                          'dd/mm/yyyy')) =
                        to_date('01/01/0001',
                                      'dd/mm/yyyy')))
                        AND (nvl(wi.season_id,
                                 0) = 0 OR ( seasontypeid <> -1  OR EXISTS
                         (SELECT sw.season_id
                                FROM seasonweek sw
                               WHERE sw.season_id = wi.season_id
                                     AND sw.weeknumber = sq_week)))
                        AND NOT (x.customerowned = 'Y')
                        AND x.ResidualValueAmount = 0;
    else v_qtyFullyAmortized:=0;
       end if;

       SELECT nvl(sum(case when ui.BUSINESSUNIT_ID = processBUID then 1 else 0 end),0)
       into v_qtyRentedPerPiecePool
                 FROM uniqueitem ui, uniqueitemnonpool b, wearerinventory wi
                WHERE ui.uniqueitem_id = b.uniqueitem_id
                 AND b.wearerinventory_id = wi.wearerinventory_id
                and b.weareremployment_id = rs.weareremployment_id
                and wi.product_id = rs.product_id
                and wi.finishingmethod_id = rs.finishingmethod_id
                and wi.sizedefinition_id = rs.sizedefinition_id
                 AND ui.status_id = statusUIInCirculation
                 AND (ui.stay_id = PACK_SQITEMSINCIRCULATION_OLD.GETSTAYID(STAY_TYPE_GARMENT, 20)
                     or ui.stay_id = PACK_SQITEMSINCIRCULATION_OLD.GETSTAYID(STAY_TYPE_GARMENT, 27)
                     or ui.stay_id = PACK_SQITEMSINCIRCULATION_OLD.GETSTAYID(STAY_TYPE_GARMENT, 28))
                  AND trunc(ui.lastoutscandate) < trunc(sysdate) -
                     7 *
                     (SELECT plpc.chargerentnoreturnpoolafterwks
                        FROM productlistpercustomer plpc
                       WHERE plpc.productlistpercustomer_id =
                             (SELECT coalesce((SELECT plpc1.productlistpercustomer_id
                                                FROM productlistpercustomer plpc1
                                               WHERE plpc1.billingmethod = 3
                                                 AND plpc1.inventorybillingtype = 4
                                                 AND plpc1.chargerentnotreturned <> 0
                                                 AND plpc1.chargerentnoreturnpoolafterwks > 0
                                                 AND plpc1.codeuniquely = 'Y'
                                                 AND plpc1.customer_id = rs.customer_id
                                                 AND plpc1.product_id = rs.product_id
                                                 AND plpc1.sizedefinition_id = ui.sizedefinition_id
                                                 AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                                 AND plpc1.dateactive =
                                                     (select max(plpc2.dateactive)
                                                      from productlistpercustomer plpc2
                                                     where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                                       and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                                       and plpc2.product_id = plpc1.product_id
                                                       and plpc2.customer_id = plpc1.customer_id
                                                       and plpc2.dateactive < sysdate
                                                       and plpc2.billingmethod = 3
                                                       and plpc2.inventorybillingtype = 4
                                                       and plpc2.chargerentnotreturned <> 0
                                                       and plpc2.chargerentnoreturnpoolafterwks > 0
                                                       and plpc2.codeuniquely = 'Y')),
                                                 coalesce((SELECT plpc1.productlistpercustomer_id
                                                            FROM productlistpercustomer plpc1
                                                           WHERE plpc1.billingmethod = 3
                                                             AND plpc1.inventorybillingtype = 4
                                                             AND plpc1.chargerentnotreturned <> 0
                                                             AND plpc1.chargerentnoreturnpoolafterwks > 0
                                                             AND plpc1.codeuniquely = 'Y'
                                                             AND plpc1.customer_id = rs.customer_id
                                                             AND plpc1.product_id = rs.product_id
                                                             AND plpc1.sizedefinition_id =
                                                                 sizeStarID
                                                             AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                                             AND plpc1.dateactive =
                                                             (select max(plpc2.dateactive)
                                                              from productlistpercustomer plpc2
                                                             where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                                               and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                                               and plpc2.product_id = plpc1.product_id
                                                               and plpc2.customer_id = plpc1.customer_id
                                                               and plpc2.dateactive < sysdate
                                                               and plpc2.billingmethod = 3
                                                               and plpc2.inventorybillingtype = 4
                                                               and plpc2.chargerentnotreturned <> 0
                                                               and plpc2.chargerentnoreturnpoolafterwks > 0
                                                               and plpc2.codeuniquely = 'Y')),
                                                          -1)
                                             )
                                    FROM dual  ));


        -- Create or Store
        emblemTemplateID := case sqonwearerlevel when 1
                              then rs.emblemtemplate_ID
                              else -1
                            end;
        createOrStoreOnSQforUniqueItem(sqheaderid,
                                       inactiveplpc,
                                       rs.customer_id,
                                       rs.department_id,
                                       rs.distributionpoint_id,
                                       rs.product_id,
                                       rs.sizedefinition_id,
                                       rs.finishingmethod_id,
                                       case sqonwearerlevel when 1 then
                                           rs.weareremployment_ID
                                         else
                                           -1
                                       end,
                                       emblemTemplateID,
                                       sizeStarID,
                                       invoiceReplacements,
                                       invoiceSubstitutes,
                                       sqItemInCirculationID,
                                       sqOnWearerLevel,
                                        v_qtyTotal,
                                       v_qtyCOG,
                                       v_qtyAssigned,
                                       v_qtyFree,
                                       v_qtyCustRentStop,
                                       v_qtyRentStop,
                                       v_qtyFreeSeason,
                                       v_qtyReplacement,
                                       v_qtySubstitute,
                                       v_qtyDepositStock,
                                       v_qtyBeyondLifeTime,
                                       v_qtyLease,
                                       v_qtyFullyAmortized,
                                       v_qtyRentedPerPiecePool);
      END LOOP;

  END; --createSQItemInCircOnUniqueItem

  FUNCTION getStatusID(vstatustype status.statustype %TYPE,
                       vstatuscode status.code%TYPE)
    RETURN status.status_id%TYPE IS

    --declaration of variables
    vstatusid status.status_id%TYPE;

  BEGIN

    BEGIN
      SELECT st.status_id
        INTO vstatusid
        FROM status st
       WHERE st.statustype = vstatustype
             AND st.code = vstatuscode;
    EXCEPTION
      WHEN no_data_found THEN
        vstatusid := -1;
    END;

    RETURN vstatusid;

  END getStatusID;

  PROCEDURE createSqItemInCircOnUniqueRent(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                           processBuID                  businessunit.businessunit_id%TYPE,
                                           invoiceBuID                  businessunit.businessunit_id%TYPE,
                                           statusIDforUniqueItemInStock status.status_id%TYPE,
                                           sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                           checkInvoiceBu               INT,
                                           sqOnWearerLevel              INT,
                                           inactivePLPC                 INT) IS

    -- declation of variables
    sqItemInCirculationID sqitemincirculation.sqitemincirculation_id%TYPE := -1;

    --declaration of cursors
    CURSOR stmtC IS
      SELECT we.distributionpoint_id,
             dp.department_id,
             we.weareremployment_id,
             ui.product_id,
             ui.sizedefinition_id,
             CASE sqOnWearerLevel
               WHEN 1 THEN
                coalesce(ui.finishingmethod_id,
                         (SELECT w2.finishingmethod_id
                            FROM wearerinventory w2
                           WHERE w2.weareremployment_id =
                                 we.weareremployment_id
                                 AND w2.product_id = ui.product_id
                                 AND
                                 w2.sizedefinition_id = ui.sizedefinition_id
                                 AND rownum = 1))
               ELSE
                coalesce(ui.finishingmethod_id,
                         (SELECT w2.finishingmethod_id
                            FROM wearerinventory w2, weareremployment e2
                           WHERE w2.weareremployment_id =
                                 e2.weareremployment_id
                                 AND e2.distributionpoint_id =
                                 we.distributionpoint_id
                                 AND w2.product_id = ui.product_id
                                 AND
                                 w2.sizedefinition_id = ui.sizedefinition_id
                                 AND rownum = 1))
             END finishingMethodID,
             w.customer_id,
             CASE sqOnWearerLevel
               WHEN 1 THEN
                we.weareremployment_id
               ELSE
                NULL
             END wearerEmploymentID,
             COUNT(ui.uniqueitem_id) noOfUniqueItems
        FROM uniqueitem          ui,
             uniqueitemfixedinfo uifi,
             reasoncode          rc,
             weareremployment    we,
             wearer              w,
             distributionpoint   dp,
             product             p,
             productgroup        pg,
             customeractivities  ca
       WHERE ui.status_id = statusIDforUniqueItemInStock
             AND ui.uniqueitem_id = uifi.uniqueitem_id
             AND uifi.reasoncode_id = rc.reasoncode_id
             AND rc.calculaterentonstock = 'Y'
             AND ui.lastweareremployment_link_id = we.weareremployment_id
             AND we.wearer_id = w.wearer_id
             AND we.distributionpoint_id = dp.distributionpoint_id
             AND p.product_id = ui.product_id
             AND pg.productgroup_id = p.productgroup_id
             AND ca.activity_id = pg.activity_id
             AND ca.customer_id = w.customer_id
             AND ca.processbusinessunit_id = processBuID

             AND abs(ca.processbusinessunit_id) = abs(ui.businessunit_id)
             AND
             'Y' =
             (SELECT p.depositStockAllowed
                FROM productlistpercustomer p
               WHERE p.productlistpercustomer_id =
                     (SELECT coalesce((SELECT productlistpercustomer_id
                                        FROM productlistpercustomer
                                       WHERE customer_id = w.customer_id
                                             AND product_id = ui.product_id
                                             AND sizedefinition_id =
                                             ui.sizedefinition_id
                                             AND
                                             finishingmethod_id =
                                             (CASE sqOnWearerLevel WHEN 1 THEN
                                              coalesce(ui.finishingmethod_id,
                                                       (SELECT w2.finishingmethod_id
                                                          FROM wearerinventory w2
                                                         WHERE w2.weareremployment_id =
                                                               we.weareremployment_id
                                                               AND w2.product_id =
                                                               ui.product_id
                                                               AND
                                                               w2.sizedefinition_id =
                                                               ui.sizedefinition_id
                                                               AND rownum = 1)) ELSE
                                              coalesce(ui.finishingmethod_id,
                                                       (SELECT w2.finishingmethod_id
                                                          FROM wearerinventory  w2,
                                                               weareremployment e2
                                                         WHERE w2.weareremployment_id =
                                                               e2.weareremployment_id
                                                               AND
                                                               e2.distributionpoint_id =
                                                               we.distributionpoint_id
                                                               AND w2.product_id =
                                                               ui.product_id
                                                               AND
                                                               w2.sizedefinition_id =
                                                               ui.sizedefinition_id
                                                               AND rownum = 1)) END)
                                             AND productlistpercustomer.dateactive <=
                                             sq_date
                                             AND productlistpercustomer.dateinactive >=
                                             sq_date),
                                      (CASE ui.sizedefinition_id
                                        WHEN sizeStarID THEN
                                         -1
                                        ELSE
                                         coalesce((SELECT productlistpercustomer_id
                                                    FROM productlistpercustomer
                                                   WHERE customer_id =
                                                         w.customer_id
                                                         AND product_id =
                                                         ui.product_id
                                                         AND sizedefinition_id =
                                                         sizeStarID
                                                         AND
                                                         finishingmethod_id =
                                                         (CASE sqOnWearerLevel WHEN 1 THEN
                                                          coalesce(ui.finishingmethod_id,
                                                                   (SELECT w2.finishingmethod_id
                                                                      FROM wearerinventory w2
                                                                     WHERE w2.weareremployment_id =
                                                                           we.weareremployment_id
                                                                           AND
                                                                           w2.product_id =
                                                                           ui.product_id
                                                                           AND
                                                                           w2.sizedefinition_id =
                                                                           ui.sizedefinition_id
                                                                           AND
                                                                           rownum = 1)) ELSE
                                                          coalesce(ui.finishingmethod_id,
                                                                   (SELECT w2.finishingmethod_id
                                                                      FROM wearerinventory  w2,
                                                                           weareremployment e2
                                                                     WHERE w2.weareremployment_id =
                                                                           e2.weareremployment_id
                                                                           AND
                                                                           e2.distributionpoint_id =
                                                                           we.distributionpoint_id
                                                                           AND
                                                                           w2.product_id =
                                                                           ui.product_id
                                                                           AND
                                                                           w2.sizedefinition_id =
                                                                           ui.sizedefinition_id
                                                                           AND
                                                                           rownum = 1)) END)
                                                         AND productlistpercustomer.dateactive <=
                                                         sq_date
                                                         AND productlistpercustomer.dateinactive >=
                                                         sq_date),
                                                  -1)
                                      END))
                        FROM dual))
             AND uifi.enddatefullrent > sq_date
       GROUP BY we.weareremployment_id,
                dp.department_id,
                w.customer_id,
                we.distributionpoint_id,
                ui.product_id,
                ui.sizedefinition_id,
                ui.finishingmethod_id,
                6;

    CURSOR stmtC_checkinvoicedbu IS
      SELECT we.distributionpoint_id,
             dp.department_id,
             we.weareremployment_id,
             ui.product_id,
             ui.sizedefinition_id,
             CASE sqOnWearerLevel
               WHEN 1 THEN
                coalesce(ui.finishingmethod_id,
                         (SELECT w2.finishingmethod_id
                            FROM wearerinventory w2
                           WHERE w2.weareremployment_id =
                                 we.weareremployment_id
                                 AND w2.product_id = ui.product_id
                                 AND
                                 w2.sizedefinition_id = ui.sizedefinition_id
                                 AND rownum = 1))
               ELSE
                coalesce(ui.finishingmethod_id,
                         (SELECT w2.finishingmethod_id
                            FROM wearerinventory w2, weareremployment e2
                           WHERE w2.weareremployment_id =
                                 e2.weareremployment_id
                                 AND e2.distributionpoint_id =
                                 we.distributionpoint_id
                                 AND w2.product_id = ui.product_id
                                 AND
                                 w2.sizedefinition_id = ui.sizedefinition_id
                                 AND rownum = 1))
             END finishingMethodID,
             w.customer_id,
             CASE sqOnWearerLevel
               WHEN 1 THEN
                we.weareremployment_id
               ELSE
                NULL
             END wearerEmploymentID,
             COUNT(ui.uniqueitem_id) noOfUniqueItems
        FROM uniqueitem          ui,
             uniqueitemfixedinfo uifi,
             reasoncode          rc,
             weareremployment    we,
             wearer              w,
             distributionpoint   dp,
             product             p,
             productgroup        pg,
             customeractivities  ca
       WHERE ui.status_id = statusIDforUniqueItemInStock
             AND ui.uniqueitem_id = uifi.uniqueitem_id
             AND uifi.reasoncode_id = rc.reasoncode_id
             AND rc.calculaterentonstock = 'Y'
             AND ui.lastweareremployment_link_id = we.weareremployment_id
             AND we.wearer_id = w.wearer_id
             AND we.distributionpoint_id = dp.distributionpoint_id
             AND p.product_id = ui.product_id
             AND pg.productgroup_id = p.productgroup_id
             AND ca.activity_id = pg.activity_id
             AND ca.customer_id = w.customer_id
             AND ca.processbusinessunit_id = processBuID
             AND ca.invoicebusinessunit_id = invoiceBuID
             AND abs(ca.processbusinessunit_id) = abs(ui.businessunit_id)
             AND
             'Y' =
             (SELECT p.depositStockAllowed
                FROM productlistpercustomer p
               WHERE p.productlistpercustomer_id =
                     (SELECT coalesce((SELECT productlistpercustomer_id
                                        FROM productlistpercustomer
                                       WHERE customer_id = w.customer_id
                                             AND product_id = ui.product_id
                                             AND sizedefinition_id =
                                             ui.sizedefinition_id
                                             AND
                                             finishingmethod_id =
                                             (CASE sqOnWearerLevel WHEN 1 THEN
                                              coalesce(ui.finishingmethod_id,
                                                       (SELECT w2.finishingmethod_id
                                                          FROM wearerinventory w2
                                                         WHERE w2.weareremployment_id =
                                                               we.weareremployment_id
                                                               AND w2.product_id =
                                                               ui.product_id
                                                               AND
                                                               w2.sizedefinition_id =
                                                               ui.sizedefinition_id
                                                               AND rownum = 1)) ELSE
                                              coalesce(ui.finishingmethod_id,
                                                       (SELECT w2.finishingmethod_id
                                                          FROM wearerinventory  w2,
                                                               weareremployment e2
                                                         WHERE w2.weareremployment_id =
                                                               e2.weareremployment_id
                                                               AND
                                                               e2.distributionpoint_id =
                                                               we.distributionpoint_id
                                                               AND w2.product_id =
                                                               ui.product_id
                                                               AND
                                                               w2.sizedefinition_id =
                                                               ui.sizedefinition_id
                                                               AND rownum = 1)) END)
                                             AND productlistpercustomer.dateactive <=
                                             sq_date

                                             AND productlistpercustomer.dateinactive >=
                                             sq_date),
                                      (CASE ui.sizedefinition_id
                                        WHEN sizeStarID THEN
                                         -1
                                        ELSE
                                         coalesce((SELECT productlistpercustomer_id
                                                    FROM productlistpercustomer
                                                   WHERE customer_id =
                                                         w.customer_id
                                                         AND product_id =
                                                         ui.product_id
                                                         AND sizedefinition_id =
                                                         sizeStarID
                                                         AND
                                                         finishingmethod_id =
                                                         (CASE sqOnWearerLevel WHEN 1 THEN
                                                          coalesce(ui.finishingmethod_id,
                                                                   (SELECT w2.finishingmethod_id
                                                                      FROM wearerinventory w2
                                                                     WHERE w2.weareremployment_id =
                                                                           we.weareremployment_id
                                                                           AND
                                                                           w2.product_id =
                                                                           ui.product_id
                                                                           AND
                                                                           w2.sizedefinition_id =
                                                                           ui.sizedefinition_id
                                                                           AND
                                                                           rownum = 1)) ELSE
                                                          coalesce(ui.finishingmethod_id,
                                                                   (SELECT w2.finishingmethod_id
                                                                      FROM wearerinventory  w2,
                                                                           weareremployment e2
                                                                     WHERE w2.weareremployment_id =
                                                                           e2.weareremployment_id
                                                                           AND
                                                                           e2.distributionpoint_id =
                                                                           we.distributionpoint_id
                                                                           AND
                                                                           w2.product_id =
                                                                           ui.product_id
                                                                           AND
                                                                           w2.sizedefinition_id =
                                                                           ui.sizedefinition_id
                                                                           AND
                                                                           rownum = 1)) END)
                                                         AND productlistpercustomer.dateactive <=
                                                         sq_date
                                                         AND productlistpercustomer.dateinactive >=
                                                         sq_date),
                                                  -1)
                                      END))
                        FROM dual))
             AND uifi.enddatefullrent > sq_date
       GROUP BY we.weareremployment_id,
                dp.department_id,
                w.customer_id,
                we.distributionpoint_id,
                ui.product_id,
                ui.sizedefinition_id,
                ui.finishingmethod_id,
                6;

  BEGIN

    IF (checkInvoiceBu = 1) THEN
      FOR rs_checkBu IN stmtC_checkinvoicedbu LOOP
        BEGIN
          --search if exists an sqitemincircID
          SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                                rs_checkBu.distributionpoint_id,
                                                rs_checkBu.wearerEmploymentID,
                                                rs_checkBu.product_id,
                                                rs_checkBu.sizedefinition_id,
                                                rs_checkBu.finishingMethodID)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;

        -- create / store a sqitemincirc
        createOrStoreOnSqForUiRent(sqHeaderID,
                                   rs_checkBu.customer_id,
                                   rs_checkBu.department_id,
                                   rs_checkBu.distributionpoint_id,
                                   rs_checkBu.product_id,
                                   rs_checkBu.sizedefinition_id,
                                   rs_checkBu.finishingMethodID,
                                   rs_checkBu.weareremployment_id,
                                   sqItemInCirculationID,
                                   rs_checkBu.noOfUniqueItems,
                                   inactivePLPC,
                                   sizeStarID);
      END LOOP;
    ELSE
      FOR rs IN stmtC LOOP
        BEGIN
          --search if exists an sqitemincircID
          SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                                rs.distributionpoint_id,
                                                rs.wearerEmploymentID,
                                                rs.product_id,
                                                rs.sizedefinition_id,
                                                rs.finishingMethodID)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;

        -- create / store a sqitemincirc
        createOrStoreOnSqForUiRent(sqHeaderID,
                                   rs.customer_id,
                                   rs.department_id,
                                   rs.distributionpoint_id,
                                   rs.product_id,
                                   rs.sizedefinition_id,
                                   rs.finishingMethodID,
                                   rs.weareremployment_id,
                                   sqItemInCirculationID,
                                   rs.noOfUniqueItems,
                                   inactivePLPC,
                                   sizeStarID);
      END LOOP;
    END IF;

  END createSqItemInCircOnUniqueRent;

  FUNCTION getSqItemInCircOnUiRentForStmt(sqHeaderID          statusquoheader.statusquoheader_id%TYPE,
                                          distributionPointID weareremployment.distributionpoint_id%TYPE,
                                          wearerEmploymentID  weareremployment.weareremployment_id%TYPE,
                                          productID           uniqueitem.product_id%TYPE,
                                          sizeDefinitionID    uniqueitem.sizedefinition_id%TYPE,
                                          finishingMethodID   INT)
    RETURN sqitemincirculation.sqitemincirculation_id%TYPE IS

    -- declaration of variables
    sqItemInCirculationID sqitemincirculation.sqitemincirculation_id%TYPE := -1;

  BEGIN
    BEGIN
      SELECT coalesce((CASE coalesce(wearerEmploymentID,
                                 -1)
                        WHEN -1 THEN
                         (CASE coalesce(finishingMethodID, -1)
                        WHEN -1 THEN
                         (SELECT MIN(x.sqitemincirculation_id)
                            FROM sqitemincirculation x
                           WHERE x.statusquoheader_id = sqHeaderID
                                 AND x.distributionpoint_link_id =
                                 distributionPointID
                                 AND nvl(x.weareremployment_link_id,
                                         0) = 0
                                 AND x.product_link_id = productID
                                 AND
                                 x.sizedefinition_link_id = sizeDefinitionID)
                        ELSE
                         (SELECT min(x.sqitemincirculation_id)
                            FROM sqitemincirculation x
                           WHERE x.statusquoheader_id = sqHeaderID
                                 AND x.distributionpoint_link_id =
                                 distributionPointID
                                 AND nvl(x.weareremployment_link_id,
                                         0) = 0
                                 AND x.product_link_id = productID
                                 AND
                                 x.sizedefinition_link_id = sizeDefinitionID
                                 AND
                                 x.finishingmethod_id = finishingMethodID)
                      END) ELSE(CASE coalesce(finishingMethodID,
                                     -1)
                             WHEN -1 THEN
                              (SELECT MIN(sqitemincirculation_id)
                                 FROM sqitemincirculation x
                                WHERE x.statusquoheader_id = sqHeaderID
                                      AND x.distributionpoint_link_id =
                                      distributionPointID
                                      AND x.weareremployment_link_id =
                                      wearerEmploymentID
                                      AND x.product_link_id = productID
                                      AND x.sizedefinition_link_id =
                                      sizeDefinitionID)
                             ELSE
                              (SELECT min(sqitemincirculation_id)
                                 FROM sqitemincirculation x
                                WHERE x.statusquoheader_id = sqHeaderID
                                      AND x.distributionpoint_link_id =
                                      distributionPointID
                                      AND x.weareremployment_link_id =
                                      wearerEmploymentID
                                      AND x.product_link_id = productID
                                      AND x.sizedefinition_link_id =
                                      sizeDefinitionID
                                      AND x.finishingmethod_id =
                                      finishingMethodID)
                           END) END), -1)
        INTO sqItemInCirculationID
        FROM dual        ;
    EXCEPTION
      WHEN no_data_found THEN
        sqItemInCirculationID := -1;
    END;

    RETURN sqItemInCirculationID;

  END getSqItemInCircOnUiRentForStmt;

  PROCEDURE createOrStoreOnSqForUiRent(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                       customerID            customer.customer_id%TYPE,
                                       departmentID          department.department_id%TYPE,
                                       distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                       productID             product.product_id%TYPE,
                                       sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                       finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                       wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                       sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                       noOfUniqueItems       INT,
                                       inactivePLPC          INT,
                                       sizeStarID            sizedefinition.sizedefinition_id%TYPE) --
   IS

    --declaration of variables
    vQtyRentedDepositStock INT;
    plpcID                 productlistpercustomer.productlistpercustomer_id%TYPE := -1;
    billingMethod          productlistpercustomer.billingMethod%TYPE := -1;
    seasonTypeID           seasontype.seasontype_id%TYPE := -1;
    depositStockAllowed    productlistpercustomer.depositStockAllowed%TYPE;
    percAfterDepreciation  productlistpercustomer.percentageafterdepreciation%TYPE := 0;
    emblemTemplateID       emblemtemplate.emblemtemplate_id%TYPE;
    isActive               BOOLEAN := FALSE;
    found_plpc             BOOLEAN;
    typeOfMerchandise      product.typeofmerchandise%TYPE;
    inventorybillingtype   productlistpercustomer.inventorybillingtype%TYPE := -1;
    seasonalRent            productlistpercustomer.seasonalrent%TYPE := 0;
  BEGIN

    --  compute qtyrenteddepositstock
    vQtyRentedDepositStock := noOfUniqueItems;

    -- search for SQItemInCirculationIDOnUniqueItemForRent
    IF (sqItemInCirculationID = -1 AND wearerEmploymentID > 0) THEN
      BEGIN
        SELECT sq.sqitemincirculation_id
          INTO sqItemInCirculationID
          FROM sqitemincirculation sq
         WHERE sq.statusquoheader_id = sqHeaderID
               AND sq.distributionpoint_link_id = distributionPointID
               AND sq.weareremployment_link_id = wearerEmploymentID
               AND sq.product_link_id = productID
               AND sq.sizedefinition_link_id = sizeDefinitionID
               AND sq.finishingmethod_id = finishingMethodID;
      EXCEPTION
        WHEN no_data_found THEN
          sqItemInCirculationID := -1;
      END;
    END IF;

    --insert / update
    insertValuesIntoSqItemInCirc(sqItemInCirculationID,
                                 sqHeaderID,
                                 customerID,
                                 departmentID,
                                 distributionPointID,
                                 wearerEmploymentID,
                                 productID,
                                 sizeDefinitionID,
                                 finishingMethodID,
                                 0, --maxinv
                                 0, --qtytotalcircinv
                                 0, --changesPerWeek,
                                 0, --maxFreeOfCharge,
                                 0, --qtyfree
                                 0, --cogcircin
                                 0, --qtyfreeseason
                                 0, --beyondlifetimecirc
                                 0, --qtyrentedperpiece
                                 0, --qtyrentother
                                 0, --qtycustrentstop
                                 0, --qtyrentstop
                                 NULL, -- emblemTemplateID,
                                 0, --qtyrentemblem
                                 0, --qtyreplacement
                                 0, --qtyassigned
                                 vQtyRentedDepositStock, --qtyrenteddepositstock
                                 0, --qtysubstitute
                                 'N', --chargeafterdepreciation
                                 0, -- QtyRentedPerPiecePool
                                 0, -- QtyRentedReturnRent
                                 0, -- QtyRentedMinRent
                                 0);

    --find plpc for statusQuo.Date
BEGIN
    found_plpc := getPLPC(customerID,
                          productID,
                          sizeDefinitionID,
                          finishingMethodID,
                          sizeStarID,
                          inactivePLPC,
                          0,
                          billingMethod,
                          seasontypeid,
                          emblemTemplateID,
                          depositStockAllowed,
                          percafterdepreciation,
                          plpcID,
                          isActive,
                          inventoryBillingType, seasonalRent);
EXCEPTION
WHEN OTHERS THEN
/*write_log('No active PLPC was found for customerID ' || customerID ||
                    ' productID ' || productID || ' sizeDefinitionID ' ||
                    sizeDefinitionID || ' finishingMethodID ' || finishingMethodID || ' in date ' ||
                    sq_date,
                    3);*/
                    commit;
END;
    --update plpc
    BEGIN
      SELECT pro.typeofmerchandise
        INTO typeOfMerchandise
        FROM product pro
       WHERE pro.product_id = productID;
    EXCEPTION
      WHEN no_data_found THEN
        typeOfMerchandise := -1;
    END;

    IF (typeOfMerchandise = TYPEOFMERCHANDISE_Garment) THEN
      updatePLPC(plpcID,
                 0, --qtytotalcircinv
                 0, --qtyrentedperpiece
                 0, --qtyrentother
                 vQtyRentedDepositStock,
				 'F',
				 0);
    END IF;
  END createOrStoreOnSqForUiRent;

  FUNCTION getStayID(vStayType stay.staytype %TYPE,
                     vStayNr   stay.staynr%TYPE) RETURN stay.stay_id%TYPE IS

    --declaration of variables
    vStayID stay.stay_id%TYPE;

  BEGIN

    BEGIN
      SELECT st.stay_id
        INTO vStayID
        FROM stay st
       WHERE st.staytype = vStayType
             AND st.staynr = vStayNr;
    EXCEPTION
      WHEN no_data_found THEN
        vStayID := -1;
    END;

    RETURN vStayID;

  END;

  PROCEDURE createOrStoreOnSQforUniqueItem(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                           inactivePLPC          INT,
                                           customerID            customer.customer_id%TYPE,
                                           departmentID          department.department_id%TYPE,
                                           distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                           productID             product.product_id%TYPE,
                                           sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                           finishingMethodID     IN OUT finishingmethod.finishingmethod_id%TYPE,
                                           wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                           emblemTemplateID      IN OUT emblemtemplate.emblemtemplate_id%TYPE,
                                           sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                                           invoiceReplacements   INT,
                                           invoiceSubstitutes    INT,
                                           sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                           sqOnWearerLevel       INT,
                                           qtyTotal              IN OUT sqitemincirculation.totalcircinv%TYPE, --countNUI
                                           qtyCOG                IN OUT sqitemincirculation.cogcircinv%TYPE, --countCustomerOwnedUI
                                           qtyAssigned           IN OUT sqitemincirculation.qtyassigned%TYPE, --countQtyAssigned
                                           qtyFree               IN OUT sqitemincirculation.freeissuedcircinv%TYPE, --countExtraGarmentUI
                                           qtyCustRentStop       IN OUT sqitemincirculation.qtycustomerrentstop%TYPE, --countCustomerRentStop
                                           qtyRentStop           IN OUT sqitemincirculation.qtyrentstop%TYPE, --countWearerInvRentStop
                                           qtyFreeSeason         IN OUT sqitemincirculation.freeseasoncircinv%TYPE, --countQtyFreeSeason
                                           qtyReplacement        IN OUT sqitemincirculation.qtyreplacement%TYPE, --countQtyReplacement
                                           qtySubstitute         IN OUT sqitemincirculation.qtysubstitute%TYPE, --countQtySubstitute
                                           qtyDepositStock       IN OUT sqitemincirculation.qtyrenteddepositstock%TYPE, -- countQtyRentDepositStock
                                           qtyBeyondLifeTime     IN OUT sqitemincirculation.beyondlifetimecirc%TYPE, --countFullRentUI
                                           qtyLease              IN OUT sqitemincirculation.qtyrentedother%TYPE, --countQtyLease
                                           qtyFullyAmortized     IN OUT sqitemincirculation.qtyfullyamortized%TYPE, --countQtyFullyAmortized
                                           qtyRentedPerPiecePool IN OUT sqitemincirculation.qtyrentedperpiecepool%TYPE --qtyRentedPerPiecePool
                                           ) IS

    qtyTotalCircInv     sqitemincirculation.totalcircinv%TYPE := qtyTotal; --countNUI
    qtyReplacement_used sqitemincirculation.qtyreplacement%TYPE := 0; --countQtyReplacement
    qtySubstitute_used  sqitemincirculation.qtysubstitute%TYPE := 0; --countQtySubstitute

    foundPLPC           BOOLEAN;
    billingMehod        productlistpercustomer.billingmethod%TYPE := -1;
    seasonTypeID        seasontype.seasontype_id%TYPE := -1;
    depositStockAllowed productlistpercustomer.depositstockallowed%TYPE := 'N';
    percAfterDeprec     productlistpercustomer.percentageafterdepreciation%TYPE := 0;
    plpcID              productlistpercustomer.productlistpercustomer_id%TYPE := -1;
    isActive            BOOLEAN := FALSE;
    qtyRentedPerPiece   sqitemincirculation.qtyrentedperpiece%TYPE := 0;
    qtyRentOther        sqitemincirculation.qtyrentedother%TYPE := 0;
    qtyRentEmblem       sqitemincirculation.qtyrentemblem%TYPE := 0;

    chargeAfterDepreciation VARCHAR2(1);
    typeOfMerchandise      product.typeofmerchandise%TYPE;
    inventorybillingtype   productlistpercustomer.inventorybillingtype%TYPE := -1;
    maxinv                 wearerinventory.maxinventory%TYPE := 0;
    seasonalRent           productlistpercustomer.seasonalrent%TYPE := 0;
    diff INT := 0;

  BEGIN

    --calculate SUM fields

    IF (finishingMethodID = -1) THEN
      finishingMethodID := getFinMethodFromWearerInv(distributionPointID,
                                                     productID,
                                                     sizeDefinitionID,
                                                     wearerEmploymentID,
                                                     sqOnWearerLevel);
    END IF;

    --find plpc for statusQuo.Date
BEGIN
    foundPLPC := getplpc(customerID,
                         productID,
                         sizeDefinitionID,
                         finishingMethodID,
                         sizestarID,
                         inactivePLPC,
                         sqonwearerlevel,
                         billingMehod,
                         seasonTypeID,
                         emblemTemplateID,
                         depositStockAllowed,
                         percAfterDeprec,
                         plpcID,
                         isActive,
                         inventoryBillingType, seasonalRent);
EXCEPTION
WHEN OTHERS THEN
/*write_log('No active PLPC was found for customerID ' || customerID ||
                    ' productID ' || productID || ' sizeDefinitionID ' ||
                    sizeDefinitionID || ' finishingMethodID ' || finishingMethodID || ' in date ' ||
                    sq_date,
                    3);*/
                    commit;
END;

    --checks
    -- IF (foundPLPC) THEN --LCO

    IF (isActive = FALSE AND inactivePLPC = 2) THEN
      qtyTotalCircInv := 0;
    END IF;

    qtyRentOther := qtyLease;
    diff         := qtyTotal - qtyAssigned - qtyCOG - qtyLease - qtyFree;

    IF (qtyCustRentStop > 0) THEN
      qtyCustRentStop   := diff;
      qtyRentStop       := 0;
      qtyFreeSeason     := 0;
      qtyBeyondLifeTime := 0;
      qtyFullyAmortized := 0;
      qtyReplacement    := 0;
      qtySubstitute     := 0;
      qtyRentedPerPiece := 0;
      qtyRentEmblem     := 0;
      qtyRentedPerPiecePool     := 0;
    ELSE
      qtyCustRentStop := 0;

      IF (invoicereplacements = 1) THEN
        qtyReplacement_used := 0;
      END IF;

      IF (invoicesubstitutes = 1) THEN
        qtySubstitute_used := 0;
      END IF;

      IF (seasontypeID <> -1 and seasonalRent = 2) THEN
         qtyFreeSeason := 0;
      END IF;

      diff := diff - qtyRentStop - qtyFreeSeason - qtyFullyAmortized;


      IF ((foundPLPC AND billingMehod = bill_circulating_inventory OR
          (billingMehod = BILL_RENT_BASED_MINIMUM AND underuseMethodSS = 4))
         AND (isActive OR inactiveplpc = 0)) THEN

        diff := diff - qtyBeyondLifeTime;
        IF (depositStockAllowed = 'Y') THEN
          qtyRentedPerPiece := diff - qtyReplacement_used -
                               qtySubstitute_used - qtyDepositStock;
          IF (inventoryBillingType = INVENTORY_BILLING_TYPE_MAX AND bm3MaxInvReduceDepositSS = 1
                    AND sqItemInCirculationID > -1) THEN
            BEGIN
              SELECT x.maxinv
                INTO maxinv
                FROM sqitemincirculation x
               WHERE x.sqitemincirculation_id = sqItemInCirculationID and x.maxinv >= qtyDepositStock;
            EXCEPTION
              WHEN no_data_found THEN
                maxinv := 0;
            END;
            IF (maxinv > 0) THEN
              maxinv := - qtyDepositStock;
            END IF;
          END IF;
        ELSE
          qtyDepositStock := 0;
          IF (isActive = TRUE OR inactivePLPC = 0) THEN
            qtyRentedPerPiece := diff - qtyReplacement_used -
                                 qtySubstitute_used;
          END IF;
        END IF;

        IF (emblemtemplateID <> -1) THEN
          qtyRentEmblem := diff;
        END IF;
      ELSE
        qtyDepositStock   := 0;
        qtyBeyondLifeTime := 0;
        qtyRentedPerPiece := 0;

        IF (isActive OR inactiveplpc = 1) THEN
          qtyBeyondLifeTime := 0;
          qtyRentOther      := diff;
          IF (emblemtemplateID <> -1) THEN
            qtyRentEmblem := diff;
          END IF;
        END IF;
      END IF;
    END IF;

    chargeAfterDepreciation := 'N';
    IF (billingMehod = BILL_CIRCULATING_INVENTORY AND PercAfterDeprec > 0) THEN
      chargeAfterDepreciation := 'Y';
    END IF;
    IF (qtyRentedPerPiece < 0) THEN
      qtyRentedPerPiece := 0;
    END IF;
    IF (qtyRentedPerPiecePool < 0) THEN
      qtyRentedPerPiecePool := 0;
    END IF;
    IF (qtyRentOther < 0) THEN
      qtyRentOther := 0;
    END IF;
    IF (emblemTemplateID = -1) THEN
       emblemTemplateID := null;
    END IF;

    --insertion/update
    insertvaluesintosqitemincirc(sqItemInCirculationID,
                                 sqHeaderID,
                                 customerID,
                                 departmentID,
                                 distributionpointID,
                                 weareremploymentID,
                                 productID,
                                 sizedefinitionID,
                                 finishingmethodID,
                                 maxinv,
                                 qtyTotalCircInv,
                                 0,
                                 0,
                                 qtyFree,
                                 qtyCOG, --COGCIRCINV
                                 qtyFreeSeason,
                                 qtyBeyondLifeTime, --BEYONDLIFETIMECIRC
                                 qtyRentedPerPiece,
                                 qtyRentOther,
                                 qtyCustRentStop,
                                 qtyRentStop,
                                 emblemTemplateID,
                                 qtyRentEmblem,
                                 qtyReplacement,
                                 qtyAssigned,
                                 qtyDepositStock, --QTYRENTEDDEPOSITSTOCK
                                 qtySubstitute, --QTYSUBSTITUTE
                                 chargeAfterDepreciation,
                                 qtyRentedPerPiecePool, -- QtyRentedPerPiecePool
                                 0, -- QtyRentedReturnRent
                                 0, -- QtyRentedMinRent
                                 qtyFullyAmortized);

    --update plpc
    SELECT pr.typeofmerchandise
      INTO typeOfMerchandise
      FROM product pr
     WHERE pr.product_id = productid;

    IF (typeofMerchandise = TYPEOFMERCHANDISE_Garment) THEN
      updatePLPC(plpcID,
                 qtyTotalCircInv,
                 qtyRentedPerPiece,
                 qtyRentOther,
                 qtyDepositStock,
				 chargeAfterDepreciation,
				 qtyBeyondLifeTime);
    END IF;

    --  END IF;

  END;

  FUNCTION getFinMethodFromWearerInv(distributionPointID distributionpoint.distributionpoint_id%TYPE,
                                     productID           product.product_id%TYPE,
                                     sizeDefinitionID    sizedefinition.sizedefinition_id%TYPE,
                                     wearerEmploymentID  weareremployment.weareremployment_id%TYPE,
                                     sqonwearerlevel     INT)
    RETURN finishingmethod.finishingmethod_id%TYPE IS

    --declaration of variables
    finMethID finishingmethod.finishingmethod_id%TYPE;

  BEGIN

    IF (sqonwearerlevel = 1) THEN
      BEGIN
        SELECT w.finishingmethod_id
          INTO finMethID
          FROM wearerinventory w
         WHERE w.weareremployment_id = wearerEmploymentID
               AND w.product_id = productID
               AND w.sizedefinition_id = sizeDefinitionID;
      EXCEPTION
        WHEN no_data_found THEN
          finMethID := -1;
      END;
    ELSE
      BEGIN
        SELECT w.finishingmethod_id
          INTO finMethID
          FROM wearerinventory w, weareremployment e
         WHERE w.weareremployment_id = e.weareremployment_id
               AND e.distributionpoint_id = distributionPointID
               AND w.product_id = productID
               AND w.sizedefinition_id = sizeDefinitionID;
      EXCEPTION
        WHEN no_data_found THEN
          finMethID := -1;
      END;
    END IF;

    RETURN finMethID;
  END; --getFinishingMethodFromWearerInventory

  FUNCTION getWearerEmploymentLinkID(wearerEmploymentID weareremployment.weareremployment_id%TYPE)
    RETURN weareremployment.weareremployment_id%TYPE IS
    v_WearerEmploymentLinkID weareremployment.weareremployment_id%TYPE;
  BEGIN
    IF wearerEmploymentID = -1 THEN
      v_WearerEmploymentLinkID := NULL;
    ELSE
      v_WearerEmploymentLinkID := wearerEmploymentID;
    END IF;
    RETURN v_WearerEmploymentLinkID;
  END getWearerEmploymentLinkID;

----- mba

  PROCEDURE createOrStoreOnSqForPoolItems(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                       customerID            customer.customer_id%TYPE,
                                       departmentID          department.department_id%TYPE,
                                       distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                       wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                       productID             product.product_id%TYPE,
                                       sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                       finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                       sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                       noOfUniqueItems       INT,
                                       qtyRentStop           INT) --
   IS

    --declaration of variables
    vQtyRentedPerPiecePool INT;
    qtycustrentstop INT;
  BEGIN
    qtycustrentstop := 0; --countCustomerRentStop
    --  compute qtyrentedperPiecePool
    vQtyRentedPerPiecePool := noOfUniqueItems;
    BEGIN
      SELECT COUNT(t.temporarygarmentrentstop_id)
        INTO qtycustrentstop
        FROM temporarygarmentrentstop t
       WHERE t.customer_id = customerID
             AND f_isinyearweeklifespan(startyear,
                                        startweek,
                                        sq_year,
                                        sq_week,
                                        endyear,
                                        endweek) = 1;
    EXCEPTION
      WHEN no_data_found THEN
        qtycustrentstop := 0;
    END;

    IF (qtycustrentstop > 0) THEN
      qtycustrentstop   := noOfUniqueItems;
      vQtyRentedPerPiecePool := 0;
    END IF;
    -- search for SQItemInCirculationIDForPoolItems
    IF (sqItemInCirculationID = -1) THEN
      BEGIN
        SELECT sq.sqitemincirculation_id
          INTO sqItemInCirculationID
          FROM sqitemincirculation sq
         WHERE sq.statusquoheader_id = sqHeaderID
               AND sq.distributionpoint_link_id = distributionPointID
               AND coalesce(sq.weareremployment_link_id , -1) = coalesce(wearerEmploymentID, -1)
               AND sq.product_link_id = productID
               AND sq.sizedefinition_link_id = sizeDefinitionID
               AND sq.finishingmethod_id = finishingMethodID;
      EXCEPTION
        WHEN no_data_found THEN
          sqItemInCirculationID := -1;
      END;
    END IF;

    --insert / update
    insertValuesIntoSqItemInCirc(sqItemInCirculationID,
                                 sqHeaderID,
                                 customerID,
                                 departmentID,
                                 distributionPointID,
                                 wearerEmploymentID, --weareremployment
                                 productID,
                                 sizeDefinitionID,
                                 finishingMethodID,
                                 0, --maxinv
                                 0, --qtytotalcircinv
                                 0, --changesPerWeek,
                                 0, --maxFreeOfCharge,
                                 0, --qtyfree
                                 0, --cogcircin
                                 0, --qtyfreeseason
                                 0, --beyondlifetimecirc
                                 0, --qtyrentedperpiece
                                 0, --qtyrentother
                                 qtycustrentstop, --qtycustrentstop
                                 qtyRentStop, --qtyrentstop
                                 null, -- emblemTemplateID,
                                 0, --qtyrentemblem
                                 0, --qtyreplacement
                                 0, --qtyassigned
                                 0, --qtyrenteddepositstock
                                 0, --qtysubstitute
                                 'N', --chargeafterdepreciation
                                 vQtyRentedPerPiecePool - qtyRentStop,
                                 0, -- QtyRentedReturnRent
                                 0, -- QtyRentedMinRent
                                 0);

  END createOrStoreOnSqForPoolItems;

  PROCEDURE createSqItemInCircForPoolItems(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                           processBuID                  businessunit.businessunit_id%TYPE,
                                           invoiceBuID                  businessunit.businessunit_id%TYPE,
                                           sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                           checkInvoiceBu               INT) IS

    -- declation of variables
    sqItemInCirculationID sqitemincirculation.sqitemincirculation_id%TYPE := -1;

    --declaration of cursors
    CURSOR stmtC IS
SELECT dp.department_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       ui.distributionpoint_id,
       dep.customer_id,
       COUNT(ui.uniqueitem_id) noOfUniqueItems,
       sum(coalesce( (select 1 from standarddeliveryline y, productlistperdistribpoint plpdp
                 where y.productlistperdistribpoint_id = plpdp.productlistperdistribpoint_id and
                   plpdp.distributionpoint_id = ui.distributionpoint_id and
                 --  y.productlistpercustomer_id = plpc.productlistpercustomer_id and
                   plpdp.product_id = p.product_id and
                   plpdp.sizedefinition_id = sd.sizedefinition_id and
                   plpdp.finishingmethod_id = ui.finishingmethod_id and
                       exists (select tds.standarddeliveryline_id from temporarydeliverystop tds
                               where tds.standarddeliveryline_id = y.standarddeliveryline_id and
                                     ((tds.tempstoprentforweek = 'Y' and
                                       (sq_week between tds.temporarystopstartweek and tds.temporarystopendweek) or
                                       (tds.temporarystopstartweek > tds.temporarystopendweek and ((sq_week <= tds.temporarystopendweek and 0 < sq_week ) or (temporarystopstartweek <= sq_week and sq_week <= 53)))) or
                                      (tds.tempstoprentforyearweek = 'Y' and
                                       f_isinyearweeklifespan(tds.temporarystopstartyear, tds.tempstopstartweekforyear,
                                                               sq_year, sq_week,
                                                               tds.temporarystopendyear, tds.tempstopendweekforyear) = 1) or
                                       (tds.tempstoprentfordate = 'Y' and (tds.startdate<= sysdate and sysdate <= tds.enddate)) ))
                       )
           , 0))  rentStop
  FROM uniqueitem         ui,
       department         dep,
       distributionpoint  dp,
       product            p,
       sizedefinition     sd
  WHERE ( UI.STATUS_ID = PACK_SQITEMSINCIRCULATION_OLD.GETSTATUSID('UI', '20') OR UI.STATUS_ID = PACK_SQITEMSINCIRCULATION_OLD.GETSTATUSID('UI', '30'))
   AND (ui.stay_id = PACK_SQITEMSINCIRCULATION_OLD.GETSTAYID(STAY_TYPE_GARMENT, 20)
       or ui.stay_id = PACK_SQITEMSINCIRCULATION_OLD.GETSTAYID(STAY_TYPE_GARMENT, 27)
       or ui.stay_id = PACK_SQITEMSINCIRCULATION_OLD.GETSTAYID(STAY_TYPE_GARMENT, 28))
   AND ui.distributionpoint_id = dp.distributionpoint_id
   AND dp.department_id = dep.department_id
   AND p.product_id = nvl(ui.substituteforproduct_id, ui.product_id)
   AND exists (select 1 from productgroup pg, customeractivities ca
             where abs(ca.activity_id) = abs(pg.activity_id)
             AND abs(ca.processbusinessunit_id) = abs(ui.businessunit_id)
             AND pg.productgroup_id = p.productgroup_id
             AND ca.customer_id = dep.customer_id
             AND ca.processbusinessunit_id = processBuID)
   AND not exists (select 1 from uniqueitemloss uil where uil.uniqueitem_link_id = ui.uniqueitem_id and
                (uil.lossstatus = 0 or uil.lossstatus = 1) and ui.LASTOUTSCANDATE = uil.OUTSCANDATE)
   AND sd.sizedefinition_id = nvl(ui.substituteforsizedefinition_id, ui.sizedefinition_id)
   AND trunc(ui.lastoutscandate) < trunc(sysdate) -
       7 *
       (SELECT plpc.chargerentnoreturnpoolafterwks
          FROM productlistpercustomer plpc
         WHERE plpc.productlistpercustomer_id =
               (SELECT coalesce((SELECT plpc1.productlistpercustomer_id
                                  FROM productlistpercustomer plpc1
                                 WHERE plpc1.billingmethod = 3
                                   AND plpc1.inventorybillingtype = 4
                                   AND plpc1.chargerentnoreturnpoolafterwks > 0
                                   AND plpc1.chargerentnotreturned <> 1
                                   AND plpc1.codeuniquely = 'Y'
                                   AND p.uniquepoolitem ='Y'
                                   AND plpc1.customer_id = dep.customer_id
                                   AND plpc1.product_id = p.product_id
                                   AND plpc1.sizedefinition_id = sd.sizedefinition_id
                                   AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                   AND plpc1.dateactive =
                                       (select max(plpc2.dateactive)
                                        from productlistpercustomer plpc2
                                       where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                         and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                         and plpc2.product_id = plpc1.product_id
                                         and plpc2.customer_id = plpc1.customer_id
                                         and plpc2.dateactive < sysdate
                                         and plpc2.billingmethod = 3
                                         and plpc2.inventorybillingtype = 4
                                         and plpc2.chargerentnoreturnpoolafterwks > 0
                                         AND plpc2.chargerentnotreturned <> 1
                                         and plpc2.codeuniquely = 'Y')),
                                (CASE sd.sizedefinition_id
                                  WHEN sizeStarID THEN
                                   -1
                                  ELSE
                                   coalesce((SELECT plpc1.productlistpercustomer_id
                                              FROM productlistpercustomer plpc1
                                             WHERE plpc1.billingmethod = 3
                                               AND plpc1.inventorybillingtype = 4
                                               AND plpc1.chargerentnoreturnpoolafterwks > 0
                                               AND plpc1.chargerentnotreturned <> 1
                                               AND plpc1.codeuniquely = 'Y'
                                               AND p.uniquepoolitem = 'Y'
                                               AND plpc1.customer_id = dep.customer_id
                                               AND plpc1.product_id = p.product_id
                                               AND plpc1.sizedefinition_id =
                                                   sizeStarID
                                               AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                               AND plpc1.dateactive =
                                               (select max(plpc2.dateactive)
                                                from productlistpercustomer plpc2
                                               where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                                 and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                                 and plpc2.product_id = plpc1.product_id
                                                 and plpc2.customer_id = plpc1.customer_id
                                                 and plpc2.dateactive < sysdate
                                                 and plpc2.billingmethod = 3
                                                 and plpc2.inventorybillingtype = 4
                                                 and plpc2.chargerentnoreturnpoolafterwks > 0
                                                 AND plpc2.chargerentnotreturned <> 1
                                                 and plpc2.codeuniquely = 'Y')),
                                            -1)
                                END))
                  FROM dual))
 GROUP BY dp.department_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       ui.distributionpoint_id,
       dep.customer_id;

    CURSOR stmtC_checkinvoicedbu IS
SELECT dp.department_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       ui.distributionpoint_id,
       dep.customer_id,
       COUNT(ui.uniqueitem_id) noOfUniqueItems,
       sum(coalesce( (select 1 from standarddeliveryline y, productlistperdistribpoint plpdp
                 where y.productlistperdistribpoint_id = plpdp.productlistperdistribpoint_id and
                   plpdp.distributionpoint_id = ui.distributionpoint_id and
                 --  y.productlistpercustomer_id = plpc.productlistpercustomer_id and
                   plpdp.product_id = p.product_id and
                   plpdp.sizedefinition_id = sd.sizedefinition_id and
                   plpdp.finishingmethod_id = ui.finishingmethod_id and
                       exists (select tds.standarddeliveryline_id from temporarydeliverystop tds
                               where tds.standarddeliveryline_id = y.standarddeliveryline_id and
                                     ((tds.tempstoprentforweek = 'Y' and
                                       (sq_week between tds.temporarystopstartweek and tds.temporarystopendweek) or
                                       (tds.temporarystopstartweek > tds.temporarystopendweek and ((sq_week <= tds.temporarystopendweek and 0 < sq_week ) or (temporarystopstartweek <= sq_week and sq_week <= 53)))) or
                                      (tds.tempstoprentforyearweek = 'Y' and
                                       f_isinyearweeklifespan(tds.temporarystopstartyear, tds.tempstopstartweekforyear,
                                                               sq_year, sq_week,
                                                               tds.temporarystopendyear, tds.tempstopendweekforyear) = 1)or
                                       (tds.tempstoprentfordate = 'Y' and (tds.startdate<= sysdate and sysdate <= tds.enddate)) ))
                  )
           , 0)) rentStop
  FROM uniqueitem          ui,
       department         dep,
       distributionpoint  dp,
       product             p,
       sizedefinition      sd
  WHERE ( UI.STATUS_ID = pack_sqitemsincirculation_OLD.GETSTATUSID('UI', '20') OR UI.STATUS_ID = pack_sqitemsincirculation_OLD.GETSTATUSID('UI', '30'))
   AND (ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 20)
       or ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 27)
       or ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 28))
   AND ui.distributionpoint_id = dp.distributionpoint_id
   AND dp.department_id = dep.department_id
   AND p.product_id = nvl(ui.substituteforproduct_id, ui.product_id)
   AND exists (select 1 from productgroup pg, customeractivities ca
             where abs(ca.activity_id) = abs(pg.activity_id)
             AND abs(ca.processbusinessunit_id) = abs(ui.businessunit_id)
             AND pg.productgroup_id = p.productgroup_id
             AND ca.customer_id = dep.customer_id
             AND ca.processbusinessunit_id = processBuID
             AND ca.invoicebusinessunit_id = invoiceBuID)
   AND sd.sizedefinition_id = nvl(ui.substituteforsizedefinition_id, ui.sizedefinition_id)
   AND not exists (select 1 from uniqueitemloss uil where uil.uniqueitem_link_id = ui.uniqueitem_id and
             (uil.lossstatus = 0 or uil.lossstatus = 1) and ui.LASTOUTSCANDATE = uil.OUTSCANDATE)
   AND trunc(ui.lastoutscandate) < trunc(sysdate) -
       7 *
       (SELECT plpc.chargerentnoreturnpoolafterwks
          FROM productlistpercustomer plpc
         WHERE plpc.productlistpercustomer_id =
               (SELECT coalesce((SELECT plpc1.productlistpercustomer_id
                                  FROM productlistpercustomer plpc1
                                 WHERE plpc1.billingmethod = 3
                                   AND plpc1.inventorybillingtype = 4
                                   AND plpc1.chargerentnoreturnpoolafterwks > 0
                                   AND plpc1.chargerentnotreturned <> 1
                                   AND plpc1.codeuniquely = 'Y'
                                   AND p.uniquepoolitem = 'Y'
                                   AND plpc1.customer_id = dep.customer_id
                                   AND plpc1.product_id = p.product_id
                                   AND plpc1.sizedefinition_id = sd.sizedefinition_id
                                   AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                   AND plpc1.dateactive =
                                   (select max(plpc2.dateactive)
                                    from productlistpercustomer plpc2
                                   where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                     and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                     and plpc2.product_id = plpc1.product_id
                                     and plpc2.customer_id = plpc1.customer_id
                                     and plpc2.dateactive < sysdate
                                     and plpc2.billingmethod = 3
                                     and plpc2.inventorybillingtype = 4
                                     and plpc2.chargerentnoreturnpoolafterwks > 0
                                     AND plpc2.chargerentnotreturned <> 1
                                     and plpc2.codeuniquely = 'Y')),
                                (CASE sd.sizedefinition_id
                                  WHEN sizeStarID THEN
                                   -1
                                  ELSE
                                   coalesce((SELECT plpc1.productlistpercustomer_id
                                              FROM productlistpercustomer plpc1
                                             WHERE plpc1.billingmethod = 3
                                               AND plpc1.inventorybillingtype = 4
                                               AND plpc1.chargerentnoreturnpoolafterwks > 0
                                               AND plpc1.chargerentnotreturned <> 1
                                               AND plpc1.codeuniquely = 'Y'
                                               AND p.uniquepoolitem = 'Y'
                                               AND plpc1.customer_id = dep.customer_id
                                               AND plpc1.product_id = p.product_id
                                               AND plpc1.sizedefinition_id =
                                                   sizeStarID
                                               AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                               AND plpc1.dateactive =
                                                   (select max(plpc2.dateactive)
                                                    from productlistpercustomer plpc2
                                                   where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                                     and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                                     and plpc2.product_id = plpc1.product_id
                                                     and plpc2.customer_id = plpc1.customer_id
                                                     and plpc2.dateactive < sysdate
                                                     and plpc2.billingmethod = 3
                                                     and plpc2.inventorybillingtype = 4
                                                     and plpc2.chargerentnoreturnpoolafterwks > 0
                                                     AND plpc2.chargerentnotreturned <> 1
                                                     and plpc2.codeuniquely = 'Y')),
                                            -1)
                                END))
                  FROM dual))
 GROUP BY dp.department_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       ui.distributionpoint_id,
       dep.customer_id;

  BEGIN

    IF (checkInvoiceBu = 1) THEN
      FOR rs_checkBu IN stmtC_checkinvoicedbu LOOP
        BEGIN
          --search if exists an sqitemincircID
          SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                                rs_checkBu.distributionpoint_id,
                                                null,
                                                rs_checkBu.product_id,
                                                rs_checkBu.sizedefinition_id,
                                                rs_checkBu.finishingmethod_id)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;

        -- create / store a sqitemincirc
        createOrStoreOnSqForPoolItems(sqHeaderID,
                                   rs_checkBu.customer_id,
                                   rs_checkBu.department_id,
                                   rs_checkBu.distributionpoint_id,
                                   null,
                                   rs_checkBu.product_id,
                                   rs_checkBu.sizedefinition_id,
                                   rs_checkBu.finishingmethod_id,
                                   sqItemInCirculationID,
                                   rs_checkBu.noOfUniqueItems,
                                   rs_checkBu.rentStop);
      END LOOP;
    ELSE
      FOR rs IN stmtC LOOP
        BEGIN
          --search if exists an sqitemincircID
          SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                                rs.distributionpoint_id,
                                                null,
                                                rs.product_id,
                                                rs.sizedefinition_id,
                                                rs.finishingmethod_id)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;

        -- create / store a sqitemincirc
        createOrStoreOnSqForPoolItems(sqHeaderID,
                                   rs.customer_id,
                                   rs.department_id,
                                   rs.distributionpoint_id,
                                   null,
                                   rs.product_id,
                                   rs.sizedefinition_id,
                                   rs.finishingmethod_id,
                                   sqItemInCirculationID,
                                   rs.noOfUniqueItems,
                                   rs.rentStop);
      END LOOP;
    END IF;

  END createSqItemInCircForPoolItems;

  PROCEDURE createSqItemInCircForPoolDummy(sqHeaderID                   statusquoheader.statusquoheader_id%TYPE,
                                               processBuID                  businessunit.businessunit_id%TYPE,
                                               invoiceBuID                  businessunit.businessunit_id%TYPE,
                                               sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                               checkInvoiceBu               INT) IS

    -- declation of variables
    sqItemInCirculationID sqitemincirculation.sqitemincirculation_id%TYPE := -1;

    --declaration of cursors
    CURSOR stmtC IS
SELECT dp.department_id, we.weareremployment_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       we.distributionpoint_id,
       dep.customer_id,
       COUNT(ui.uniqueitem_id) noOfUniqueItems
  FROM uniqueitem         ui, uniqueitemnonpool uinp, weareremployment we,
       department         dep,
       distributionpoint  dp,
       product            p,
       sizedefinition     sd
 WHERE ( UI.STATUS_ID = pack_sqitemsincirculation_OLD.GETSTATUSID('UI', '20') OR UI.STATUS_ID = pack_sqitemsincirculation_OLD.GETSTATUSID('UI', '30'))
   AND (ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 20)
       or ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 27)
       or ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 28))
   AND ui.poolitem = 2
   AND ui.uniqueitem_id=uinp.uniqueitem_id
   AND uinp.weareremployment_id=we.weareremployment_id
   AND exists (select 1 from wearer w where we.wearer_id=w.wearer_id AND w.dummyforpool='Y' AND w.customer_id=dep.customer_id)
   AND we.distributionpoint_id = dp.distributionpoint_id
   AND dp.department_id = dep.department_id
   AND p.product_id = nvl(ui.substituteforproduct_id, ui.product_id)
   AND exists (select 1 from productgroup pg, customeractivities ca
               where abs(ca.activity_id) = abs(pg.activity_id)
               AND abs(ca.processbusinessunit_id) = abs(ui.businessunit_id)
               AND pg.productgroup_id = p.productgroup_id
               AND ca.customer_id = dep.customer_id
               AND ca.processbusinessunit_id = processBuID)
   AND sd.sizedefinition_id = nvl(ui.substituteforsizedefinition_id, ui.sizedefinition_id)
   AND trunc(ui.lastoutscandate) < trunc(sysdate) -
       7 *
       (SELECT plpc.chargerentnoreturnpoolafterwks
          FROM productlistpercustomer plpc
         WHERE plpc.productlistpercustomer_id =
               (SELECT coalesce((SELECT plpc1.productlistpercustomer_id
                                  FROM productlistpercustomer plpc1
                                 WHERE plpc1.billingmethod = 3
                                   AND plpc1.inventorybillingtype = 4
                                   AND plpc1.chargerentnotreturned <> 1
                                   AND plpc1.chargerentnoreturnpoolafterwks > 0
                                   AND plpc1.codeuniquely = 'Y'
                                   AND p.uniquepoolitem = 'Y'
                                   AND plpc1.customer_id = dep.customer_id
                                   AND plpc1.product_id = p.product_id
                                   AND plpc1.sizedefinition_id = sd.sizedefinition_id
                                   AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                   AND plpc1.dateactive =
                                       (select max(plpc2.dateactive)
                                        from productlistpercustomer plpc2
                                       where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                         and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                         and plpc2.product_id = plpc1.product_id
                                         and plpc2.customer_id = plpc1.customer_id
                                         and plpc2.dateactive < sysdate
                                         and plpc2.billingmethod = 3
                                         and plpc2.inventorybillingtype = 4
                                         and plpc2.chargerentnoreturnpoolafterwks > 0
                                         AND plpc2.chargerentnotreturned <> 1
                                         and plpc2.codeuniquely = 'Y')),
                                (CASE sd.sizedefinition_id
                                  WHEN sizeStarID THEN
                                   -1
                                  ELSE
                                   coalesce((SELECT plpc1.productlistpercustomer_id
                                              FROM productlistpercustomer plpc1
                                             WHERE plpc1.billingmethod = 3
                                               AND plpc1.inventorybillingtype = 4
                                               AND plpc1.chargerentnoreturnpoolafterwks > 0
                                               AND plpc1.chargerentnotreturned <> 1
                                               AND plpc1.codeuniquely = 'Y'
                                               AND p.uniquepoolitem = 'Y'
                                               AND plpc1.customer_id = dep.customer_id
                                               AND plpc1.product_id = p.product_id
                                               AND plpc1.sizedefinition_id =
                                                   sizeStarID
                                               AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                               AND plpc1.dateactive =
                                               (select max(plpc2.dateactive)
                                                from productlistpercustomer plpc2
                                               where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                                 and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                                 and plpc2.product_id = plpc1.product_id
                                                 and plpc2.customer_id = plpc1.customer_id
                                                 and plpc2.dateactive < sysdate
                                                 and plpc2.billingmethod = 3
                                                 and plpc2.inventorybillingtype = 4
                                                 and plpc2.chargerentnoreturnpoolafterwks > 0
                                                 AND plpc2.chargerentnotreturned <> 1
                                                 and plpc2.codeuniquely = 'Y')),
                                            -1)
                                END))
                  FROM dual))
 GROUP BY dp.department_id, we.weareremployment_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       we.distributionpoint_id,
       dep.customer_id;

    CURSOR stmtC_checkinvoicedbu IS
SELECT dp.department_id, we.weareremployment_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       we.distributionpoint_id,
       dep.customer_id,
       COUNT(ui.uniqueitem_id) noOfUniqueItems
  FROM uniqueitem          ui, uniqueitemnonpool uinp, weareremployment we,
       department         dep,
       distributionpoint  dp,
       product             p,
       sizedefinition      sd
 WHERE ( UI.STATUS_ID = pack_sqitemsincirculation_OLD.GETSTATUSID('UI', '20') OR UI.STATUS_ID = pack_sqitemsincirculation_OLD.GETSTATUSID('UI', '30'))
   AND (ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 20)
       or ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 27)
       or ui.stay_id = pack_sqitemsincirculation_OLD.GETSTAYID(STAY_TYPE_GARMENT, 28))
   AND ui.poolitem = 2
   AND ui.uniqueitem_id=uinp.uniqueitem_id
   AND uinp.weareremployment_id=we.weareremployment_id
   AND exists (select 1 from wearer w where we.wearer_id=w.wearer_id AND w.dummyforpool='Y' AND w.customer_id=dep.customer_id)
   AND we.distributionpoint_id = dp.distributionpoint_id
   AND dp.department_id = dep.department_id
   AND p.product_id = nvl(ui.substituteforproduct_id, ui.product_id)
   AND exists (select 1 from productgroup pg, customeractivities ca
               where abs(ca.activity_id) = abs(pg.activity_id)
               AND abs(ca.processbusinessunit_id) = abs(ui.businessunit_id)
               AND pg.productgroup_id = p.productgroup_id
               AND ca.customer_id = dep.customer_id
               AND ca.processbusinessunit_id = processBuID
               AND ca.invoicebusinessunit_id = invoiceBuID)
   AND sd.sizedefinition_id = nvl(ui.substituteforsizedefinition_id, ui.sizedefinition_id)
   AND trunc(ui.lastoutscandate) < trunc(sysdate) -
       7 *
       (SELECT plpc.chargerentnoreturnpoolafterwks
          FROM productlistpercustomer plpc
         WHERE plpc.productlistpercustomer_id =
               (SELECT coalesce((SELECT productlistpercustomer_id
                                  FROM productlistpercustomer plpc1
                                 WHERE plpc1.billingmethod = 3
                                   AND plpc1.inventorybillingtype = 4
                                   AND plpc1.chargerentnoreturnpoolafterwks > 0
                                   AND plpc1.chargerentnotreturned <> 1
                                   AND plpc1.codeuniquely = 'Y'
                                   AND p.uniquepoolitem = 'Y'
                                   AND plpc1.customer_id = dep.customer_id
                                   AND plpc1.product_id = p.product_id
                                   AND plpc1.sizedefinition_id = sd.sizedefinition_id
                                   AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                   AND plpc1.dateactive =
                                   (select max(plpc2.dateactive)
                                    from productlistpercustomer plpc2
                                   where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                     and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                     and plpc2.product_id = plpc1.product_id
                                     and plpc2.customer_id = plpc1.customer_id
                                     and plpc2.dateactive < sysdate)),
                                (CASE sd.sizedefinition_id
                                  WHEN sizeStarID THEN
                                   -1
                                  ELSE
                                   coalesce((SELECT plpc1.productlistpercustomer_id
                                              FROM productlistpercustomer plpc1
                                             WHERE plpc1.billingmethod = 3
                                               AND plpc1.inventorybillingtype = 4
                                               AND plpc1.chargerentnoreturnpoolafterwks > 0
                                               AND plpc1.chargerentnotreturned <> 1
                                               AND plpc1.codeuniquely = 'Y'
                                               AND p.uniquepoolitem = 'Y'
                                               AND plpc1.customer_id = dep.customer_id
                                               AND plpc1.product_id = p.product_id
                                               AND plpc1.sizedefinition_id =
                                                   sizeStarID
                                               AND plpc1.finishingmethod_id = ui.finishingmethod_id
                                               AND plpc1.dateactive =
                                                   (select max(plpc2.dateactive)
                                                    from productlistpercustomer plpc2
                                                   where plpc2.finishingmethod_id = plpc1.finishingmethod_id
                                                     and plpc2.sizedefinition_id = plpc1.sizedefinition_id
                                                     and plpc2.product_id = plpc1.product_id
                                                     and plpc2.customer_id = plpc1.customer_id
                                                     and plpc2.dateactive < sysdate)),
                                            -1)
                                END))
                  FROM dual))
 GROUP BY dp.department_id, we.weareremployment_id,
       p.product_id,
       sd.sizedefinition_id,
       ui.finishingmethod_id,
       we.distributionpoint_id,
       dep.customer_id;

  BEGIN

    IF (checkInvoiceBu = 1) THEN
      FOR rs_checkBu IN stmtC_checkinvoicedbu LOOP
        BEGIN
          --search if exists an sqitemincircID
          SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                                rs_checkBu.distributionpoint_id,
                                                rs_checkBu.weareremployment_id,
                                                rs_checkBu.product_id,
                                                rs_checkBu.sizedefinition_id,
                                                rs_checkBu.finishingmethod_id)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;

        -- create / store a sqitemincirc
        createOrStoreOnSqForPoolItems(sqHeaderID,
                                   rs_checkBu.customer_id,
                                   rs_checkBu.department_id,
                                   rs_checkBu.distributionpoint_id,
                                   rs_checkBu.weareremployment_id,
                                   rs_checkBu.product_id,
                                   rs_checkBu.sizedefinition_id,
                                   rs_checkBu.finishingmethod_id,
                                   sqItemInCirculationID,
                                   rs_checkBu.noOfUniqueItems,
                                   0);
      END LOOP;
    ELSE
      FOR rs IN stmtC LOOP
        BEGIN
          --search if exists an sqitemincircID
          SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                                rs.distributionpoint_id,
                                                rs.weareremployment_id,
                                                rs.product_id,
                                                rs.sizedefinition_id,
                                                rs.finishingmethod_id)
            INTO sqItemInCirculationID
            FROM dual;
        EXCEPTION
          WHEN no_data_found THEN
            sqItemInCirculationID := -1;
        END;

        -- create / store a sqitemincirc
        createOrStoreOnSqForPoolItems(sqHeaderID,
                                   rs.customer_id,
                                   rs.department_id,
                                   rs.distributionpoint_id,
                                   rs.weareremployment_id,
                                   rs.product_id,
                                   rs.sizedefinition_id,
                                   rs.finishingmethod_id,
                                   sqItemInCirculationID,
                                   rs.noOfUniqueItems,
                                   0);
      END LOOP;
    END IF;

  END createSqItemInCircForPoolDummy;

  PROCEDURE createSqItemInCircOnReturnRent(sqHeaderID                  statusquoheader.statusquoheader_id%TYPE,
                                           sizeStarID                   sizedefinition.sizedefinition_id%TYPE,
                                           sqOnWearerLevel              INT,
                                           inactivePLPC                 INT) IS

    -- declation of variables
    sqItemInCirculationID  sqitemincirculation.sqitemincirculation_id%TYPE := -1;
    v_wearerEmploymentID   weareremployment.weareremployment_id%TYPE := -1;
    --declaration of cursors
    CURSOR stmtReturnRent IS
    select count(1) noofuniqueitems,
           uirr.returnrenttype,
           uirr.customer_link_id,
           dp.department_id,
           we.distributionpoint_id,
           uirr.weareremployment_link_id,
           uirr.product_link_id,
           uirr.sizedefinition_link_id,
           uirr.finishingmethod_id
      from uniqueitemreturnrent uirr,
           weareremployment     we,
           distributionpoint    dp,
           department           d
     where uirr.returnrenttype in (1, 2)
       and uirr.rentyear = sq_year
       and uirr.rentweek = sq_week
       and exists (select productlistpercustomer_id
              from productlistpercustomer plpc
             where plpc.customer_id = uirr.customer_link_id
               and plpc.product_id = uirr.product_link_id
               and (plpc.sizedefinition_id = uirr.sizedefinition_link_id or plpc.sizedefinition_id = sizeStarID)
               and plpc.finishingmethod_id = uirr.finishingmethod_id
               and plpc.dateactive <= sq_date
               and plpc.billingmethod = 3
               and plpc.inventorybillingtype in (1, 2))
       and we.weareremployment_id = uirr.weareremployment_link_id
       and we.distributionpoint_id = dp.distributionpoint_id
       and dp.department_id = d.department_id
       and exists (select sqitemincirculation_id
          from sqitemincirculation  sqi
         where sqi.statusquoheader_id = sqheaderid and sqi.customer_link_id = uirr.customer_link_id and
               sqi.product_link_id = uirr.product_link_id and sqi.totalcircinv > 0)
     group by uirr.returnrenttype,
              uirr.customer_link_id,
              dp.department_id,
              we.distributionpoint_id,
              uirr.weareremployment_link_id,
              uirr.product_link_id,
              uirr.sizedefinition_link_id,
              uirr.finishingmethod_id;

  BEGIN

  FOR rs IN stmtReturnRent LOOP
     IF (sqOnWearerLevel = 1) THEN
        v_wearerEmploymentID := rs.weareremployment_link_id;
     ELSE
        v_wearerEmploymentID := -1;
     END IF;

    BEGIN
      --search if exists an sqitemincircID
      SELECT getSqItemInCircOnUiRentForStmt(sqHeaderID,
                                            rs.distributionpoint_id,
                                            v_wearerEmploymentID,
                                            rs.product_link_id,
                                            rs.sizedefinition_link_id,
                                            rs.finishingmethod_id)
        INTO sqItemInCirculationID
        FROM dual;
    EXCEPTION
      WHEN no_data_found THEN
        sqItemInCirculationID := -1;
    END;

    -- create / store a sqitemincirc
    createOrStoreOnSqOnReturnRent(sqHeaderID,
                               inactivePLPC,
                               rs.customer_link_id,
                               rs.department_id,
                               rs.distributionpoint_id,
                               v_wearerEmploymentID,
                               rs.product_link_id,
                               rs.sizedefinition_link_id,
                               sizeStarID,
                               rs.finishingmethod_id,
                               sqItemInCirculationID,
                               rs.noOfUniqueItems,
                               rs.returnrenttype);
  END LOOP;

  END createSqItemInCircOnReturnRent;

  PROCEDURE createOrStoreOnSqOnReturnRent(sqHeaderID            statusquoheader.statusquoheader_id%TYPE,
                                       inactivePLPC          INT,
                                       customerID            customer.customer_id%TYPE,
                                       departmentID          department.department_id%TYPE,
                                       distributionPointID   distributionpoint.distributionpoint_id%TYPE,
                                       wearerEmploymentID    weareremployment.weareremployment_id%TYPE,
                                       productID             product.product_id%TYPE,
                                       sizeDefinitionID      sizedefinition.sizedefinition_id%TYPE,
                                       sizeStarID            sizedefinition.sizedefinition_id%TYPE,
                                       finishingMethodID     finishingmethod.finishingmethod_id%TYPE,
                                       sqItemInCirculationID IN OUT sqitemincirculation.sqitemincirculation_id%TYPE,
                                       noOfUniqueItems       INT,
                                       returnrenttype        INT)
   IS

    --declaration of variables
    foundplpc               BOOLEAN;
    vQtyRentedPerReturnRent INT;
    vQtyRentedPerMinRent    INT;
    emblemTemplateID       emblemTemplate.emblemTemplate_ID%TYPE := -1;
    billingMethod          productlistpercustomer.billingMethod%TYPE := -1;
    seasontypeid           seasontype.seasontype_id%TYPE := -1;
    depositStockAllowed    productlistpercustomer.depositStockAllowed%TYPE;
    percafterdeprec        productlistpercustomer.percentageafterdepreciation%TYPE := 0;
    plpcID                 productlistpercustomer.productlistpercustomer_id%TYPE := -1;
    isActive               BOOLEAN := FALSE;
    inventoryBillingType   productlistpercustomer.inventoryBillingType%TYPE := -1;
    maxinv                 wearerinventory.maxinventory%TYPE := 0;
    qtycustrentstop INT;
    qtyrentstop INT;
    vQtyRentedPerPiece INT;
    seasonalRent           productlistpercustomer.seasonalrent%TYPE := 0;
  BEGIN
    qtycustrentstop := 0; --countCustomerRentStop
    qtyrentstop := 0;

    BEGIN
      SELECT COUNT(t.temporarygarmentrentstop_id)
        INTO qtycustrentstop
        FROM temporarygarmentrentstop t
       WHERE t.customer_id = customerID
             AND f_isinyearweeklifespan(startyear,
                                        startweek,
                                        sq_year,
                                        sq_week,
                                        endyear,
                                        endweek) = 1;
    EXCEPTION
      WHEN no_data_found THEN
        qtycustrentstop := 0;
    END;

    BEGIN
      SELECT COUNT(WI.WEARERINVENTORY_ID) INTO qtyrentstop
      FROM WEARERINVENTORY WI
      WHERE WI.WEAREREMPLOYMENT_ID = wearerEmploymentID AND WI.PRODUCT_ID = productID AND
            WI.SIZEDEFINITION_ID = sizeDefinitionID AND WI.FINISHINGMETHOD_ID = finishingMethodID AND
            sysdate BETWEEN WI.TEMPORARYRENTSTOPSTARTDATE AND WI.TEMPORARYRENTSTOPENDDATE;
    EXCEPTION
      WHEN no_data_found THEN
        qtyrentstop := 0;
    END;

    --  compute
    IF (returnrenttype = 1) THEN
        vQtyRentedPerReturnRent := noOfUniqueItems;
        vQtyRentedPerMinRent := 0;
    ELSE
        vQtyRentedPerReturnRent := 0;
        vQtyRentedPerMinRent := noOfUniqueItems;
    END IF;

    IF (qtycustrentstop > 0 OR qtyrentstop > 0) THEN
      vQtyRentedPerReturnRent := 0;
      vQtyRentedPerMinRent := 0;
      vQtyRentedPerPiece :=0;
    ELSE
      vQtyRentedPerPiece   := noOfUniqueItems;
    END IF;

    IF (qtycustrentstop > 0) THEN
      qtycustrentstop   := noOfUniqueItems;
    END IF;
    IF (qtyrentstop > 0) THEN
      qtyrentstop   := noOfUniqueItems;
    END IF;

    -- search for SQItemInCirculationID
    IF (sqItemInCirculationID = -1) THEN
      BEGIN
        SELECT sq.sqitemincirculation_id
          INTO sqItemInCirculationID
          FROM sqitemincirculation sq
         WHERE sq.statusquoheader_id = sqHeaderID
               AND sq.distributionpoint_link_id = distributionPointID
               AND sq.weareremployment_link_id is null
               AND sq.product_link_id = productID
               AND sq.sizedefinition_link_id = sizeDefinitionID
               AND sq.finishingmethod_id = finishingMethodID;
      EXCEPTION
        WHEN no_data_found THEN
          sqItemInCirculationID := -1;
      END;
    END IF;

    --find plpc for statusQuo.Date
    BEGIN
            foundplpc := getPLPC(customerID,
                         productID,
                         sizeDefinitionID,
                         finishingMethodID,
                         sizeStarID,
                         inactivePLPC,
                         0,
                         billingMethod,
                         seasontypeid,
                         emblemTemplateID,
                         depositStockAllowed,
                         percAfterDeprec,
                         plpcID,
                         isActive,
                         inventoryBillingType, seasonalRent);
    EXCEPTION
    WHEN OTHERS THEN
    /*write_log('No active PLPC was found for customerID ' || customerID ||
                        ' productID ' || productID || ' sizeDefinitionID ' ||
                        sizeDefinitionID || ' finishingMethodID ' || finishingMethodID || ' in date ' ||
                        sq_date,
                        3);*/
                        commit;
    END;

    --checks
    IF (foundplpc AND (isActive OR inactivePLPC < 2)) THEN
      IF (inventoryBillingType = 2) THEN
        maxinv := noOfUniqueItems;
      END IF;
        --insert / update
      insertValuesIntoSqItemInCirc(sqItemInCirculationID,
                                   sqHeaderID,
                                   customerID,
                                   departmentID,
                                   distributionPointID,
                                   wearerEmploymentID, --weareremployment
                                   productID,
                                   sizeDefinitionID,
                                   finishingMethodID,
                                   maxinv,
                                   0, --qtytotalcircinv
                                   0, --changesPerWeek,
                                   0, --maxFreeOfCharge,
                                   0, --qtyfree
                                   0, --cogcircin
                                   0, --qtyfreeseason
                                   0, --beyondlifetimecirc
                                   vQtyRentedPerPiece, --qtyrentedperpiece
                                   0, --qtyrentother
                                   qtycustrentstop, --qtycustrentstop
                                   qtyrentstop, --qtyrentstop
                                   null, -- emblemTemplateID,
                                   0, --qtyrentemblem
                                   0, --qtyreplacement
                                   0, --qtyassigned
                                   0, --qtyrenteddepositstock
                                   0, --qtysubstitute
                                   'N', --chargeafterdepreciation
                                   0,
                                   vQtyRentedPerReturnRent,
                                   vQtyRentedPerMinRent,
                                   0);

    END IF;

  END createOrStoreOnSqOnReturnRent;

END pack_sqitemsincirculation_OLD;

/
create or replace package PACK_SQMaxItemInCirculation is

  SQ_MAX_ITEMS_IN_CIRCULATION statusquoheader.statusquotype%type := 13;

  procedure createSQMaxItemsInCirculation(sqHeaderID   out statusquoheader.statusquoheader_id%type,
                                          processBUID  businessunit.businessunit_id%type,
                                          invoiceBUID  businessunit.businessunit_id%type,
                                          sqDate       date,
                                          sqYear       int,
                                          sqWeek       int,
                                          systemUserID systemuser.systemuser_id%type,
                                          checkInvoiceBu int);

  procedure createSQItemOnUniqueItem(sqHeaderID            statusquoheader.statusquoheader_id%type,
                                     processBUID           businessunit.businessunit_id%type,
                                     invoiceBUID           businessunit.businessunit_id%type,
                                     sqDate                date,
                                     sqYear                int,
                                     sqWeek                int,
                                     statusUIInCirculation status.status_id%type,
                                     sizeStarID            sizedefinition.sizedefinition_id%type,
                                     systemUserID          systemuser.systemuser_id%type,
                                     checkInvoiceBu        int);

  procedure createSQItemOnRentalQtyAdj(sqHeaderID   statusquoheader.statusquoheader_id%type,
                                       processBUID  businessunit.businessunit_id%type,
                                       invoiceBUID  businessunit.businessunit_id%type,
                                       sqDate       date,
                                       sqYear       int,
                                       sqWeek       int,
                                       systemUserID systemuser.systemuser_id%type,
                                       checkInvoiceBu int);

  procedure createOrStoreOnSQ(sqHeaderID   statusquoheader.statusquoheader_id%type,
                              costCenterID costcenter.costcenter_id%type,
                              productID    product.product_id%type,
                              sizeID       sizedefinition.sizedefinition_id%type,
                              finMethID    finishingmethod.finishingmethod_id%type,
                              qtyPerPiece  sqmaxitemincirculation.qtyrentedperpiece%type,
                              qtyPlusAdj   sqmaxitemincirculation.qtyplusadjust%type,
                              qtyRentStop  sqmaxitemincirculation.qtyrentstop%type,
                              qtyPlusAdjRentStop    sqmaxitemincirculation.qtyplusadjustrentstop%type,
                              systemUserID systemuser.systemuser_id%type);

  procedure createOrStoreOnTrigger_UI(uniqueItemID uniqueitem.uniqueitem_id%type,
                                      qty          int,
                                      returnFromCustomerDate statusquoheader.statusquodate%type,
                                      checkInvoiceBu        int);

  procedure createOrStoreOnTrigger_RQA(plpdipID productlistperdistribpoint.productlistperdistribpoint_id%type,
                                       qty      int,
                                       returnFromCustomerDate statusquoheader.statusquodate%type,
                                       checkInvoiceBu        int);

  procedure createOrStoreOnTrigger(processBUID  businessunit.businessunit_id%type,
                                   invoiceBUID  businessunit.businessunit_id%type,
                                   costCenterID costcenter.costcenter_id%type,
                                   productID    product.product_id%type,
                                   sizeID       sizedefinition.sizedefinition_id%type,
                                   finMethID    finishingmethod.finishingmethod_id%type,
                                   qty          int,
                                   returnFromCustomerDate statusquoheader.statusquodate%type,
                                   tempDelStops int);

  procedure t_createOrStoreOnTrigger_UI(uniqueItemID           uniqueitem.uniqueitem_id%type,
                                        qty                    int,
                                        returnFromCustomerDate statusquoheader.statusquodate%type,
                                        productID              product.product_id%type,
                                        sizeID                 sizedefinition.sizedefinition_id%type,
                                        finishingMethodID      finishingmethod.finishingmethod_id%type,
                                        weareremploymentID     uniqueitemnonpool.weareremployment_id%type
                                        );

  procedure t_createOrStoreOnTrigger_RQA(plpdipID productlistperdistribpoint.productlistperdistribpoint_id%type,
                                         qty      int,
                                         returnFromCustomerDate statusquoheader.statusquodate%type
                                          );

end PACK_SQMaxItemInCirculation;
/
create or replace package body PACK_SQMaxItemInCirculation is

  procedure createSQMaxItemsInCirculation(sqHeaderID   out statusquoheader.statusquoheader_id%type,
                                          processBUID  businessunit.businessunit_id%type,
                                          invoiceBUID  businessunit.businessunit_id%type,
                                          sqDate       date,
                                          sqYear       int,
                                          sqWeek       int,
                                          systemUserID systemuser.systemuser_id%type,
                                          checkInvoiceBu int) is
    statusUIInCirculation status.status_id%type;
    sizeStarID            sizedefinition.sizedefinition_id%type;
  begin
    -- In Circulation
    select status_id
      into statusUIInCirculation
      from status
     where statustype = 'UI'
       and code = '20';
    -- size *
    select sizedefinition_id
      into sizeStarID
      from sizedefinition
     where code = '*';

    -- StatusQuoHeader
    insert into statusquoheader
      (statusquoheader_id,
       processbusinessunit_id,
       invoicebusinessunit_id,
       statusquodate,
       statusquotype,
       totalquantity,
       year,
       week,
       month,
       systemuser_id,
       timestamp)
    values
      (seq_statusquoheader.nextval,
       processBUID,
       invoiceBUID,
       sqDate,
       SQ_MAX_ITEMS_IN_CIRCULATION,
       0,
       sqYear,
       sqWeek,
       0,
       systemUserID,
       sysdate)
    returning statusquoheader_id into sqHeaderID;

    -- SQMaxItemInCirculation based on RentalQuantityAdjustment
    createSQItemOnRentalQtyAdj(sqHeaderID,
                               processBUID,
                               invoiceBUID,
                               sqDate,
                               sqYear,
                               sqWeek,
                               systemUserID,
                               checkInvoiceBu);

    -- SQMaxItemInCirculation based on UniqueItems
    createSQItemOnUniqueItem(sqHeaderID,
                             processBUID,
                             invoiceBUID,
                             sqDate,
                             sqYear,
                             sqWeek,
                             statusUIInCirculation,
                             sizeStarID,
                             systemUserID,
                             checkInvoiceBu);
    -- update StatusQuoHeader.totalquantity
    update statusquoheader
       set totalquantity = (select nvl(sum(qtyrentedperpiece), 0)
                              from sqmaxitemincirculation
                             where sqmaxitemincirculation.statusquoheader_id =
                                   statusquoheader.statusquoheader_id)
     where statusquoheader_id = sqHeaderID;
    commit;
  end;

  procedure createSQItemOnUniqueItem(sqHeaderID            statusquoheader.statusquoheader_id%type,
                                     processBUID           businessunit.businessunit_id%type,
                                     invoiceBUID           businessunit.businessunit_id%type,
                                     sqDate                date,
                                     sqYear                int,
                                     sqWeek                int,
                                     statusUIInCirculation status.status_id%type,
                                     sizeStarID            sizedefinition.sizedefinition_id%type,
                                     systemUserID          systemuser.systemuser_id%type,
                                     checkInvoiceBu        int) is

    cursor stmt is
WITH uiel AS
 (SELECT product_id,
         sizedefinition_id,
         finishingmethod_id,
         customer_id,
         costcenter_id,
         seasonWeek,
         uifiEndDateFullRent,
         COUNT(1) AS uiCount
    FROM (SELECT (CASE
                   WHEN ui.substituteforproduct_id IS NOT NULL AND ui.substituteforsizedefinition_id IS NOT NULL THEN ui.substituteforproduct_id
                   ELSE ui.product_id
                 END) product_id,
                 (CASE
                   WHEN ui.substituteforsizedefinition_id IS NOT NULL THEN ui.substituteforsizedefinition_id
                   ELSE ui.sizedefinition_id
                 END) sizedefinition_id,
                 ui.finishingmethod_id,
                 ui.uniqueitem_id,
                 dep.customer_id,
                 dip.costcenter_id,
                 (CASE
                   WHEN WI.SEASON_ID IS NULL THEN 0
                   WHEN (SELECT COUNT(1) FROM seasonweek sw WHERE sw.season_id = wi.season_id AND sw.weeknumber = sqWeek) = 0 then 1
                   ELSE 2
                 END) seasonWeek,
                 (CASE
                   WHEN sqDate <= UIFI.ENDDATEFULLRENT THEN
                    1
                   ELSE
                    0
                 END) uifiEndDateFullRent
            FROM uniqueitem          ui,
                 uniqueitemnonpool   uinp,
                 uniqueitemfixedinfo uifi,
                 weareremployment    we,
                 wearerinventory     wi,
                 distributionpoint   dip,
                 department          dep,
                 customeractivities  ca,
                 product             p,
                 productgroup        pg
           WHERE uinp.uniqueitem_id = ui.uniqueitem_id
             AND uifi.uniqueitem_id = ui.uniqueitem_id
             AND ui.status_id = statusUIInCirculation
             AND ui.businessunit_id = processBUID
             AND ui.customerowned = 'N'
             AND ui.leaseweeks IS NULL
             AND ui.substituteforproduct_id IS NULL
             AND ui.substituteforsizedefinition_id IS NULL
             AND uinp.weareremployment_id = we.weareremployment_id
             AND we.distributionpoint_id = dip.distributionpoint_id
             AND dip.department_id = dep.department_id
             AND ui.product_id = p.product_id
             AND p.productgroup_id = pg.productgroup_id
             AND pg.activity_id = ca.activity_id
             AND dep.customer_id = ca.customer_id
             AND ca.processbusinessunit_id = processBUID
             AND ((checkInvoiceBu != 1) OR (checkInvoiceBu = 1 AND ca.invoicebusinessunit_id = invoiceBUID))
             AND uinp.wearerinventory_id = wi.wearerinventory_id
             AND (uinp.freeextragarment = 'N' OR uinp.enddatefreeextra <= sqDate)
             AND ((sqDate < wi.temporaryrentstopstartdate OR sqDate > wi.temporaryrentstopenddate)
                 OR (wi.temporaryrentstopstartdate IS NULL AND wi.temporaryrentstopenddate IS NULL)))
   GROUP BY product_id,
            sizedefinition_id,
            finishingmethod_id,
            customer_id,
            costcenter_id,
            seasonWeek,
            uifiEndDateFullRent)

SELECT uiel.costcenter_id,
       uiel.product_id,
       uiel.sizedefinition_id,
       uiel.finishingmethod_id,
       SUM(uiel.uicount) qtyperpiece
  FROM productlistpercustomer plpc, uiel
 WHERE plpc.customer_id = uiel.customer_id
   AND plpc.product_id = uiel.product_id
   AND (plpc.sizedefinition_id = uiel.sizedefinition_id OR plpc.sizedefinition_id = sizeStarID)
   AND plpc.finishingmethod_id = uiel.finishingmethod_id
   AND sqDate BETWEEN plpc.dateactive AND plpc.dateinactive
   AND plpc.billingmethod = 3
   AND plpc.inventorybillingtype = 1
   AND NOT EXISTS (SELECT t.temporarygarmentrentstop_id
          FROM temporarygarmentrentstop t
         WHERE t.customer_id = uiel.customer_id
           AND f_isinyearweeklifespan(startyear,
                                      startweek,
                                      sqYear,
                                      sqWeek,
                                      endyear,
                                      endweek) = 1)
   AND (uiel.seasonweek = 0 OR uiel.seasonweek = 1 OR (plpc.seasonalrent = 2 AND uiel.seasonweek = 2))
   AND ((plpc.percentageafterdepreciation > 0) OR (plpc.percentageafterdepreciation = 0 AND uiel.uifienddatefullrent = 1))
 GROUP BY uiel.costcenter_id,
          uiel.product_id,
          uiel.sizedefinition_id,
          uiel.finishingmethod_id;


  begin
    for rs in stmt loop
      createOrStoreOnSQ(sqHeaderID,
                        rs.costcenter_id,
                        rs.product_id,
                        rs.sizedefinition_id,
                        rs.finishingmethod_id,
                        rs.qtyPerPiece,
                        0,
                        0,
                        0,
                        systemUserID);
    end loop;
  end;

  procedure createSQItemOnRentalQtyAdj(sqHeaderID   statusquoheader.statusquoheader_id%type,
                                       processBUID  businessunit.businessunit_id%type,
                                       invoiceBUID  businessunit.businessunit_id%type,
                                       sqDate       date,
                                       sqYear       int,
                                       sqWeek       int,
                                       systemUserID systemuser.systemuser_id%type,
                                       checkInvoiceBu int) is

    cursor stmt is
      select dip.costcenter_id,
             p.product_id,
             s.sizedefinition_id,
             f.finishingmethod_id,
             sum(rqa.quantity) qtyPerPiece,
             nvl((select sum(rqx.quantity)
                   from rentalqtyadjustment        rqx,
                        productlistperdistribpoint plpdipx,
                        distributionpoint          dipx,
                        standarddeliveryline stdlx
                  where rqx.productlistperdistribpoint_id =
                        plpdipx.productlistperdistribpoint_id
                    and stdlx.productlistperdistribpoint_id =
                        plpdipx.productlistperdistribpoint_id
                    and plpdipx.distributionpoint_id =
                        dipx.distributionpoint_id
                    and dipx.costcenter_id = dip.costcenter_id
                    and plpdipx.product_id = p.product_id
                    and plpdipx.sizedefinition_id = s.sizedefinition_id
                    and plpdipx.finishingmethod_id = f.finishingmethod_id
                    and stdlx.dateactive <= sqDate
                    and stdlx.dateinactive >= sqDate
                    and rqx.adjustmentdate > sqDate
                    and getyearofweek(rqx.adjustmentdate) = sqYear
                    and getisoweek(rqx.adjustmentdate) = sqWeek),
                 0) qtyPlusAdj,
                 (select count(*)
                  from temporarydeliverystop tds,
                       standarddeliveryline  stdlx,
                       productlistperdistribpoint plpdipx,
                       distributionpoint          dipx
                  where tds.standarddeliveryline_id = stdlx.standarddeliveryline_id
                    and stdlx.productlistperdistribpoint_id =
                        plpdipx.productlistperdistribpoint_id
                    and plpdipx.distributionpoint_id =
                        dipx.distributionpoint_id
                    and dipx.costcenter_id = dip.costcenter_id
                    and plpdipx.product_id = p.product_id
                    and plpdipx.sizedefinition_id = s.sizedefinition_id
                    and plpdipx.finishingmethod_id = f.finishingmethod_id
                    and stdlx.dateactive <= sqDate
                    and stdlx.dateinactive >= sqDate
                  and ((tds.tempstoprentforweek = 'Y' and tds.temporarystopstartweek <= sqWeek and sqWeek <= tds.temporarystopendweek) or
                       (tds.tempstoprentforyearweek = 'Y' and (
                               (tds.temporarystopstartyear < sqYear and sqYear < tds.temporarystopendyear) or
                               (tds.temporarystopstartyear = sqYear and sqYear < tds.temporarystopendyear and tds.tempstopstartweekforyear <= sqWeek) or
                               (tds.temporarystopstartyear < sqYear and sqYear = tds.temporarystopendyear and sqWeek <= tds.tempstopendweekforyear) or
                               (tds.temporarystopstartyear = sqYear and sqYear = tds.temporarystopendyear and tds.tempstopstartweekforyear <= sqWeek and sqWeek <= tds.tempstopendweekforyear)
                               )
                       ) or
                       (tds.tempstoprentfordate = 'Y' and tds.startdate <= sqDate and sqDate <= tds.enddate)
                   )
                  ) tempDelStops
        from rentalqtyadjustment        rqa,
             productlistperdistribpoint plpdip,
             distributionpoint          dip,
             department                 dep,
             customeractivities         ca,
             product                    p,
             productgroup               pg,
             sizedefinition             s,
             finishingmethod            f,
             standarddeliveryline       stdl
             --,productlistpercustomer     plpc
       where rqa.productlistperdistribpoint_id =
             plpdip.productlistperdistribpoint_id
         and plpdip.distributionpoint_id = dip.distributionpoint_id
         and stdl.productlistperdistribpoint_id = plpdip.productlistperdistribpoint_id
         and dip.department_id = dep.department_id
         and plpdip.product_id = p.product_id
         and plpdip.sizedefinition_id = s.sizedefinition_id
         and plpdip.finishingmethod_id = f.finishingmethod_id
         and p.productgroup_id = pg.productgroup_id
         and pg.activity_id = ca.activity_id
         and dep.customer_id = ca.customer_id
         and stdl.dateactive <= sqDate
         and stdl.dateinactive >= sqDate
         and rqa.adjustmentdate <= sqDate
         and ca.processbusinessunit_id = processBUID
         AND ((checkInvoiceBu != 1) OR (checkInvoiceBu = 1 AND ca.invoicebusinessunit_id = invoiceBUID))
         --and plpc.productlistpercustomer_id = stdl.productlistpercustomer_id
         --and plpc.dateactive <= sqDate
         --and plpc.dateinactive >= sqDate
       group by dip.costcenter_id,
                p.product_id,
                s.sizedefinition_id,
                f.finishingmethod_id;

  begin
    for rs in stmt loop
      if rs.tempDelStops > 0 then
        createOrStoreOnSQ(sqHeaderID,
                          rs.costcenter_id,
                          rs.product_id,
                          rs.sizedefinition_id,
                          rs.finishingmethod_id,
                          rs.qtyPerPiece,
                          rs.qtyPlusAdj,
                          rs.qtyPerPiece,
                          rs.qtyPlusAdj,
                          systemUserID);
      else
        createOrStoreOnSQ(sqHeaderID,
                          rs.costcenter_id,
                          rs.product_id,
                          rs.sizedefinition_id,
                          rs.finishingmethod_id,
                          rs.qtyPerPiece,
                          rs.qtyPlusAdj,
                          0,
                          0,
                          systemUserID);
      end if;
    end loop;
  end;

  procedure createOrStoreOnSQ(sqHeaderID   statusquoheader.statusquoheader_id%type,
                              costCenterID costcenter.costcenter_id%type,
                              productID    product.product_id%type,
                              sizeID       sizedefinition.sizedefinition_id%type,
                              finMethID    finishingmethod.finishingmethod_id%type,
                              qtyPerPiece  sqmaxitemincirculation.qtyrentedperpiece%type,
                              qtyPlusAdj   sqmaxitemincirculation.qtyplusadjust%type,
                              qtyRentStop  sqmaxitemincirculation.qtyrentstop%type,
                              qtyPlusAdjRentStop    sqmaxitemincirculation.qtyplusadjustrentstop%type,
                              systemUserID systemuser.systemuser_id%type) is
  begin
    begin
      insert into sqmaxitemincirculation
        (sqmaxitemincirculation_id,
         statusquoheader_id,
         costcenter_link_id,
         product_link_id,
         sizedefinition_link_id,
         finishingmethod_id,
         qtyrentedperpiece,
         qtyplusadjust,
         qtyrentstop,
         qtyplusadjustrentstop,
         systemuser_id,
         timestamp)
      values
        (seq_sqmaxitemincirculation.nextval,
         sqHeaderID,
         costCenterID,
         productID,
         sizeID,
         finMethID,
         qtyPerPiece,
         qtyPlusAdj,
         qtyRentStop,
         qtyPlusAdjRentStop,
         systemUserID,
         sysdate);
    exception
      when dup_val_on_index then
        update sqmaxitemincirculation
           set qtyrentedperpiece = qtyrentedperpiece + qtyPerPiece,
               qtyplusadjust     = qtyplusadjust + qtyPlusAdj,
               qtyrentstop       = qtyrentstop + qtyRentStop,
               qtyplusadjustrentstop = qtyplusadjustrentstop + qtyPlusAdjRentStop,
               systemuser_id     = systemUserID,
               timestamp         = sysdate
         where statusquoheader_id = sqHeaderID
           and costcenter_link_id = costCenterID
           and product_link_id = productID
           and sizedefinition_link_id = sizeID
           and finishingmethod_id = finMethID;
    end;
  end;

  procedure createOrStoreOnTrigger_UI(uniqueItemID uniqueitem.uniqueitem_id%type,
                                      qty          int,
                                      returnFromCustomerDate statusquoheader.statusquodate%type,
                                      checkInvoiceBu        int) is
    cursor stmt is
      select dip.costcenter_id,
             ui.product_id,
             ui.sizedefinition_id,
             ui.finishingmethod_id,
             ca.processbusinessunit_id,
             ca.invoicebusinessunit_id,
             (SELECT COUNT(t.temporarygarmentrentstop_id)
                   FROM temporarygarmentrentstop t
                  WHERE t.customer_id = dep.customer_id
                        AND f_isinyearweeklifespan(startyear,
                                                   startweek,
                                                   getyearofweek(sysdate),
                                                   getisoweek(sysdate),
                                                   endyear,
                                                   endweek) = 1) qtyCustRentStop,
             (SELECT COUNT(wi.wearerinventory_id)
                   FROM wearerinventory wi
                   WHERE wi.weareremployment_id = we.weareremployment_id
                         AND wi.product_id = ui.product_id
                         AND wi.sizedefinition_id = ui.sizedefinition_id
                         AND wi.finishingmethod_id = ui.finishingmethod_id
                         AND sysdate BETWEEN wi.temporaryrentstopstartdate AND
                         wi.temporaryrentstopenddate) qtyRentStop
        from uniqueitem         ui,
             uniqueitemnonpool  uinp,
             weareremployment   we,
             distributionpoint  dip,
             department         dep,
             product            p,
             productgroup       pg,
             customeractivities ca
       where ui.uniqueitem_id = uniqueItemID
         and ui.uniqueitem_id = uinp.uniqueitem_id
         and uinp.weareremployment_id = we.weareremployment_id
         and we.distributionpoint_id = dip.distributionpoint_id
         and ui.product_id = p.product_id
         and p.productgroup_id = pg.productgroup_id
         and pg.activity_id = ca.activity_id
         and dip.department_id = dep.department_id
         and dep.customer_id = ca.customer_id
         and (uinp.freeextragarment = 'N' or uinp.enddatefreeextra <= trunc(sysdate));
  begin
    for rs in stmt loop
      if (checkInvoiceBu = 1)then --checkInvoiceBu = true
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.invoicebusinessunit_id,
                                                         rs.costcenter_id,
                                                         rs.product_id,
                                                         rs.sizedefinition_id,
                                                         rs.finishingmethod_id,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.qtyCustRentStop + rs.qtyRentStop );
      else
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.processbusinessunit_id,
                                                         rs.costcenter_id,
                                                         rs.product_id,
                                                         rs.sizedefinition_id,
                                                         rs.finishingmethod_id,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.qtyCustRentStop + rs.qtyRentStop );
       end if;
    end loop;
  end;

  procedure createOrStoreOnTrigger_RQA(plpdipID productlistperdistribpoint.productlistperdistribpoint_id%type,
                                       qty      int,
                                       returnFromCustomerDate statusquoheader.statusquodate%type,
                                       checkInvoiceBu        int) is
    currentyearnumber integer;
    currentweeknumber integer;
    cursor stmt is
      select dip.costcenter_id,
             plpdip.product_id,
             plpdip.sizedefinition_id,
             plpdip.finishingmethod_id,
             ca.processbusinessunit_id,
             ca.invoicebusinessunit_id,
             (select count(*)
              from temporarydeliverystop tds,
                   standarddeliveryline  stdl
              where tds.standarddeliveryline_id = stdl.standarddeliveryline_id
                and stdl.productlistperdistribpoint_id = plpdip.productlistperdistribpoint_id
                and stdl.dateactive <= sysdate
                and stdl.dateinactive >= sysdate
                and ((tds.tempstoprentforweek = 'Y' and tds.temporarystopstartweek <= currentweeknumber and currentweeknumber <= tds.temporarystopendweek) or
                     (tds.tempstoprentforyearweek = 'Y' and (
                           (tds.temporarystopstartyear < currentyearnumber and currentyearnumber < tds.temporarystopendyear) or
                           (tds.temporarystopstartyear = currentyearnumber and currentyearnumber < tds.temporarystopendyear and tds.tempstopstartweekforyear <= currentweeknumber) or
                           (tds.temporarystopstartyear < currentyearnumber and currentyearnumber = tds.temporarystopendyear and currentweeknumber <= tds.tempstopendweekforyear) or
                           (tds.temporarystopstartyear = currentyearnumber and currentyearnumber = tds.temporarystopendyear and tds.tempstopstartweekforyear <= currentweeknumber and currentweeknumber <= tds.tempstopendweekforyear)
                           )
                     ) or
                     (tds.tempstoprentfordate = 'Y' and tds.startdate <= sysdate and sysdate <= tds.enddate)
                 )
              ) tempDelStops
        from productlistperdistribpoint plpdip,
             distributionpoint          dip,
             department                 dep,
             product                    p,
             productgroup               pg,
             customeractivities         ca
       where plpdip.productlistperdistribpoint_id = plpdipID
         and plpdip.distributionpoint_id = dip.distributionpoint_id
         and plpdip.product_id = p.product_id
         and p.productgroup_id = pg.productgroup_id
         and pg.activity_id = ca.activity_id
         and dip.department_id = dep.department_id
         and dep.customer_id = ca.customer_id;
  begin
    currentyearnumber:=cast(to_char(sysdate, 'IYYY') as numeric);
    currentweeknumber:=getisoweek(sysdate);
    for rs in stmt loop
      if (checkInvoiceBu = 1)then --checkInvoiceBu = true
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.invoicebusinessunit_id,
                                                         rs.costcenter_id,
                                                         rs.product_id,
                                                         rs.sizedefinition_id,
                                                         rs.finishingmethod_id,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.tempdelstops );
      else
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.processbusinessunit_id,
                                                         rs.costcenter_id,
                                                         rs.product_id,
                                                         rs.sizedefinition_id,
                                                         rs.finishingmethod_id,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.tempdelstops );
      end if;
    end loop;
  end;

  procedure createOrStoreOnTrigger(processBUID  businessunit.businessunit_id%type,
                                   invoiceBUID  businessunit.businessunit_id%type,
                                   costCenterID costcenter.costcenter_id%type,
                                   productID    product.product_id%type,
                                   sizeID       sizedefinition.sizedefinition_id%type,
                                   finMethID    finishingmethod.finishingmethod_id%type,
                                   qty          int,
                                   returnFromCustomerDate statusquoheader.statusquodate%type,
                                   tempDelStops int) is
    sqHeaderID statusquoheader.statusquoheader_id%type;
    sqID       sqmaxitemincirculation.sqmaxitemincirculation_id%type;
    newQty     int;
    statusDate statusquoheader.statusquodate%type;
  begin

    begin
      select sq.statusquoheader_id, sq.statusquodate
        into sqHeaderID , statusDate
        from statusquoheader sq
       where sq.statusquotype = SQ_MAX_ITEMS_IN_CIRCULATION
         and getisoweek(sq.statusquodate) = getisoweek(sysdate)
         and getyearofweek(sq.statusquodate) = getyearofweek(sysdate)
         and sq.processbusinessunit_id = processBUID
         and sq.invoicebusinessunit_id = invoiceBUID;

      if (trunc(returnFromCustomerDate)=trunc(to_date('1900-01-01','yyyy-mm-dd'))) then
        update sqmaxitemincirculation
           set qtyplusadjust = qtyplusadjust + qty,
               qtyplusadjustrentstop  = qtyplusadjustrentstop +
                                      (case when tempDelStops > 0 then qty else 0 end),
               systemuser_id = 1,
               timestamp     = sysdate
         where statusquoheader_id = sqHeaderID
           and costcenter_link_id = costCenterID
           and product_link_id = productID
           and sizedefinition_link_id = sizeID
           and finishingmethod_id = finMethID returning
         sqmaxitemincirculation_id, qtyplusadjust into sqID, newQty;
        if (newQty < 0) then
          update sqmaxitemincirculation
             set qtyplusadjust = 0,
             qtyplusadjustrentstop  = (case when tempDelStops > 0 then 0 else qtyplusadjustrentstop end)
           where sqmaxitemincirculation_id = sqID;
         end if;
      else
        if (qty < 0) then
             update sqmaxitemincirculation
             set qtyminadjust = qtyminadjust + 1,
                 qtyplusadjustrentstop  = qtyplusadjustrentstop + (case when tempDelStops > 0 then 1 else 0 end),
                 systemuser_id = 1,
                 timestamp     = sysdate
           where statusquoheader_id = sqHeaderID
             and costcenter_link_id = costCenterID
             and product_link_id = productID
             and sizedefinition_link_id = sizeID
             and finishingmethod_id = finMethID;
         end if;
       end if;

      if (qty > 0 and sql%rowcount = 0) then
        insert into sqmaxitemincirculation
          (sqmaxitemincirculation_id,
           statusquoheader_id,
           costcenter_link_id,
           product_link_id,
           sizedefinition_link_id,
           finishingmethod_id,
           qtyrentedperpiece,
           qtyplusadjust,
           qtyplusadjustrentstop,
           systemuser_id,
           timestamp)
        values
          (seq_sqmaxitemincirculation.nextval,
           sqHeaderID,
           costCenterID,
           productID,
           sizeID,
           finMethID,
           0,
           qty,
           (case when tempDelStops > 0 then qty else 0 end),
           1,
           sysdate);
      end if;

    exception
      when no_data_found then
        null;
    end;
  end;

 procedure t_createOrStoreOnTrigger_UI(uniqueItemID           uniqueitem.uniqueitem_id%type,
                                        qty                    int,
                                        returnFromCustomerDate statusquoheader.statusquodate%type,
                                        productID              product.product_id%type,
                                        sizeID                 sizedefinition.sizedefinition_id%type,
                                        finishingMethodID      finishingmethod.finishingmethod_id%type,
                                        weareremploymentID     uniqueitemnonpool.weareremployment_id%type
                                        ) is
    cursor stmt is
      select dip.costcenter_id,
             ca.processbusinessunit_id,
             ca.invoicebusinessunit_id,
             (SELECT COUNT(t.temporarygarmentrentstop_id)
                   FROM temporarygarmentrentstop t
                  WHERE t.customer_id = dep.customer_id
                        AND f_isinyearweeklifespan(startyear,
                                                   startweek,
                                                   getyearofweek(sysdate),
                                                   getisoweek(sysdate),
                                                   endyear,
                                                   endweek) = 1) qtyCustRentStop,
             (SELECT COUNT(wi.wearerinventory_id)
                   FROM wearerinventory wi
                   WHERE wi.weareremployment_id = weareremploymentID
                         AND wi.product_id = productID
                         AND wi.sizedefinition_id = sizeID
                         AND wi.finishingmethod_id = finishingMethodID
                         AND sysdate BETWEEN wi.temporaryrentstopstartdate AND
                         wi.temporaryrentstopenddate) qtyRentStop
        from weareremployment   we,
             distributionpoint  dip,
             department         dep,
             product            p,
             productgroup       pg,
             customeractivities ca
       where weareremploymentID = we.weareremployment_id
         and we.distributionpoint_id = dip.distributionpoint_id
         and productID = p.product_id
         and p.productgroup_id = pg.productgroup_id
         and pg.activity_id = ca.activity_id
         and dip.department_id = dep.department_id
         and dep.customer_id = ca.customer_id;
     checkInvoiceBu int :=1;
  begin
    for rs in stmt loop
      BEGIN
     select case ss.value when 'Y' then 1
                                   else -1
            end
      into   checkInvoiceBu
      from   businessunit bu
             join systemsetting ss
                  on bu.plant_id = ss.plant_id
      where  bu.businessunit_id = rs.processbusinessunit_id
             and upper(ss.name) = 'CHECKINVOICEBUSINESSUNIT'
             and ss.groupname = 'Billing';
      EXCEPTION
        WHEN no_data_found THEN
          checkInvoiceBu := -1;
      END;

      if (checkInvoiceBu = 1)then --checkInvoiceBu = true
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.invoicebusinessunit_id,
                                                         rs.costcenter_id,
                                                         productID  ,
                                                         sizeID,
                                                         finishingMethodID,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.qtyCustRentStop + rs.qtyRentStop );
      else
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.processbusinessunit_id,
                                                         rs.costcenter_id,
                                                         productID  ,
                                                         sizeID,
                                                         finishingMethodID,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.qtyCustRentStop + rs.qtyRentStop );
       end if;
    end loop;
  end;

  procedure t_createOrStoreOnTrigger_RQA(plpdipID productlistperdistribpoint.productlistperdistribpoint_id%type,
                                       qty      int,
                                       returnFromCustomerDate statusquoheader.statusquodate%type
                                        ) is
    currentyearnumber integer;
    currentweeknumber integer;
    cursor stmt is
      select dip.costcenter_id,
             plpdip.product_id,
             plpdip.sizedefinition_id,
             plpdip.finishingmethod_id,
             ca.processbusinessunit_id,
             ca.invoicebusinessunit_id,
             (select count(*)
              from temporarydeliverystop tds,
                   standarddeliveryline  stdl
              where tds.standarddeliveryline_id = stdl.standarddeliveryline_id
                and stdl.productlistperdistribpoint_id = plpdip.productlistperdistribpoint_id
                and stdl.dateactive <= sysdate
                and stdl.dateinactive >= sysdate
                and ((tds.tempstoprentforweek = 'Y' and tds.temporarystopstartweek <= currentweeknumber and currentweeknumber <= tds.temporarystopendweek) or
                     (tds.tempstoprentforyearweek = 'Y' and (
                           (tds.temporarystopstartyear < currentyearnumber and currentyearnumber < tds.temporarystopendyear) or
                           (tds.temporarystopstartyear = currentyearnumber and currentyearnumber < tds.temporarystopendyear and tds.tempstopstartweekforyear <= currentweeknumber) or
                           (tds.temporarystopstartyear < currentyearnumber and currentyearnumber = tds.temporarystopendyear and currentweeknumber <= tds.tempstopendweekforyear) or
                           (tds.temporarystopstartyear = currentyearnumber and currentyearnumber = tds.temporarystopendyear and tds.tempstopstartweekforyear <= currentweeknumber and currentweeknumber <= tds.tempstopendweekforyear)
                           )
                     ) or
                     (tds.tempstoprentfordate = 'Y' and tds.startdate <= sysdate and sysdate <= tds.enddate)
                 )
              ) tempDelStops
        from productlistperdistribpoint plpdip,
             distributionpoint          dip,
             department                 dep,
             product                    p,
             productgroup               pg,
             customeractivities         ca
       where plpdip.productlistperdistribpoint_id = plpdipID
         and plpdip.distributionpoint_id = dip.distributionpoint_id
         and plpdip.product_id = p.product_id
         and p.productgroup_id = pg.productgroup_id
         and pg.activity_id = ca.activity_id
         and dip.department_id = dep.department_id
         and dep.customer_id = ca.customer_id;
    checkInvoiceBu int;
  begin
    currentyearnumber:=cast(to_char(sysdate, 'IYYY') as numeric);
    currentweeknumber:=getisoweek(sysdate);

    for rs in stmt loop
     BEGIN
     select case ss.value when 'Y' then 1
                                   else -1
            end
      into   checkInvoiceBu
      from   businessunit bu
             join systemsetting ss
                  on bu.plant_id = ss.plant_id
      where  bu.businessunit_id = rs.processbusinessunit_id
             and upper(ss.name) = 'CHECKINVOICEBUSINESSUNIT'
             and ss.groupname = 'Billing';
      EXCEPTION
        WHEN no_data_found THEN
          checkInvoiceBu := -1;
      END;
      if (checkInvoiceBu = 1)then --checkInvoiceBu = true
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.invoicebusinessunit_id,
                                                         rs.costcenter_id,
                                                         rs.product_id,
                                                         rs.sizedefinition_id,
                                                         rs.finishingmethod_id,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.tempdelstops );
      else
         pack_sqmaxitemincirculation.createOrStoreOnTrigger(rs.processbusinessunit_id,
                                                         rs.processbusinessunit_id,
                                                         rs.costcenter_id,
                                                         rs.product_id,
                                                         rs.sizedefinition_id,
                                                         rs.finishingmethod_id,
                                                         qty,
                                                         returnFromCustomerDate,
                                                         rs.tempdelstops );
      end if;
    end loop;
  end;

end PACK_SQMaxItemInCirculation;
/
create or replace PACKAGE PACK_STANDARDDELIVERY is

procedure CFbStoreOrCreate (
        FPnSTANDARDDELIVERY_ID                    in out STANDARDDELIVERY.STANDARDDELIVERY_ID%type,
        FPnSEQUENCENUMBER                         in out STANDARDDELIVERY.SEQUENCENUMBER%type,
        FPsDELIVERSTERILE                         in out STANDARDDELIVERY.DELIVERSTERILE%type,
        FPnPLANTDEPARTMENT_ID                     in out STANDARDDELIVERY.PLANTDEPARTMENT_ID%type,
        FPsCLEANRETURN                            in out STANDARDDELIVERY.CLEANRETURN%type,
        FPnTRANSPORTARTICLE_ID                    in out STANDARDDELIVERY.TRANSPORTARTICLE_ID%type,
        FPsGENERATEZEROLINES                      in out STANDARDDELIVERY.GENERATEZEROLINES%type,
        FPnNUMBEROFTRANSPORTARTICLES              in out STANDARDDELIVERY.NUMBEROFTRANSPORTARTICLES%type,
        FPnDISTRIBUTIONPOINT_ID                   in out STANDARDDELIVERY.DISTRIBUTIONPOINT_ID%type,
		    FPdtLASTPACKINGDATE                       in out STANDARDDELIVERY.LASTPACKINGDATE%type,
		    FPsCORRECTSHORTAGES                       in out STANDARDDELIVERY.CORRECTSHORTAGES%type,
		    FPsCORRECTOVERDELIVERIES                  in out STANDARDDELIVERY.CORRECTOVERDELIVERIES%type,
		    FPsTRUCKLOADPOSITION                      in out STANDARDDELIVERY.TRUCKLOADPOSITION%type,
        FPnSYSTEMUSER_ID                          in out STANDARDDELIVERY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out STANDARDDELIVERY.TIMESTAMP%type);

end PACK_STANDARDDELIVERY;








/
create or replace PACKAGE BODY PACK_STANDARDDELIVERY is

procedure CFbStoreOrCreate (
        FPnSTANDARDDELIVERY_ID                    in out STANDARDDELIVERY.STANDARDDELIVERY_ID%type,
        FPnSEQUENCENUMBER                         in out STANDARDDELIVERY.SEQUENCENUMBER%type,
        FPsDELIVERSTERILE                         in out STANDARDDELIVERY.DELIVERSTERILE%type,
        FPnPLANTDEPARTMENT_ID                     in out STANDARDDELIVERY.PLANTDEPARTMENT_ID%type,
        FPsCLEANRETURN                            in out STANDARDDELIVERY.CLEANRETURN%type,
        FPnTRANSPORTARTICLE_ID                    in out STANDARDDELIVERY.TRANSPORTARTICLE_ID%type,
        FPsGENERATEZEROLINES                      in out STANDARDDELIVERY.GENERATEZEROLINES%type,
        FPnNUMBEROFTRANSPORTARTICLES              in out STANDARDDELIVERY.NUMBEROFTRANSPORTARTICLES%type,
        FPnDISTRIBUTIONPOINT_ID                   in out STANDARDDELIVERY.DISTRIBUTIONPOINT_ID%type,
		    FPdtLASTPACKINGDATE                       in out STANDARDDELIVERY.LASTPACKINGDATE%type,
		    FPsCORRECTSHORTAGES                       in out STANDARDDELIVERY.CORRECTSHORTAGES%type,
		    FPsCORRECTOVERDELIVERIES                  in out STANDARDDELIVERY.CORRECTOVERDELIVERIES%type,
		    FPsTRUCKLOADPOSITION                      in out STANDARDDELIVERY.TRUCKLOADPOSITION%type,
        FPnSYSTEMUSER_ID                          in out STANDARDDELIVERY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out STANDARDDELIVERY.TIMESTAMP%type
) is
begin
    insert into STANDARDDELIVERY(
        STANDARDDELIVERY_ID,
        SEQUENCENUMBER,
        DELIVERSTERILE,
        PLANTDEPARTMENT_ID,
        CLEANRETURN,
        TRANSPORTARTICLE_ID,
        GENERATEZEROLINES,
        NUMBEROFTRANSPORTARTICLES,
        DISTRIBUTIONPOINT_ID,
		    LASTPACKINGDATE,
		    CORRECTSHORTAGES,
		    CORRECTOVERDELIVERIES,
		    TRUCKLOADPOSITION,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        SEQ_STANDARDDELIVERY.nextval,
        FPnSEQUENCENUMBER,
        FPsDELIVERSTERILE,
        FPnPLANTDEPARTMENT_ID,
        FPsCLEANRETURN,
        FPnTRANSPORTARTICLE_ID,
        FPsGENERATEZEROLINES,
        FPnNUMBEROFTRANSPORTARTICLES,
        FPnDISTRIBUTIONPOINT_ID,
		    FPdtLASTPACKINGDATE,
		    FPsCORRECTSHORTAGES,
		    FPsCORRECTOVERDELIVERIES,
		    FPsTRUCKLOADPOSITION,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
    select SEQ_STANDARDDELIVERY.currval into FPnSTANDARDDELIVERY_ID from dual;
  exception
  	when dup_val_on_index then

    update STANDARDDELIVERY
    set
        SEQUENCENUMBER = FPnSEQUENCENUMBER,
        DELIVERSTERILE = FPsDELIVERSTERILE,
        PLANTDEPARTMENT_ID = FPnPLANTDEPARTMENT_ID,
        CLEANRETURN = FPsCLEANRETURN,
        TRANSPORTARTICLE_ID = FPnTRANSPORTARTICLE_ID,
        GENERATEZEROLINES = FPsGENERATEZEROLINES,
        NUMBEROFTRANSPORTARTICLES = FPnNUMBEROFTRANSPORTARTICLES,
        DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID,
		    LASTPACKINGDATE = FPdtLASTPACKINGDATE,
		    CORRECTSHORTAGES = FPsCORRECTSHORTAGES,
		    CORRECTOVERDELIVERIES = FPsCORRECTOVERDELIVERIES,
		    TRUCKLOADPOSITION = FPsTRUCKLOADPOSITION,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID and
          SEQUENCENUMBER = FPnSEQUENCENUMBER
		returning STANDARDDELIVERY_ID into FPnSTANDARDDELIVERY_ID;

end;

end PACK_STANDARDDELIVERY;









/
create or replace PACKAGE PACK_STANDARDDELIVERYAMOUNT is

procedure CFbLoad (
        FPnSTDDELIVERYHISTORY_ID  in STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
        FPcursor								  out	 pack_utilities.refcursor);

procedure CFbCreate (
        FPnSTDDELIVERYHISTORY_ID  in STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
        FPnDAY_ID                                 in     STANDARDDELIVERYAMOUNT.DAY_ID%type,
        FPnAMOUNT                                 in     STANDARDDELIVERYAMOUNT.AMOUNT%type,
        FPnSYSTEMUSER_ID                          in     STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in     STANDARDDELIVERYAMOUNT.TIMESTAMP%type);

procedure CFbRemove (
        FPnSTDDELIVERYHISTORY_ID  in STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type);

procedure CFbStoreOrCreate (
        FPnSTDDELIVERYHISTORY_ID  in out STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
        FPnDAY_ID                                 in out STANDARDDELIVERYAMOUNT.DAY_ID%type,
        FPnAMOUNT                                 in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
        FPnSYSTEMUSER_ID                          in out STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out STANDARDDELIVERYAMOUNT.TIMESTAMP%type);

end PACK_STANDARDDELIVERYAMOUNT;










/
create or replace PACKAGE BODY PACK_STANDARDDELIVERYAMOUNT is

procedure CFbLoad (
        FPnSTDDELIVERYHISTORY_ID  in STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
        FPcursor								  out	 pack_utilities.refcursor
) is
begin
    open FPcursor for
	select
        STANDARDDELIVERYAMOUNT.DAY_ID,
        DAY.DAYNUMBER,
        STANDARDDELIVERYAMOUNT.AMOUNT,
        STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID,
        STANDARDDELIVERYAMOUNT.TIMESTAMP
    from STANDARDDELIVERYAMOUNT, DAY
    where STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID = FPnSTDDELIVERYHISTORY_ID and
          STANDARDDELIVERYAMOUNT.DAY_ID = DAY.DAY_ID
    order by DAY.DAYNUMBER;
end;

procedure CFbCreate (
        FPnSTDDELIVERYHISTORY_ID  in STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
        FPnDAY_ID                 in     STANDARDDELIVERYAMOUNT.DAY_ID%type,
        FPnAMOUNT                 in     STANDARDDELIVERYAMOUNT.AMOUNT%type,
        FPnSYSTEMUSER_ID          in     STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP             in     STANDARDDELIVERYAMOUNT.TIMESTAMP%type
) is
begin
    insert into STANDARDDELIVERYAMOUNT(
        STANDARDDELIVERYLINE_ID,
        DAY_ID,
        AMOUNT,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        FPnSTDDELIVERYHISTORY_ID,
        FPnDAY_ID,
        FPnAMOUNT,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
end;

procedure CFbRemove (
        FPnSTDDELIVERYHISTORY_ID  in STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type) is
begin
    delete from STANDARDDELIVERYAMOUNT
    where STANDARDDELIVERYLINE_ID = FPnSTDDELIVERYHISTORY_ID;
end;

procedure CFbStoreOrCreate (
        FPnSTDDELIVERYHISTORY_ID  in out STANDARDDELIVERYAMOUNT.STANDARDDELIVERYLINE_ID%type,
        FPnDAY_ID                                 in out STANDARDDELIVERYAMOUNT.DAY_ID%type,
        FPnAMOUNT                                 in out STANDARDDELIVERYAMOUNT.AMOUNT%type,
        FPnSYSTEMUSER_ID                          in out STANDARDDELIVERYAMOUNT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out STANDARDDELIVERYAMOUNT.TIMESTAMP%type
) is
begin
    insert into STANDARDDELIVERYAMOUNT(
        STANDARDDELIVERYLINE_ID,
        DAY_ID,
        AMOUNT,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        FPnSTDDELIVERYHISTORY_ID,
        FPnDAY_ID,
        FPnAMOUNT,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );

  exception
  	when dup_val_on_index then
      update STANDARDDELIVERYAMOUNT
        set
          STANDARDDELIVERYLINE_ID = FPnSTDDELIVERYHISTORY_ID,
          DAY_ID = FPnDAY_ID,
          AMOUNT = FPnAMOUNT,
          SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
          TIMESTAMP = FPdtTIMESTAMP
        where STANDARDDELIVERYLINE_ID = FPnSTDDELIVERYHISTORY_ID and DAY_ID = FPnDAY_ID;
end;

end PACK_STANDARDDELIVERYAMOUNT;










/
create or replace package pack_stockroom is

  -- Author  : MONICA.B
  -- Created : 11/26/2013 2:12:59 PM
  -- Purpose : Determine Slow/Fast Movers Per Stockroom

  -- Public type declarations

  -- Public constant declarations

  -- Public variable declarations

  -- Public function and procedure declarations
  procedure determineSlowFastMovers(fp_plantprocessId     plantprocess.plantprocess_id%type,
                                    fp_systemuserId       systemuser.systemuser_id%type,
                                    fp_abslogprocessjobId in out abslogprocessjob.abslogprocessjob_id%type);

end pack_stockroom;
/
create or replace package body pack_stockroom is

  -- Private type declarations
  gv_userexception           exception;

  -- Private constant declarations
  RETURN_OK CONSTANT INTEGER := 0;
  RETURN_FAILED_UNKNOWN CONSTANT INTEGER := -1;
  PRIORITY_MESSAGE CONSTANT abslogprocessjobline.priority%TYPE := 1;
  PRIORITY_ERROR CONSTANT abslogprocessjobline.priority%TYPE := 3;

  -- Private variable declarations
--  gv_processname              abslogprocessjobpart.processname%type;
  gv_systemuserId             systemuser.systemuser_id%type := 0;
  gv_abslogprocessjobId       abslogprocessjob.abslogprocessjob_id%type;
  gv_abslogprocessjobpartId   abslogprocessjobpart.abslogprocessjobpart_id%type;
  gv_message                  abslog.message%type;
  gv_processname              abslogprocessjobpart.processname%type;
  gv_returnValue              number := RETURN_OK;
  gv_plantId                  plant.plant_id%type;
  gv_languageId               languages.language_id%type;
  gv_stockMoverDays           number;
  gv_stockMoverPerc           number;

  -- Function and procedure implementations
  procedure write_log_line(fp_message        in abslogprocessjobline.message%type) is
--                            fp_routenumber    in route.routenumber%type default null,
--  lv_message varchar2(1000) := fp_message;
  begin
--    if (fp_routenumber is not null) then
--      lv_message := rpad(fp_routenumber, 10) || rpad(nvl(to_char(fp_drivingdate, 'dd-mm-yyyy'), ' '), 12)
--                    || rpad(nvl(to_char(fp_stopnumber), ' '), 12) || rpad(nvl(to_char(fp_customernumber), ' '), 15) || fp_message;
--    end if;

    IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
       abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_MESSAGE, fp_message, gv_systemuserid);
    END IF;
  exception
    when others then
      begin
        dbms_output.put_line(fp_message);
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := RETURN_FAILED_UNKNOWN;
        raise gv_userexception;
      end;
  end write_log_line;

  procedure get_abslogprocessjobid(fp_plantprocessid in plantprocess.plantprocess_id%type,
                                   fp_plantid IN plant.plant_id%TYPE) is
  begin
    --write_log
    gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(fp_plantid, sysdate, null, null,
                                                                fp_plantprocessid, gv_systemuserid);
  end get_abslogprocessjobid;

  function getSystemSetting(fp_systemSettingName systemsetting.name%type,
                             fp_plantId systemsetting.plant_id%TYPE) return NUMBER is
  lv_value NUMBER;
  begin
    --get_systemsetting
    gv_message := 'Error getting System Setting ' || fp_systemSettingName;
    select to_number( nvl(ss.value, ss.factorydefault) )
    into   lv_value
    from   systemsetting ss
    where  ss.plant_id = fp_plantId
    and    ss.name = fp_systemSettingName;
    return lv_value;
  exception
    when others then
       raise_application_error( -20001, gv_message);
  end getSystemSetting;

  function getEconomicStock(sdiId stockdefinitionperitem.stockdefinitionperitem_id%type) return number is
    lv_physical number;
    lv_reserved number;
    lv_ordered  number;
    lv_result   number;

  begin
    -- physical qty
    select nvl(sum(sq.qtyunique + sq.qtyuniquewithmodifications + sq.qtynonunique), 0) into lv_physical
      from stockreservationpergrade srg,
           stockquantity            sq,
           stockroomlocation        sl,
           locationtype             lt
     where srg.stockdefinitionperitem_id = sdiId
       and sq.stockreservationpergrade_id = srg.stockreservationpergrade_id
       and sl.stockroomlocation_id = sq.stockroomlocation_id
       and lt.locationtype_id = sl.locationtype_id
       and lt.useforpurchreqcalculation = 1;

    -- reserved qty
    select nvl(sum(srg.qtyuniquereserved + srg.qtynonuniquereserved + srg.qtynonuniquereserved), 0) into lv_reserved
      from stockreservationpergrade srg
     where srg.stockdefinitionperitem_id = sdiId;

    -- ordered qty
    select nvl(sum(srg.qtyuniqueordered + srg.qtynonuniqueordered - srg.qtynonuniqueordereddirectissue - srg.qtyuniqueordereddirectissue), 0) into lv_ordered
      from stockreservationpergrade srg
     where srg.stockdefinitionperitem_id = sdiId;

    lv_result := lv_physical - lv_reserved + lv_ordered;

    return lv_result;
  exception
    when others then
      gv_message := Sqlerrm;
  end getEconomicStock;

  function getStockMoverPercentage(sdiId       stockdefinitionperitem.stockdefinitionperitem_id%type,
                                   totalEcQty  number,
                                   lastXDays   number) return number is
    lv_result           number;
    lv_issuedLastXDays number;
    lv_outstanding     number;
  begin
/*    select nvl(sum(wol.quantityordered), 0) into lv_orderedLastXDays
      from workorder wo, workorderline wol
     where wol.workorder_id = wo.workorder_id
       and wol.product_link_id = productId
       and wol.sizedefinition_link_id = sizeId
       and wo.requestdate >= trunc(sysdate) - lastXDays
       and wo.requestdate <= trunc(sysdate)
       and wo.processingstockroom_id = stockroomId;*/
    select abs(nvl(sum(wst.quantity), 0)) into lv_issuedLastXDays
      from stocktransaction          st,
           workorderstocktransaction wst,
           stockreservationpergrade  srg
     where wst.stocktransaction_id = st.stocktransaction_id
       and srg.stockreservationpergrade_id = st.stockreservationpergrade_id
       and srg.stockdefinitionperitem_id = sdiId
       and st.transactiondate >= (sysdate - lastXDays)
       and st.transactiondate <= sysdate
       and st.transactiontype_id in (22, 32, 422, 50, 450, 453, 454);

    select nvl(sum(wol.quantityordered - wol.quantityfilled - wol.quantitycancelled), 0) into lv_outstanding
      from workorder wo,
           workorderline wol,
           status s,
           stockdefinitionperitem sdi
     where wol.workorder_id = wo.workorder_id
       and wol.product_link_id = sdi.product_id
       and wol.sizedefinition_link_id = sdi.sizedefinition_id
       and wo.requestdate >= trunc(sysdate - lastXDays)
       and wo.requestdate <= trunc(sysdate)
       and wo.processingstockroom_id = sdi.stockroom_id
       and sdi.stockdefinitionperitem_id = sdiId
       and wo.deliverfrom = 2
       and s.status_id = wo.status_id
       and (((s.statustype = 'WO') and (s.code not in ('30', '40'))) or
           ((s.statustype = 'MO') and (s.code not in ('30', '40', '50'))));


    if (totalEcQty = 0) then
      if (lv_issuedLastXDays + lv_outstanding = 0) then
        lv_result := 0;
      else
        lv_result := 100;
      end if;
    else
       lv_result := lv_issuedLastXDays + (lv_outstanding/totalEcQty);
    end if;

    return lv_result;
  exception
    when others then
      gv_message := Sqlerrm;
  end getStockMoverPercentage;

  procedure determineSlowFastMovers(fp_plantprocessId     plantprocess.plantprocess_id%type,
                                    fp_systemuserId       systemuser.systemuser_id%type,
                                    fp_abslogprocessjobId in out abslogprocessjob.abslogprocessjob_id%type) is
    lv_economicQty       number;
    lv_stockMoverPerc    number;
    lv_prevBuId          number := 0;
    lv_prevStockroomId   number := 0;
    lv_prevSize          number := 0;
    lv_prevProd          number := 0;
    lv_prevRanking       number := 0;
    lv_actualRanking     number := 0;
  begin
    --START
    gv_abslogprocessjobid := fp_abslogprocessjobId;
    gv_processname := 'pack_stockroom.determineSlowFastMovers';
    gv_message := gv_processname;
    if (fp_systemuserId is not null) then
       gv_systemuserid := fp_systemuserId;
    end if;

    select p.plant_id, p.language_id into gv_plantid, gv_languageId
           from plant p,
                plantprocess pp
           where pp.plant_id = p.plant_id
                 and pp.plantprocess_id = fp_plantprocessId;

    --get abslog process job id
    if (gv_abslogprocessjobid is null) then
       gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(gv_plantid,
                                                                   sysdate,
                                                                   null,
                                                                   null,
                                                                   fp_plantprocessId,
                                                                   gv_systemuserid);
    end if;

    --write_log part
    if gv_abslogprocessjobid is not null then
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gv_abslogprocessjobid,
                                                                          gv_processname,
                                                                          gv_systemuserid);
    end if;

    fp_abslogprocessjobId := gv_abslogprocessjobid;

    select ('Process Determine Slow and Fast movers for plant ' || p.code || ' - ' || p.name) into gv_message from plant p where p.plant_id = gv_plantid;
    write_log_line(gv_message);

    -- determine system settings values
    gv_stockMoverDays := getSystemSetting('STOCKMOVERDAYS', gv_plantid);
    gv_stockMoverPerc := getSystemSetting('STOCKMOVERPERC', gv_plantid);

    for sdiRec in (select sdi.stockdefinitionperitem_id,
                     sdi.product_id,
                     sdi.sizedefinition_id,
                     sdi.stockroom_id,
                     bu.code bucode,
                     bu.description budesc,
                     sr.code scode,
                     sr.name srdesc,
                     p.code pcode,
                     (select pd.description from product_desc pd where pd.product_id = p.product_id and pd.language_id = gv_languageId) pdesc,
                     sd.code sdcode,
                     (select sdd.description from sizedefinition_desc sdd where sdd.sizedefinition_id = sd.sizedefinition_id and sdd.language_id = gv_languageId) sddesc,
                     bu.businessunit_id
                from plantprocess           pp,
                     businessunit           bu,
                     stockroom              sr,
                     stockdefinitionperitem sdi,
                     product                p,
                     sizedefinition         sd
               where pp.plant_id = bu.plant_id
                 and sr.managedbybu_id = bu.businessunit_id
                 and sdi.stockroom_id = sr.stockroom_id
                 and sdi.product_id = p.product_id
                 and sdi.sizedefinition_id = sd.sizedefinition_id
                 and pp.plantprocess_id = fp_plantprocessId
                 and sdi.productconsumptiontype = 3
               order by bu.code, sr.code, p.code, sd.code
              ) loop
      if (lv_prevBuId != sdiRec.Businessunit_Id) then
        gv_message := 'Processing Business Unit ' || sdiRec.Bucode || ' - ' || sdiRec.Budesc;
        write_log_line(gv_message);
        lv_prevBuId := sdiRec.Businessunit_Id;
      end if;
      if (lv_prevStockroomId != sdiRec.Stockroom_Id) then
        gv_message := '   Processing StockRoom ' || sdiRec.Scode || ' - ' || sdiRec.Scode;
        write_log_line(gv_message);
        lv_prevStockroomId := sdiRec.Stockroom_Id;
      end if;
      gv_message := '      Product: ' || sdiRec.Pcode || ', Size: ' || sdiRec.Sdcode || ', Consumption Ranking: ';

      lv_economicQty := getEconomicStock(sdiRec.stockdefinitionperitem_id);
      if (lv_economicQty < 0) then
        lv_actualRanking := 2;
      else
        lv_stockMoverPerc := getStockMoverPercentage(sdiRec.Stockdefinitionperitem_Id, lv_economicQty, gv_stockMoverDays);
        if (lv_stockMoverPerc < gv_stockMoverPerc) then
          lv_actualRanking := 1;
        else
          lv_actualRanking := 2;
        end if;
      end if;

      if (lv_actualRanking = 1) then
         update stockdefinitionperitem set productconsumptionranking = 1 where stockdefinitionperitem_id = sdiRec.Stockdefinitionperitem_Id;
         gv_message := gv_message || '1 - Slow Mover';
      else
         update stockdefinitionperitem set productconsumptionranking = 2 where stockdefinitionperitem_id = sdiRec.Stockdefinitionperitem_Id;
         gv_message := gv_message || '2 - Fast Mover';
      end if;

      if (sdiRec.Product_Id != lv_prevProd or sdiRec.Sizedefinition_Id != lv_prevSize or lv_actualRanking != lv_prevRanking) then
         write_log_line(gv_message);
         lv_prevProd := sdiRec.Product_Id;
         lv_prevSize := sdiRec.Sizedefinition_Id;
         lv_prevRanking := lv_actualRanking;
      end if;
    end loop;
    commit;
  exception
    when others then
      IF (gv_abslogprocessjobpartid IS NOT NULL) THEN
         abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, PRIORITY_ERROR, gv_message, gv_systemuserid);
      END IF;
      raise gv_userexception;
  end DetermineSlowFastMovers;

begin
  -- Initialization
  begin
    select sy.systemuser_id into gv_systemuserid from systemuser sy where sy.username = 'SYSADM';
  exception
    when no_data_found then
    begin
    select sy.systemuser_id into gv_systemuserid from systemuser sy where sy.username = 'ABSADM';
    exception
      when no_data_found then
        begin
          select min(sy.systemuser_id) into gv_systemuserid from systemuser sy;
        end;
    end;
  end;
end pack_stockroom;
/
create or replace PACKAGE PACK_TRADE is
  --Version 2.0 PACK_TRADE
  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderLinesTotalAmount
     Use this function to calculate accumulated value of all sales order lines, no discounts
  */
  function GetSalesOrderLinesTotalAmount(SalesNote_ID       workorder.workorder_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderLinesTotalNetAmount
     Use this function to calculate accumulated value of all sales order lines.
  */

  function GetSalesOrderLinesTotalNetAmt(SalesNote_ID       workorder.workorder_id%type)
  return number;


  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderLinesEmblemTotalAmount
     Use this function to calculate accumulated value of all emblem lines no discount.
  */

  function GetSalesOrderLinesEmblTotalAmt(SalesNote_ID       workorder.workorder_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderLinesEmblemTotalNetAmount
     Use this function to calculate accumulated value of all emblem lines. Take into account system setting EMBLEMONSALESNOTE
  */

  function GetSalesOrdLinesEmbTotNetAmt (SalesNote_ID       workorder.workorder_id%type,
                                         param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderLinesTotalDiscount
     Use this function to calculate accumulated discount value of all sales order lines
  */
  function GetSalesOrdLinesTotalDisc(SalesNote_ID       workorder.workorder_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderLinesEmblemTotalDiscount
     Use this function to calculate ccumulated discount value of all emblem lines. Take into account system setting EMBLEMONSALESNOTE
  */
  function GetSalesOrdLinesEmbTotDisc(SalesNote_ID       workorder.workorder_id%type,
                                      param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderTheoreticalWeight
     Use this function to calculate total theoretical weight
  */
  function GetSalesOrderTheoreticalWeight(SalesNote_ID    workorder.workorder_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetDeliveryTermUnitPrice
     Use this function to calculate the actual price that is active at ?price date? for the delivery term of the sales note (DeliveryTermPrice.UnitPrice)
  */
  function GetDeliveryTermUnitPrice(DeliveryTermID       deliveryterm.deliveryterm_id%type,
                                    Weight                number,
                                    PriceDate             date)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderTransportCosts
     Use this function to calculate Postage / Transport costs
  */
  function GetSalesOrderTransportCosts(SalesNote_ID       workorder.workorder_id%type,
                                       param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderTotalVAT
     Use this function to calculate the VAT
  */
  function GetSalesOrderTotalVAT(SalesNote_ID       workorder.workorder_id%type,
                                 param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderTotalNetAmount
     Use this function to calculate Subtotal 2
  */
  function GetSalesOrderTotalNetAmount(SalesNote_ID       workorder.workorder_id%type,
                                       param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderTotalGrossAmount
     Use this function to calculate Gross order amount
  */
  function GetSalesOrderTotalGrossAmount(SalesNote_ID       workorder.workorder_id%type,
                                         param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSubTotal1
     Use this function to calculate M_SubTotal1
  */
  function GetSubTotal1(SalesNote_ID       workorder.workorder_id%type,
                        param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSubTotal2
     Use this function to calculate M_SubTotal2
  */
  function GetSubTotal2(SalesNote_ID       workorder.workorder_id%type,
                        param_plant_ID     plant.plant_id%type)
  return number;

  /* ----------------------------------------------------------------------------------------------
     Function GetSalesOrderGODAmount
     Use this function to calculate Sales Order General Order Discount Amount
  */
  function GetSalesOrderGODAmount(SalesNote_ID       workorder.workorder_id%type,
                                  param_plant_ID     plant.plant_id%type)
  return number;
end PACK_TRADE;
/
create or replace PACKAGE BODY PACK_TRADE is

 ------------------------------------------------------------------------------------

  function GetSalesOrderLinesTotalAmount(SalesNote_ID         in workorder.workorder_id%type)
  return number is
     M_SalesOrderLineTotal      number;

  begin
     select case when wo.origin = 7
            then nvl(sum (wol.salesprice * wol.quantitytobecredited),0)
            else nvl(sum (wol.salesprice * (wol.quantityordered-wol.quantitycancelled)),0)
            end SalesOrderLineTotal
      into  M_SalesOrderLineTotal
      from workorderline wol, workorder wo
     where wol.workorder_id = wo.workorder_id and wo.workorder_id = SalesNote_ID
     group by wo.origin;

    return (M_SalesOrderLineTotal);
    end GetSalesOrderLinesTotalAmount;

 ---------------------------------------------------------------------------------------

  function GetSalesOrderLinesTotalNetAmt(SalesNote_ID         in workorder.workorder_id%type)
    return number is
     M_SalesOrderLineNetTotal      number;

  begin
     select case when wo.origin = 7
            then nvl(sum (wol.salesprice * wol.quantitytobecredited*(100 - wol.discountpercentage)/100),0)
            else nvl(sum (wol.salesprice * (wol.quantityordered-wol.quantitycancelled)*(100 - wol.discountpercentage)/100),0)
            end SalesOrderLineNetTotal
      into  M_SalesOrderLineNetTotal
      from workorderline wol, workorder wo
     where wol.workorder_id = wo.workorder_id and wo.workorder_id = SalesNote_ID
     group by wo.origin;

         return (M_SalesOrderLineNetTotal);
    end GetSalesOrderLinesTotalNetAmt;

 ----------------------------------------------------------------------------------------

  function GetSalesOrderLinesEmblTotalAmt(SalesNote_ID         in workorder.workorder_id%type)
    return number is
     M_SalesOrderEmblemLineTotal      number;

  begin

      select nvl(sum (wole.salesprice * wole.qtyrequested),0)
      into  M_SalesOrderEmblemLineTotal
      from workorderline wol, workorderlineemblem wole
      where wole.workorderline_id=wol.workorderline_id
      and wol.workorder_id = SalesNote_ID;

    return (M_SalesOrderEmblemLineTotal);
  end GetSalesOrderLinesEmblTotalAmt;

  ------------------------------------------------------------------------------------------

  function GetSalesOrdLinesEmbTotNetAmt(SalesNote_ID         in workorder.workorder_id%type,
                                        param_plant_ID       in plant.plant_id%type)
    return number is
     M_SalesOrderEmblemLineNetTotal      number;
     value_EMBLEMONSALESNOTE             number;
  begin

   select nvl(ss.value, ss.factorydefault)
      into value_EMBLEMONSALESNOTE
      from plant p, systemsetting ss
     where p.plant_id = param_plant_ID
       and p.plant_id = ss.plant_id
       and ss.name = 'EMBLEMSONSALESNOTE';

       if (value_EMBLEMONSALESNOTE = 0) then

            select nvl(sum (wole.salesprice * wole.qtyrequested),0)
            into  M_SalesOrderEmblemLineNetTotal
            from workorderline wol, workorderlineemblem wole
            where wole.workorderline_id=wol.workorderline_id
            and wole.product_id is not null
            and wole.sizedefinition_id is not null
            and wol.workorder_id = SalesNote_ID;

     else

          select nvl(sum (wole.salesprice * wole.qtyrequested * (100 - wol.discountpercentage)/100),0)
          into  M_SalesOrderEmblemLineNetTotal
          from workorderline wol, workorderlineemblem wole
          where wole.workorderline_id=wol.workorderline_id
          and wole.product_id is not null
          and wole.sizedefinition_id is not null
          and wol.workorder_id = SalesNote_ID;

      end if;

      return (M_SalesOrderEmblemLineNetTotal);
  end GetSalesOrdLinesEmbTotNetAmt;
 ---------------------------------------------------------------------------------------------

  function GetSalesOrdLinesTotalDisc(SalesNote_ID         in workorder.workorder_id%type)
    return number is
     M_SalesOrderLineDiscount      number;

  begin

     select case when wo.origin = 7
            then nvl(sum (wol.salesprice * wol.quantitytobecredited * (wol.discountpercentage)/100),0)
            else nvl(sum (wol.salesprice * (wol.quantityordered - wol.quantitycancelled) * (wol.discountpercentage)/100),0)
            end SalesOrderLineDiscount
     into M_SalesOrderLineDiscount
     from workorderline wol, workorder wo
     where wol.workorder_id = wo.workorder_id and wo.workorder_id = SalesNote_ID
     group by wo.origin;

       return (M_SalesOrderLineDiscount);
    end GetSalesOrdLinesTotalDisc;

   ---------------------------------------------------------------------------------------------

  function GetSalesOrdLinesEmbTotDisc(SalesNote_ID         in workorder.workorder_id%type,
                                      param_plant_ID       in plant.plant_id%type)
    return number is
     M_SalesOrderEmblemLineDiscount      number;
     value_EMBLEMONSALESNOTE             number;
  begin

       select nvl(ss.value, ss.factorydefault)
      into value_EMBLEMONSALESNOTE
      from plant p, systemsetting ss
     where p.plant_id = param_plant_ID
       and p.plant_id = ss.plant_id
       and ss.name = 'EMBLEMSONSALESNOTE';

       if (value_EMBLEMONSALESNOTE = 0) then
         M_SalesOrderEmblemLineDiscount := 0;

       else

        select nvl(sum (wole.salesprice * wole.qtyrequested * (wol.discountpercentage/100)),0)
        into M_SalesOrderEmblemLineDiscount
        from workorderline wol, workorderlineemblem wole
        where   wole.workorderline_id=wol.workorderline_id
        and wol.workorder_id=SalesNote_ID;

    end if;
       return (M_SalesOrderEmblemLineDiscount);
    end GetSalesOrdLinesEmbTotDisc;

   ---------------------------------------------------------------------------------------------
  function GetSalesOrderTheoreticalWeight(SalesNote_ID in workorder.workorder_id%type)
    return number is

     M_TheoreticalWeight                 number;
     calcweight                          number;
     calcemblemweight                    number;
     origin                    workorder.origin%type;
  begin

  select wo.origin into origin
    from workorder wo
   where wo.workorder_id = SalesNote_ID;

    select
      case when origin = 7  then
            nvl(sum (wol.quantitytobecredited * decode(ps.theoreticalweight, 0, p.theoreticalweight, ps.theoreticalweight)),0)
      else
            nvl(sum ((wol.quantityordered - wol.quantitycancelled) * decode(ps.theoreticalweight, 0, p.theoreticalweight, ps.theoreticalweight)),0)
     end  thweight
    into calcweight
    from workorderline wol, product p, productsize ps
    where p.product_id=wol.product_link_id
    and ps.product_id=wol.product_link_id
    and ps.sizedefinition_id=wol.sizedefinition_link_id
    and wol.workorder_id = SalesNote_ID;

    select nvl(sum (wole.qtyrequested * decode(ps.theoreticalweight, 0, p.theoreticalweight, ps.theoreticalweight)),0)
    into calcemblemweight
    from workorderline wol, workorderlineemblem wole, product p, productsize ps
    where wole.workorderline_id=wol.workorderline_id
    and p.product_id=wole.product_id
    and ps.product_id=wole.product_id
    and ps.sizedefinition_id=wole.sizedefinition_id
    and wol.workorder_id=SalesNote_ID;

    M_TheoreticalWeight := calcweight + calcemblemweight;
     return (M_TheoreticalWeight);
  end GetSalesOrderTheoreticalWeight;

  ---------------------------------------------------------------------------------------------
    function GetDeliveryTermUnitPrice(DeliveryTermID       deliveryterm.deliveryterm_id%type,
                                    Weight               number,
                                    PriceDate            date)
  return number is

  UnitPrice                     number;

  begin
    begin
      select *
      into UnitPrice from
      (select s1.unitprice
        from deliverytermprice s1
       where s1.deliveryterm_id = DeliveryTermID
         and s1.fromweight = (select max(s2.fromweight) from  deliverytermprice s2 where s2.startdate <= PriceDate and s2.fromweight <= Weight
                            and s2.deliveryterm_id=DeliveryTermID)
         and s1.startdate <= PriceDate
        order by s1.startdate desc
        )
        -- to make sure that only the most recent price is returned
        where
            rownum = 1;
      exception
           when no_data_found then
           UnitPrice := 0;
      end;
    return (UnitPrice);
  end GetDeliveryTermUnitPrice;

  ---------------------------------------------------------------------------------------------

  function GetSalesOrderTransportCosts(SalesNote_ID         in workorder.workorder_id%type,
                                        param_plant_ID       in plant.plant_id%type)
  return number is

     M_TransportCosts                    number;
     M_SubTotal2                         number;
     M_MaxNetOrderValue                  number;
     M_DeliveryTermUnitPrice             number;
     M_DeliveryTerm_ID                   number;
     M_TheoreticalWeight                 number;

  begin
    -- determine sales order amount minus sales order line discounts
    M_SubTotal2 := GetSubTotal2(SalesNote_ID, param_plant_ID);
    -- determine delivery term, registered weight, transport costs and max order value
    select wo.deliveryterm_id, wo.transportcosts, dt.maxnetordervalue
    into M_DeliveryTerm_ID, M_TransportCosts, M_MaxNetOrderValue
    from workorder wo, deliveryterm dt
    where wo.deliveryterm_id(+) = dt.deliveryterm_id
    and wo.workorder_id = SalesNote_ID;
    M_TheoreticalWeight := GetSalesOrderTheoreticalWeight(SalesNote_ID);
       -- calculate transport costs only when not stored yet for order
    if (M_SubTotal2 > M_MaxNetOrderValue) then
        M_TransportCosts := 0;
      else
        -- determine applicable unit price using dedicated method
        M_DeliveryTermUnitPrice :=  GetDeliveryTermUnitPrice(M_DeliveryTerm_ID, M_TheoreticalWeight, sysdate);
        M_TransportCosts := M_DeliveryTermUnitPrice * M_TheoreticalWeight;
      end if;
    return (M_TransportCosts);
  end GetSalesOrderTransportCosts;

  ---------------------------------------------------------------------------------------------

  function GetSalesOrderTotalVAT (SalesNote_ID         in workorder.workorder_id%type,
                                  param_plant_ID       in plant.plant_id%type)
    return number is
    -- declare cursor to calculate total VAT for sales order
    -- RVI 20171214 begin
    -- Use m_referencedate instead of SYSDATE to determine applicable VAT rate
    --
    --cursor taxcalc is
    cursor taxcalc(m_referencedate date) is
      select sum(v4.rate_vatamount) totalvatamount
        from (select v3.vatcode, v3.vatrate, sum(vatamount) rate_vatamount
                -- WorkOrderLines
                from (select 'WOL' linetype,
                             tg.code vatcode,
                             case
                               when (tg.startdatetaxrate <= trunc(m_referencedate)) then
                                ((tg.taxrate / 100) * v2.netamount)
                               else
                                ((tg.oldtaxrate / 100) * v2.netamount)
                             end vatamount,
                             case
                               when (tg.startdatetaxrate <= trunc(m_referencedate)) then
                                tg.taxrate
                               else
                                tg.oldtaxrate
                             end vatrate
                        from (select v1.taxgroup_id,
                                     sum((v1.wol_ordered * v1.salesprice *
                                         (100 - v1.wol_discount) / 100) *
                                         ((100 - v1.wo_discount) / 100)) netamount
                                from (select wol.product_link_id,
                                             wol.salesprice,
                                             wol.discountpercentage wol_discount,
                                             case
                                               when (wo.origin = 7) then
                                                wol.quantitytobecredited
                                               else
                                                (wol.quantityordered -
                                                wol.quantitycancelled)
                                             end wol_ordered,
                                             wo.discountpercentage wo_discount,
                                             coalesce(
                                                 -- specific customer / product tax group
                                                 (select cpd.taxgroup_id
                                                   from customerproducttaxdef cpd
                                                  where cpd.customer_id =
                                                        wo.customer_link_id
                                                    and cpd.product_id =
                                                        wol.product_link_id
                                                    and cpd.type = 4),
                                                 -- specific product tax group
                                                 (select pt.taxgroup_id
                                                    from producttax pt
                                                   where pt.country_id = c.country_id
                                                     and pt.product_id =
                                                         wol.product_link_id),
                                                 -- specific invoice line (sub) type tax group
                                                 (select nvl(ill.taxgroup_id, tg.taxgroup_id)
                                                         from invoicelinesubtype ilst
                                                              left outer join turnovergroup tg
                                                          on ilst.turnovergroup_id=tg.turnovergroup_id
                                                          , invoicelinesubtypetax ill
                                                        where ilst.invoicelinetype_id = 5
                                                        and ilst.invoicelinesubtype_id =
                                                              ill.invoicelinesubtype_id
                                                          and ill.country_id =  c.country_id
                                                          and ((ilst.subtype = 17 and
                                                              wo.origin = 6) or
                                                              (wo.origin = 7 and
                                                              ilst.subtype = 18))),
                                                      -- specific invoice line  type tax group
                                                      (select nvl(iltt.taxgroup_id,
                                                                  iltg.taxgroup_id)
                                                         from  invoicelinetypetax iltt, invoicelinetype    ilt left outer join
                                                              turnovergroup      iltg on ilt.turnovergroup_id =
                                                              iltg.turnovergroup_id
                                                        where ilt.invoicelinetype_id =
                                                              iltt.invoicelinetype_id
                                                               and iltt.invoicelinetype_id = 5
                                                          and iltt.country_id =
                                                              c.country_id)) taxgroup_id
                                        from workorder     wo,
                                             customer      c,
                                             workorderline wol
                                       where c.customer_id = wo.customer_link_id
                                         and wol.workorder_id = wo.workorder_id
                                         and wo.workorder_id = SalesNote_ID) v1
                               group by v1.taxgroup_id) v2,
                             taxgroup tg

                       where tg.taxgroup_id = v2.taxgroup_id
                      UNION
                -- WorkOrderLineEmblem lines
                      select 'WOLE' linetype,
                             tg.code vatcode,
                             case
                               when (tg.startdatetaxrate <= trunc(m_referencedate)) then
                                ((tg.taxrate / 100) * v2.netamount)
                               else
                                ((tg.oldtaxrate / 100) * v2.netamount)
                             end vatamount,
                             case
                               when (tg.startdatetaxrate <= trunc(m_referencedate)) then
                                tg.taxrate
                               else
                                tg.oldtaxrate
                             end vatrate
                        from (select v1.taxgroup_id,
                                     v1.emblemonsalesnote,
                                     case
                                       when v1.emblemonsalesnote = 1 then
                                        sum((v1.wole_ordered * v1.salesprice *
                                            (100 - v1.wol_discount) / 100) *
                                            ((100 - v1.wo_discount) / 100))
                                       else
                                        sum((v1.wole_ordered * v1.salesprice *
                                            (100 - v1.wo_discount) / 100))
                                     end netamount
                                from (select wole.product_id,
                                             wole.salesprice,
                                             wol.discountpercentage wol_discount,
                                             wole.qtyrequested wole_ordered,
                                             0 quantitytobecredited,
                                             wo.discountpercentage wo_discount,
                                             s.value emblemonsalesnote,
                                             coalesce(
                                                 -- specific customer / product tax group
                                                 (select cpd.taxgroup_id
                                                   from customerproducttaxdef cpd
                                                  where cpd.customer_id =
                                                        wo.customer_link_id
                                                    and cpd.product_id =
                                                        wole.product_id
                                                    and cpd.type = 4),
                                                 -- specific product tax group
                                                 (select pt.taxgroup_id
                                                    from producttax pt
                                                   where pt.country_id = c.country_id
                                                     and pt.product_id =
                                                         wole.product_id),

                                                 -- specific invoice line (sub) type tax group
                                                 (select nvl(ill.taxgroup_id, tg.taxgroup_id)
                                                         from invoicelinesubtype ilst
                                                              left outer join turnovergroup tg
                                                          on ilst.turnovergroup_id=tg.turnovergroup_id
                                                          , invoicelinesubtypetax ill
                                                        where ilst.invoicelinetype_id = 5
                                                        and ilst.invoicelinesubtype_id =
                                                              ill.invoicelinesubtype_id
                                                          and ill.country_id =  c.country_id
                                                          and ((ilst.subtype = 17 and
                                                              wo.origin = 6) or
                                                              (wo.origin = 7 and
                                                              ilst.subtype = 18))),
                                                      -- specific invoice line  type tax group
                                                      (select nvl(iltt.taxgroup_id,
                                                                  iltg.taxgroup_id)
                                                         from invoicelinetype    ilt,
                                                              invoicelinetypetax iltt,
                                                              turnovergroup      iltg
                                                        where ilt.invoicelinetype_id =
                                                              iltt.invoicelinetype_id
                                                          and iltg.turnovergroup_id =
                                                              ilt.turnovergroup_id
                                                          and iltt.invoicelinetype_id = 5
                                                          and iltt.country_id =
                                                              c.country_id)) taxgroup_id
                                        from workorder           wo,
                                             customer            c,
                                             workorderline       wol,
                                             workorderlineemblem wole,
                                             systemsetting       s
                                       where c.customer_id = wo.customer_link_id
                                         and wol.workorder_id = wo.workorder_id
                                         and wole.workorderline_id =
                                             wol.workorderline_id
                                         and wole.product_id is not null
                                         and wole.sizedefinition_id is not null
                                         and s.plant_id = param_plant_id
                                         and s.name = 'EMBLEMSONSALESNOTE'
                                         and wo.workorder_id = SalesNote_ID) v1
                               group by v1.taxgroup_id, v1.emblemonsalesnote) v2,
                             taxgroup tg

                       where tg.taxgroup_id = v2.taxgroup_id
                      UNION
                -- Transport Costs
                      select 'WOTPC' linetype,
                             tg.code vatcode,
                             case
                               when (tg.startdatetaxrate <= trunc(m_referencedate)) then
                                ((tg.taxrate / 100) * v1.transportcosts)
                               else
                                ((tg.oldtaxrate / 100) * v1.transportcosts)
                             end vatamount,
                             case
                               when (tg.startdatetaxrate <= trunc(m_referencedate)) then
                                tg.taxrate
                               else
                                tg.oldtaxrate
                             end vatrate
                        from (select wo.transportcosts,
                                     (select case
                                               when ilst.taxgroup_id is not null then
                                                ilst.taxgroup_id
                                               when ilsg.taxgroup_id is not null then
                                                ilsg.taxgroup_id
                                               when iltt.taxgroup_id is not null then
                                                iltt.taxgroup_id
                                               else
                                                iltg.taxgroup_id
                                             end taxgroup_id
                                        from invoicelinetype       ilt,
                                             invoicelinetypetax    iltt,
                                             invoicelinesubtype    ils,
                                             invoicelinesubtypetax ilst,
                                             turnovergroup         iltg,
                                             turnovergroup         ilsg
                                       where iltg.turnovergroup_id =
                                             ilt.turnovergroup_id
                                         and iltt.invoicelinetype_id(+) =
                                             ilt.invoicelinetype_id
                                         and iltt.country_id(+) = c.country_id
                                         and ils.invoicelinetype_id(+) =
                                             ilt.invoicelinetype_id
                                         and ilsg.turnovergroup_id =
                                             ils.turnovergroup_id
                                         and ilst.invoicelinesubtype_id(+) =
                                             ils.invoicelinesubtype_id
                                         and ilst.country_id(+) = c.country_id
                                         and ilt.invoicelinetype_id = 16
                                         and ils.subtype = 2) taxgroup_id

                                from workorder wo, customer c
                               where c.customer_id = wo.customer_link_id
                                 and wo.workorder_id = SalesNote_ID) v1,
                             taxgroup tg

                       where tg.taxgroup_id = v1.taxgroup_id) v3
               group by v3.vatcode, v3.vatrate) v4;

    -- declare variables
    m_vatamount      number;
    customertaxable  customer.taxable%type;
    m_referencedate  date;
  begin
    m_vatamount := 0;
    --determine if the customer is taxable or not.
    select cu.taxable,
      case when wo.completiondate >= to_date('31-12-2099','dd-mm-yyyy') then sysdate
        else wo.completiondate
       end
      into  customertaxable, m_referencedate
      from workorder wo, customer cu
     where wo.customer_link_id = cu.customer_id
       and wo.workorder_id = SalesNote_ID;

    if (customertaxable = 'Y') then
      begin
        for c_ in taxcalc(m_referencedate) loop
         m_vatamount := c_.totalvatamount;
        end loop;
      end;
    else
      m_vatamount := 0;
    end if;
    return(m_vatamount);
  end GetSalesOrderTotalVAT;

  ---------------------------------------------------------------------------------------------

  function GetSalesOrderTotalNetAmount(SalesNote_ID         in workorder.workorder_id%type,
                                       param_plant_ID       in plant.plant_id%type)
    return number is
     M_NetOrderAmount      number;
     transportcosts        number;
  begin
    --determine the transport cost from the database
   select wo.transportcosts
     into  transportcosts
     from workorder wo
    where wo.workorder_id = SalesNote_ID;

     M_NetOrderAmount := GetSubTotal2(SalesNote_ID, param_plant_ID) + transportcosts;
       return (M_NetOrderAmount);

  end GetSalesOrderTotalNetAmount;

  function GetSalesOrderTotalGrossAmount(SalesNote_ID         in workorder.workorder_id%type,
                                         param_plant_ID       in plant.plant_id%type)
    return number is
     M_GrossOrderAmount      number;

  begin

     M_GrossOrderAmount := GetSalesOrderTotalNetAmount(SalesNote_ID, param_plant_ID) + GetSalesOrderTotalVAT(SalesNote_ID,param_plant_ID);
       return (M_GrossOrderAmount);
    end GetSalesOrderTotalGrossAmount;

  function GetSubTotal1(SalesNote_ID         in workorder.workorder_id%type,
                        param_plant_ID       in plant.plant_id%type)
    return number is
       M_SubTotal1                    number;

  begin

    M_SubTotal1 := GetSalesOrderLinesTotalAmount(SalesNote_ID) -
                   GetSalesOrdLinesTotalDisc(SalesNote_ID) +
                   GetSalesOrderLinesEmblTotalAmt(SalesNote_ID) -
                   GetSalesOrdLinesEmbTotDisc(SalesNote_ID, param_plant_ID);
       return (M_SubTotal1);
    end GetSubTotal1;

  function GetSubTotal2(SalesNote_ID         in workorder.workorder_id%type,
                        param_plant_ID       in plant.plant_id%type)
    return number is
       M_SubTotal2                    number;

  begin

   M_SubTotal2 := GetSubTotal1(SalesNote_ID, param_plant_ID) - GetSalesOrderGODAmount(SalesNote_ID, param_plant_ID);
       return (M_SubTotal2);
    end GetSubTotal2;

  function GetSalesOrderGODAmount(SalesNote_ID         in workorder.workorder_id%type,
                                  param_plant_ID       in plant.plant_id%type)
    return number is
     M_GeneralOrderDiscount      number;
     M_DiscPercentage            number;

  begin

    select wo.discountpercentage
    into M_DiscPercentage
    from workorder wo
    where wo.workorder_id = SalesNote_ID;

    M_GeneralOrderDiscount := (GetSubTotal1(SalesNote_ID, param_plant_ID) * (M_DiscPercentage/100));
       return (M_GeneralOrderDiscount);
  end GetSalesOrderGODAmount;

  END PACK_TRADE;
/
create or replace PACKAGE PACK_UNIQUEITEM is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEM.UNIQUEITEM_ID%type,
        FPsPRIMARYID                              in out UNIQUEITEM.PRIMARYID%type,
        FPnIDCODESEQUENCENUMBER                   in out UNIQUEITEM.IDCODESEQUENCENUMBER%type,
        FPdtSTATUSCHANGEDATE                      in out UNIQUEITEM.STATUSCHANGEDATE%type,
        FPdtSTAYCHANGEDATE                        in out UNIQUEITEM.STAYCHANGEDATE%type,
        FPdtLASTINSCANDATE                        in out UNIQUEITEM.LASTINSCANDATE%type,
        FPdtLASTOUTSCANDATE                       in out UNIQUEITEM.LASTOUTSCANDATE%type,
        FPdtLASTSCANDATE                          in out UNIQUEITEM.LASTSCANDATE%type,
        FPdtITEMINFOUPDATEDATE                    in out UNIQUEITEM.ITEMINFOUPDATEDATE%type,
        FPsPOOL                                   in out UNIQUEITEM.POOLITEM%type,
        FPnWASHESTOTAL                            in out UNIQUEITEM.WASHESTOTAL%type,
        FPnREPAIRSTOTAL                           in out UNIQUEITEM.REPAIRSTOTAL%type,
        FPnREWASHTOTAL                            in out UNIQUEITEM.REWASHTOTAL%type,
        FPsCUSTOMEROWNED                          in out UNIQUEITEM.CUSTOMEROWNED%type,
        FPnBUSINESSUNIT_ID                        in out UNIQUEITEM.BUSINESSUNIT_ID%type,
        FPnSTATUS_ID                              in out UNIQUEITEM.STATUS_ID%type,
        FPnPREVSTATUS_ID                          in out UNIQUEITEM.PREVSTATUS_ID%type,
        FPnPREVSTAY_ID                            in out UNIQUEITEM.PREVSTAY_ID%type,
        FPnSTAY_ID                                in out UNIQUEITEM.STAY_ID%type,
        FPnPRODUCT_ID                             in out UNIQUEITEM.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out UNIQUEITEM.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out UNIQUEITEM.FINISHINGMETHOD_ID%type,
        FPnRELATEDCUSTOMER_ID                     in out UNIQUEITEM.RELATEDCUSTOMER_ID%type,
        FPnDISTRIBUTIONPOINT_ID                   in out UNIQUEITEM.DISTRIBUTIONPOINT_ID%type,
        FPnLASTDISTRIBPOINT_LINK_ID               in out UNIQUEITEM.LASTDISTRIBUTIONPOINT_LINK_ID%type,
        FPdtPLANNEDDELIVERYDATE                   in out UNIQUEITEM.PLANNEDDELIVERYDATE%type,
        FPsDELIVERYFROMSTOCK                      in out UNIQUEITEM.DELIVERYFROMSTOCK%type,
        FPnSTARTRENTFROM                          in out UNIQUEITEM.STARTRENTFROM%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEM.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEM.TIMESTAMP%type,
        FPnLASTWEAREREMPL_LINK_ID                 in out UNIQUEITEM.LASTWEAREREMPLOYMENT_LINK_ID%type);

procedure CFbRetrieveProductInformations(
          FPnCUSTOMER_ID                          in CUSTOMER.CUSTOMER_ID%type,
          FPsPRODUCTCODE                          in  PRODUCT.CODE%type,
          FPsSIZEDEFINITIONCODE                   in  SIZEDEFINITION.CODE%type,
          FPnSUPPLIERNUMBER                       in  SUPPLIER.SUPPLIERNUMBER%type,
          FPnPRODUCT_ID                           out PRODUCT.PRODUCT_ID%type,
          FPnSIZEDEFINITION_ID                    out SIZEDEFINITION.SIZEDEFINITION_ID%type,
          FPnFINISHINGMETHOD_ID                   out FINISHINGMETHOD.FINISHINGMETHOD_ID%type,
          FPnSUPPLIER_ID                          out SUPPLIER.SUPPLIER_ID%type,
          FPnCURRENCY_ID                          out SUPPLIER.CURRENCY_ID%type,
          FPnError                                in out int);

end PACK_UNIQUEITEM;

/
create or replace PACKAGE BODY PACK_UNIQUEITEM is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEM.UNIQUEITEM_ID%type,
        FPsPRIMARYID                              in out UNIQUEITEM.PRIMARYID%type,
        FPnIDCODESEQUENCENUMBER                   in out UNIQUEITEM.IDCODESEQUENCENUMBER%type,
        FPdtSTATUSCHANGEDATE                      in out UNIQUEITEM.STATUSCHANGEDATE%type,
        FPdtSTAYCHANGEDATE                        in out UNIQUEITEM.STAYCHANGEDATE%type,
        FPdtLASTINSCANDATE                        in out UNIQUEITEM.LASTINSCANDATE%type,
        FPdtLASTOUTSCANDATE                       in out UNIQUEITEM.LASTOUTSCANDATE%type,
        FPdtLASTSCANDATE                          in out UNIQUEITEM.LASTSCANDATE%type,
        FPdtITEMINFOUPDATEDATE                    in out UNIQUEITEM.ITEMINFOUPDATEDATE%type,
        FPsPOOL                                   in out UNIQUEITEM.POOLITEM%type,
        FPnWASHESTOTAL                            in out UNIQUEITEM.WASHESTOTAL%type,
        FPnREPAIRSTOTAL                           in out UNIQUEITEM.REPAIRSTOTAL%type,
        FPnREWASHTOTAL                            in out UNIQUEITEM.REWASHTOTAL%type,
        FPsCUSTOMEROWNED                          in out UNIQUEITEM.CUSTOMEROWNED%type,
        FPnBUSINESSUNIT_ID                        in out UNIQUEITEM.BUSINESSUNIT_ID%type,
        FPnSTATUS_ID                              in out UNIQUEITEM.STATUS_ID%type,
        FPnPREVSTATUS_ID                          in out UNIQUEITEM.PREVSTATUS_ID%type,
        FPnPREVSTAY_ID                            in out UNIQUEITEM.PREVSTAY_ID%type,
        FPnSTAY_ID                                in out UNIQUEITEM.STAY_ID%type,
        FPnPRODUCT_ID                             in out UNIQUEITEM.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out UNIQUEITEM.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out UNIQUEITEM.FINISHINGMETHOD_ID%type,
        FPnRELATEDCUSTOMER_ID                     in out UNIQUEITEM.RELATEDCUSTOMER_ID%type,
        FPnDISTRIBUTIONPOINT_ID                   in out UNIQUEITEM.DISTRIBUTIONPOINT_ID%type,
        FPnLASTDISTRIBPOINT_LINK_ID               in out UNIQUEITEM.LASTDISTRIBUTIONPOINT_LINK_ID%type,
        FPdtPLANNEDDELIVERYDATE                   in out UNIQUEITEM.PLANNEDDELIVERYDATE%type,
        FPsDELIVERYFROMSTOCK                      in out UNIQUEITEM.DELIVERYFROMSTOCK%type,
        FPnSTARTRENTFROM                          in out UNIQUEITEM.STARTRENTFROM%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEM.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEM.TIMESTAMP%type,
        FPnLASTWEAREREMPL_LINK_ID                 in out UNIQUEITEM.LASTWEAREREMPLOYMENT_LINK_ID%type)
 is
begin
  begin
   insert into UNIQUEITEM(
        UNIQUEITEM_ID,
        PRIMARYID,
        IDCODESEQUENCENUMBER,
        STATUSCHANGEDATE,
        STAYCHANGEDATE,
        LASTINSCANDATE,
        LASTOUTSCANDATE,
        LASTSCANDATE,
        ITEMINFOUPDATEDATE,
        POOLITEM,
        WASHESTOTAL,
        REPAIRSTOTAL,
        REWASHTOTAL,
        CUSTOMEROWNED,
        BUSINESSUNIT_ID,
        STATUS_ID,
        PREVSTATUS_ID,
        PREVSTAY_ID,
        STAY_ID,
        PRODUCT_ID,
        SIZEDEFINITION_ID,
        FINISHINGMETHOD_ID,
        RELATEDCUSTOMER_ID,
        DISTRIBUTIONPOINT_ID,
        LASTDISTRIBUTIONPOINT_LINK_ID,
        PLANNEDDELIVERYDATE,
        DELIVERYFROMSTOCK,
        STARTRENTFROM,
        SYSTEMUSER_ID,
        TIMESTAMP,
				RESIDUALVALUE, REPLACEMENTPRICE, RESIDUALVALUEAMOUNT,
        LASTWEAREREMPLOYMENT_LINK_ID
    )
    values (
        SEQ_UNIQUEITEM.nextval,
        FPsPRIMARYID,
        FPnIDCODESEQUENCENUMBER,
        FPdtSTATUSCHANGEDATE,
        FPdtSTAYCHANGEDATE,
        FPdtLASTINSCANDATE,
        FPdtLASTOUTSCANDATE,
        FPdtLASTSCANDATE,
        FPdtITEMINFOUPDATEDATE,
        FPsPOOL,
        FPnWASHESTOTAL,
        FPnREPAIRSTOTAL,
        FPnREWASHTOTAL,
        FPsCUSTOMEROWNED,
        FPnBUSINESSUNIT_ID,
        FPnSTATUS_ID,
        FPnPREVSTATUS_ID,
        FPnPREVSTAY_ID,
        FPnSTAY_ID,
        FPnPRODUCT_ID,
        FPnSIZEDEFINITION_ID,
        FPnFINISHINGMETHOD_ID,
        FPnRELATEDCUSTOMER_ID,
        FPnDISTRIBUTIONPOINT_ID,
        FPnLASTDISTRIBPOINT_LINK_ID,
        FPdtPLANNEDDELIVERYDATE,
        FPsDELIVERYFROMSTOCK,
        FPnSTARTRENTFROM,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
				0, 0, 0,
        FPnLASTWEAREREMPL_LINK_ID
    ) returning UNIQUEITEM_ID into FPnUNIQUEITEM_ID;
    insert into UNIQUEITEM_LINK(
        UNIQUEITEM_LINK_ID,
        UNIQUEITEM_ID,
        RAGGEDITEM_ID,
        SYSTEMUSER_ID,
        TIMESTAMP)
    values (
        FPnUNIQUEITEM_ID,
        FPnUNIQUEITEM_ID,
        null,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
  exception
  	when dup_val_on_index then
	    update UNIQUEITEM
      set
        PRIMARYID = FPsPRIMARYID,
        IDCODESEQUENCENUMBER = FPnIDCODESEQUENCENUMBER,
        STATUSCHANGEDATE = FPdtSTATUSCHANGEDATE,
        STAYCHANGEDATE = FPdtSTAYCHANGEDATE,
        LASTINSCANDATE = FPdtLASTINSCANDATE,
        LASTOUTSCANDATE = FPdtLASTOUTSCANDATE,
        LASTSCANDATE = FPdtLASTSCANDATE,
        ITEMINFOUPDATEDATE = FPdtITEMINFOUPDATEDATE,
        POOLITEM = FPsPOOL,
        WASHESTOTAL = FPnWASHESTOTAL,
        REPAIRSTOTAL = FPnREPAIRSTOTAL,
        REWASHTOTAL = FPnREWASHTOTAL,
        CUSTOMEROWNED = FPsCUSTOMEROWNED,
        BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID,
        STATUS_ID = FPnSTATUS_ID,
        PREVSTATUS_ID = FPnPREVSTATUS_ID,
        PREVSTAY_ID = FPnPREVSTAY_ID,
        STAY_ID = FPnSTAY_ID,
        PRODUCT_ID = FPnPRODUCT_ID,
        SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID,
        FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID,
        RELATEDCUSTOMER_ID = FPnRELATEDCUSTOMER_ID,
        DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID,
        LASTDISTRIBUTIONPOINT_LINK_ID = FPnLASTDISTRIBPOINT_LINK_ID,
        PLANNEDDELIVERYDATE = FPdtPLANNEDDELIVERYDATE,
        DELIVERYFROMSTOCK = FPsDELIVERYFROMSTOCK,
        STARTRENTFROM = FPnSTARTRENTFROM,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP,
        LASTWEAREREMPLOYMENT_LINK_ID = FPnLASTWEAREREMPL_LINK_ID
      where PRIMARYID = FPsPRIMARYID and
            IDCODESEQUENCENUMBER = FPnIDCODESEQUENCENUMBER and
            BUSINESSUNIT_ID = FPnBUSINESSUNIT_ID
			returning UNIQUEITEM_ID into FPnUNIQUEITEM_ID ;
  end;
end;

procedure CFbRetrieveProductInformations(
          FPnCUSTOMER_ID                          in CUSTOMER.CUSTOMER_ID%type,
          FPsPRODUCTCODE                          in  PRODUCT.CODE%type,
          FPsSIZEDEFINITIONCODE                   in  SIZEDEFINITION.CODE%type,
          FPnSUPPLIERNUMBER                       in  SUPPLIER.SUPPLIERNUMBER%type,
          FPnPRODUCT_ID                           out PRODUCT.PRODUCT_ID%type,
          FPnSIZEDEFINITION_ID                    out SIZEDEFINITION.SIZEDEFINITION_ID%type,
          FPnFINISHINGMETHOD_ID                   out FINISHINGMETHOD.FINISHINGMETHOD_ID%type,
          FPnSUPPLIER_ID                          out SUPPLIER.SUPPLIER_ID%type,
          FPnCURRENCY_ID                          out SUPPLIER.CURRENCY_ID%type,
          FPnError                                in out int)is
begin
  FPnError := 1;
  select PRODUCT_ID
  into FPnPRODUCT_ID
  from PRODUCT
  where LEGACYPRODUCTCODE = FPsPRODUCTCODE AND MODEL = 'Y';

  FPnError := 2;
  select SIZEDEFINITION_ID
  into FPnSIZEDEFINITION_ID
  from SIZEDEFINITION
  where CODE = FPsSIZEDEFINITIONCODE;

  FPnError := 3;
  if FPnSUPPLIERNUMBER > 0 then
    select SUPPLIER_ID,CURRENCY_ID
    into FPnSUPPLIER_ID,FPnCURRENCY_ID
    from SUPPLIER
    where SUPPLIERNUMBER = FPnSUPPLIERNUMBER;
  else
    select P.SUPPLIER_ID,S.CURRENCY_ID
    into FPnSUPPLIER_ID,FPnCURRENCY_ID
    from PRODUCT P,SUPPLIER S
    where P.PRODUCT_ID = FPnPRODUCT_ID and P.SUPPLIER_ID = S.SUPPLIER_ID;
  end if;

  FPnError := 4;
	for vCursor in ( select PLPC.FINISHINGMETHOD_ID  from PRODUCTLISTPERCUSTOMER PLPC,SIZEDEFINITION
										where  PLPC.CUSTOMER_ID = FPnCUSTOMER_ID AND
										PLPC.PRODUCT_ID =  FPnPRODUCT_ID AND
									  PLPC.SIZEDEFINITION_ID = SIZEDEFINITION.SIZEDEFINITION_ID AND
									  ((SIZEDEFINITION.CODE = FPsSIZEDEFINITIONCODE) OR (SIZEDEFINITION.CODE = '*')) AND
										PLPC.DATEACTIVE <= TO_DATE(SYSDATE) AND
										PLPC.DATEINACTIVE >= TO_DATE(SYSDATE)
										order by plpc.dateactive desc) loop
		FPnFINISHINGMETHOD_ID:=vCursor.FINISHINGMETHOD_ID;
		exit;
	end loop ;
  FPnError := 0;
exception
  when no_data_found then null;
  when others then raise;

end;

end PACK_UNIQUEITEM;

/
create or replace PACKAGE PACK_UNIQUEITEMFIXEDINFO is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMFIXEDINFO.UNIQUEITEM_ID%type,
        FPdtPURCHASEDATE                          in out UNIQUEITEMFIXEDINFO.PURCHASEDATE%type,
        FPdtLASTONSTOCKDATE                       in out UNIQUEITEMFIXEDINFO.LASTONSTOCKDATE%type,
        FPdtFIRSTISSUEDATE                        in out UNIQUEITEMFIXEDINFO.FIRSTISSUEDATE%type,
        FPdtLASTISSUEDATE                         in out UNIQUEITEMFIXEDINFO.LASTISSUEDATE%type,
        FPnNUMBEROFISSUES                         in out UNIQUEITEMFIXEDINFO.NUMBEROFISSUES%type,
        FPdtENDDATEFULLRENT                       in out UNIQUEITEMFIXEDINFO.ENDDATEFULLRENT%type,
        FPnDAYSINCIRCPREVISSUE                    in out UNIQUEITEMFIXEDINFO.DAYSINCIRCPREVISSUE%type,
        FPnDAYSINSTOCKPREVIOUS                    in out UNIQUEITEMFIXEDINFO.DAYSINSTOCKPREVIOUS%type,
        FPnPURCHASEPRICE                          in out UNIQUEITEMFIXEDINFO.PURCHASEPRICE%type,
        FPsREMARK                                 in out UNIQUEITEMFIXEDINFO.REMARK%type,
        FPnQUALITYGRADE_ID                        in out UNIQUEITEMFIXEDINFO.QUALITYGRADE_ID%type,
        FPnSUPPLIER_ID                            in out UNIQUEITEMFIXEDINFO.SUPPLIER_ID%type,
        FPnCURRENCY_ID                            in out UNIQUEITEMFIXEDINFO.CURRENCY_ID%type,
        FPnISSUEDBYWORKORDER_ID                   in out UNIQUEITEMFIXEDINFO.ISSUEDBYWORKORDER_ID%type,
        FPnREASONCODE_ID                          in out UNIQUEITEMFIXEDINFO.REASONCODE_ID%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMFIXEDINFO.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMFIXEDINFO.TIMESTAMP%type);
end PACK_UNIQUEITEMFIXEDINFO;


/
create or replace PACKAGE BODY PACK_UNIQUEITEMFIXEDINFO is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMFIXEDINFO.UNIQUEITEM_ID%type,
        FPdtPURCHASEDATE                          in out UNIQUEITEMFIXEDINFO.PURCHASEDATE%type,
        FPdtLASTONSTOCKDATE                       in out UNIQUEITEMFIXEDINFO.LASTONSTOCKDATE%type,
        FPdtFIRSTISSUEDATE                        in out UNIQUEITEMFIXEDINFO.FIRSTISSUEDATE%type,
        FPdtLASTISSUEDATE                         in out UNIQUEITEMFIXEDINFO.LASTISSUEDATE%type,
        FPnNUMBEROFISSUES                         in out UNIQUEITEMFIXEDINFO.NUMBEROFISSUES%type,
        FPdtENDDATEFULLRENT                       in out UNIQUEITEMFIXEDINFO.ENDDATEFULLRENT%type,
        FPnDAYSINCIRCPREVISSUE                    in out UNIQUEITEMFIXEDINFO.DAYSINCIRCPREVISSUE%type,
        FPnDAYSINSTOCKPREVIOUS                    in out UNIQUEITEMFIXEDINFO.DAYSINSTOCKPREVIOUS%type,
        FPnPURCHASEPRICE                          in out UNIQUEITEMFIXEDINFO.PURCHASEPRICE%type,
        FPsREMARK                                 in out UNIQUEITEMFIXEDINFO.REMARK%type,
        FPnQUALITYGRADE_ID                        in out UNIQUEITEMFIXEDINFO.QUALITYGRADE_ID%type,
        FPnSUPPLIER_ID                            in out UNIQUEITEMFIXEDINFO.SUPPLIER_ID%type,
        FPnCURRENCY_ID                            in out UNIQUEITEMFIXEDINFO.CURRENCY_ID%type,
        FPnISSUEDBYWORKORDER_ID                   in out UNIQUEITEMFIXEDINFO.ISSUEDBYWORKORDER_ID%type,
        FPnREASONCODE_ID                          in out UNIQUEITEMFIXEDINFO.REASONCODE_ID%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMFIXEDINFO.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMFIXEDINFO.TIMESTAMP%type)
is
begin
  begin
   insert into UNIQUEITEMFIXEDINFO(
        UNIQUEITEM_ID,
        PURCHASEDATE,
        LASTONSTOCKDATE,
        FIRSTISSUEDATE,
        LASTISSUEDATE,
        NUMBEROFISSUES,
        ENDDATEFULLRENT,
        DAYSINCIRCPREVISSUE,
        DAYSINSTOCKPREVIOUS,
        PURCHASEPRICE,
        REMARK,
        QUALITYGRADE_ID,
        SUPPLIER_ID,
        CURRENCY_ID,
        ISSUEDBYWORKORDER_ID,
        REASONCODE_ID,
        SYSTEMUSER_ID,
        TIMESTAMP,
				TEMPORARYID
    )
   values (
        FPnUNIQUEITEM_ID,
        FPdtPURCHASEDATE,
        FPdtLASTONSTOCKDATE,
        FPdtFIRSTISSUEDATE,
        FPdtLASTISSUEDATE,
        FPnNUMBEROFISSUES,
        FPdtENDDATEFULLRENT,
        FPnDAYSINCIRCPREVISSUE,
        FPnDAYSINSTOCKPREVIOUS,
        FPnPURCHASEPRICE,
        FPsREMARK,
        FPnQUALITYGRADE_ID,
        FPnSUPPLIER_ID,
        FPnCURRENCY_ID,
        FPnISSUEDBYWORKORDER_ID,
        FPnREASONCODE_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
				'N'
    );
  exception
  	when dup_val_on_index then
	  update UNIQUEITEMFIXEDINFO
    set
        PURCHASEDATE = FPdtPURCHASEDATE,
        LASTONSTOCKDATE = FPdtLASTONSTOCKDATE,
        FIRSTISSUEDATE = FPdtFIRSTISSUEDATE,
        LASTISSUEDATE = FPdtLASTISSUEDATE,
        NUMBEROFISSUES = FPnNUMBEROFISSUES,
        ENDDATEFULLRENT = FPdtENDDATEFULLRENT,
        DAYSINCIRCPREVISSUE = FPnDAYSINCIRCPREVISSUE,
        DAYSINSTOCKPREVIOUS = FPnDAYSINSTOCKPREVIOUS,
        PURCHASEPRICE = FPnPURCHASEPRICE,
        REMARK = FPsREMARK,
        QUALITYGRADE_ID = FPnQUALITYGRADE_ID,
        SUPPLIER_ID = FPnSUPPLIER_ID,
        CURRENCY_ID = FPnCURRENCY_ID,
        ISSUEDBYWORKORDER_ID = FPnISSUEDBYWORKORDER_ID,
        REASONCODE_ID = FPnREASONCODE_ID,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where UNIQUEITEM_ID = FPnUNIQUEITEM_ID;
  end;
end;

end PACK_UNIQUEITEMFIXEDINFO;


/
create or replace PACKAGE PACK_UNIQUEITEMFLAG is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMFLAG.UNIQUEITEM_ID%type,
        FPnFLAG_ID                                in out UNIQUEITEMFLAG.FLAG_ID%type,
        FPdtSTARTDATE                             in out UNIQUEITEMFLAG.STARTDATE%type,
        FPsFREETEXT                               in out UNIQUEITEMFLAG.FREETEXTITEM%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMFLAG.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMFLAG.TIMESTAMP%type);

end PACK_UNIQUEITEMFLAG;

/
create or replace PACKAGE BODY PACK_UNIQUEITEMFLAG is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMFLAG.UNIQUEITEM_ID%type,
        FPnFLAG_ID                                in out UNIQUEITEMFLAG.FLAG_ID%type,
        FPdtSTARTDATE                             in out UNIQUEITEMFLAG.STARTDATE%type,
        FPsFREETEXT                               in out UNIQUEITEMFLAG.FREETEXTITEM%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMFLAG.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMFLAG.TIMESTAMP%type)
is
begin
  begin
     insert into UNIQUEITEMFLAG(
        UNIQUEITEM_ID,
        FLAG_ID,
        STARTDATE,
        FREETEXTITEM,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        FPnUNIQUEITEM_ID,
        FPnFLAG_ID,
        FPdtSTARTDATE,
        FPsFREETEXT,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
  exception
  	when dup_val_on_index then
	  update UNIQUEITEMFLAG
    set
        UNIQUEITEM_ID = FPnUNIQUEITEM_ID,
        FLAG_ID = FPnFLAG_ID,
        STARTDATE = FPdtSTARTDATE,
        FREETEXTITEM = FPsFREETEXT,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where UNIQUEITEM_ID = FPnUNIQUEITEM_ID and FLAG_ID = FPnFLAG_ID;
  end;
end;

end PACK_UNIQUEITEMFLAG;

/
create or replace PACKAGE PACK_UNIQUEITEMMODIFICATION is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMMODIFICATION.UNIQUEITEM_ID%type,
        FPnMODIFICATION_ID                        in out UNIQUEITEMMODIFICATION.MODIFICATION_ID%type,
        FPnSEQUENCENUMBER                         in out UNIQUEITEMMODIFICATION.SEQUENCENUMBER%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMMODIFICATION.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMMODIFICATION.TIMESTAMP%type);

end PACK_UNIQUEITEMMODIFICATION;

/
create or replace PACKAGE BODY PACK_UNIQUEITEMMODIFICATION is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMMODIFICATION.UNIQUEITEM_ID%type,
        FPnMODIFICATION_ID                        in out UNIQUEITEMMODIFICATION.MODIFICATION_ID%type,
        FPnSEQUENCENUMBER                         in out UNIQUEITEMMODIFICATION.SEQUENCENUMBER%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMMODIFICATION.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMMODIFICATION.TIMESTAMP%type)
is
begin
  begin
    insert into UNIQUEITEMMODIFICATION(
        UNIQUEITEM_ID,
        MODIFICATION_ID,
        SEQUENCENUMBER,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        FPnUNIQUEITEM_ID,
        FPnMODIFICATION_ID,
        FPnSEQUENCENUMBER,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
  exception
  	when dup_val_on_index then
	  update UNIQUEITEMMODIFICATION
    set
        UNIQUEITEM_ID = FPnUNIQUEITEM_ID,
        MODIFICATION_ID = FPnMODIFICATION_ID,
        SEQUENCENUMBER = FPnSEQUENCENUMBER,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where UNIQUEITEM_ID = FPnUNIQUEITEM_ID and MODIFICATION_ID = FPnMODIFICATION_ID;
  end;
end;

end PACK_UNIQUEITEMMODIFICATION;

/
create or replace PACKAGE PACK_UNIQUEITEMNONPOOL is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMNONPOOL.UNIQUEITEM_ID%type,
        FPnGARMENTSEQUENCENUMBER                  in out UNIQUEITEMNONPOOL.GARMENTSEQUENCENUMBER%type,
        FPnWEARERINVENTORY_ID                     in out UNIQUEITEMNONPOOL.WEARERINVENTORY_ID%type,
        FPnWEAREREMPLOYMENT_ID                    in out UNIQUEITEMNONPOOL.WEAREREMPLOYMENT_ID%type,
        FPnWASHESTHISISSUE                        in out UNIQUEITEMNONPOOL.WASHESTHISISSUE%type,
        FPnREPAIRSTHISISSUE                       in out UNIQUEITEMNONPOOL.REPAIRSTHISISSUE%type,
        FPnREWASHTHISISSUE                        in out UNIQUEITEMNONPOOL.REWASHTHISISSUE%type,
        FPnREPLACEMENTWORKORDERLINE_ID            in out UNIQUEITEMNONPOOL.REPLACEMENTWORKORDERLINE_ID%type,
        FPsFREEEXTRAGARMENT                       in out UNIQUEITEMNONPOOL.FREEEXTRAGARMENT%type,
        FPdtENDDATEFREEEXTRA                      in out UNIQUEITEMNONPOOL.ENDDATEFREEEXTRA%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMNONPOOL.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMNONPOOL.TIMESTAMP%type);

end PACK_UNIQUEITEMNONPOOL;


/
create or replace PACKAGE BODY PACK_UNIQUEITEMNONPOOL is

procedure CFbStoreOrCreate (
        FPnUNIQUEITEM_ID                          in out UNIQUEITEMNONPOOL.UNIQUEITEM_ID%type,
        FPnGARMENTSEQUENCENUMBER                  in out UNIQUEITEMNONPOOL.GARMENTSEQUENCENUMBER%type,
        FPnWEARERINVENTORY_ID                     in out UNIQUEITEMNONPOOL.WEARERINVENTORY_ID%type,
        FPnWEAREREMPLOYMENT_ID                    in out UNIQUEITEMNONPOOL.WEAREREMPLOYMENT_ID%type,
        FPnWASHESTHISISSUE                        in out UNIQUEITEMNONPOOL.WASHESTHISISSUE%type,
        FPnREPAIRSTHISISSUE                       in out UNIQUEITEMNONPOOL.REPAIRSTHISISSUE%type,
        FPnREWASHTHISISSUE                        in out UNIQUEITEMNONPOOL.REWASHTHISISSUE%type,
        FPnREPLACEMENTWORKORDERLINE_ID            in out UNIQUEITEMNONPOOL.REPLACEMENTWORKORDERLINE_ID%type,
        FPsFREEEXTRAGARMENT                       in out UNIQUEITEMNONPOOL.FREEEXTRAGARMENT%type,
        FPdtENDDATEFREEEXTRA                      in out UNIQUEITEMNONPOOL.ENDDATEFREEEXTRA%type,
        FPnSYSTEMUSER_ID                          in out UNIQUEITEMNONPOOL.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out UNIQUEITEMNONPOOL.TIMESTAMP%type)
is
begin
  begin
    insert into UNIQUEITEMNONPOOL(
        UNIQUEITEM_ID,
        GARMENTSEQUENCENUMBER,
        WEARERINVENTORY_ID,
        WEAREREMPLOYMENT_ID,
        WASHESTHISISSUE,
        REPAIRSTHISISSUE,
        REWASHTHISISSUE,
        REPLACEMENTWORKORDERLINE_ID,
        FREEEXTRAGARMENT,
        ENDDATEFREEEXTRA,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        FPnUNIQUEITEM_ID,
        FPnGARMENTSEQUENCENUMBER,
        FPnWEARERINVENTORY_ID,
        FPnWEAREREMPLOYMENT_ID,
        FPnWASHESTHISISSUE,
        FPnREPAIRSTHISISSUE,
        FPnREWASHTHISISSUE,
        FPnREPLACEMENTWORKORDERLINE_ID,
        FPsFREEEXTRAGARMENT,
        FPdtENDDATEFREEEXTRA,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
  exception
  	when dup_val_on_index then
	  update UNIQUEITEMNONPOOL
    set
        UNIQUEITEM_ID = FPnUNIQUEITEM_ID,
        GARMENTSEQUENCENUMBER = FPnGARMENTSEQUENCENUMBER,
        WEAREREMPLOYMENT_ID = FPnWEAREREMPLOYMENT_ID,
        WASHESTHISISSUE = FPnWASHESTHISISSUE,
        REPAIRSTHISISSUE = FPnREPAIRSTHISISSUE,
        REWASHTHISISSUE = FPnREWASHTHISISSUE,
        REPLACEMENTWORKORDERLINE_ID = FPnREPLACEMENTWORKORDERLINE_ID,
        FREEEXTRAGARMENT = FPsFREEEXTRAGARMENT,
        ENDDATEFREEEXTRA = FPdtENDDATEFREEEXTRA,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where UNIQUEITEM_ID = FPnUNIQUEITEM_ID;
  end;
end;

end PACK_UNIQUEITEMNONPOOL;


/
create or replace PACKAGE PACK_UTILITIES is
  --------------------------------------------------------------
  --Version 6.21 (containing -6.36 ABSN-8431 Peppol financial interface modification)
  --Created  - 17.02.2022
  --07.09.2022 ABS-132372
  --29.11.2022 ABS-143696
  --08.12.2022 ABS-144004
  --18-01-2023 ABS-145496 add inserts from Script_9.06.02.25.sql
  --02-02-2023 ABS-142183
  --08-02-2023 ABS-146770
  --09-03-2023 ABS-143030
  --16-03-2023 ABS-148457
  --31-03-2023 ABS-140251
  --30-05-2023 ABS-149829
  --04-08-2023 ABS-148409
  --02-11-2023 ABS-156002
  --15-11-2023 ABS-154785
  --05-04-2024 ABS-153450
  --10-09-2024 ABS-143696
  --16-09-2024 ABS-168938
  --25-09-2024 ABS-166491
  --07-10-2024 ABS-159186
  --15-10-2024 ABS-170121
  --04-10-2024 ABS-156244
  --01-11-2024 ABS-154228
  --15-11-2024 ABS-119980
  --04-12-2024 ABS-171953
  --06-12-2024 ABS-172112
  --20-01-2025 ABSN-675
  --27-01-2025 ABSN-674
  --28-01-2025 ABSN-2021
  --14-11-2025 ABSN-8431 Peppol financial interface modification
  --------------------------------------------------------------
  ABS_MAX_DATE date := to_date('31/12/2099', 'dd/MM/yyyy');
  type refcursor is ref cursor;

  procedure CreateSettingGroup(FPgroupName     settinggroup.groupname%type,
                               FPABSAccessOnly settinggroup.absaccessonly%type,
                               FPpassword      settinggroup.password%type);
  procedure CreateSystemSetting(FPgroupName      systemsetting.groupname%type,
                                FPname           systemsetting.name%type,
                                FPvalue          systemsetting.value%type,
                                FPtypeOfValue    systemsetting.typeofvalue%type,
                                FPfactoryDefault systemsetting.factorydefault%type,
                                FPdefaultAllowed systemsetting.defaultallowed%type,
                                FPusedAsDefault  systemsetting.usedasdefault%type,
                                FPminValue       systemsetting.minvalue%type,
                                FPmaxValue       systemsetting.maxvalue%type,
                                FPallowedChars   systemsetting.allowedchars%type,
                                FPdescription    long,
                                FPisObsolete     varchar2);

  procedure CreateSerialDevice(FPbrandType           serialdevice.brandtype%type,
                               FPname                serialdevice.name%type,
                               FPdeviceType          serialdevice.devicetype%type,
                               FPbaudRate            serialdevice.baudrate%type,
                               FPparity              serialdevice.parity%type,
                               FPdataBits            serialdevice.databits%type,
                               FPstopBits            serialdevice.stopbits%type,
                               FPinitString          serialdevice.initstring%type,
                               FPinitChar1           serialdevice.initchar1%type,
                               FPinitChar2           serialdevice.initchar2%type,
                               FPinitChar3           serialdevice.initchar3%type,
                               FPverifyString        serialdevice.verifystring%type,
                               FPverifyPosition      serialdevice.verifyposition%type,
                               FPweightPosition      serialdevice.weightposition%type,
                               FPweightStringSize    serialdevice.weightstringsize%type,
                               FPweightDecimals      serialdevice.weightdecimals%type,
                               FPendCharacter1       serialdevice.endcharacter1%type,
                               FPendCharacter2       serialdevice.endcharacter2%type,
                               FPalibiPrinter        serialdevice.alibiprinter%type,
                               FPalibiInitString     serialdevice.alibiinitstring%type,
                               FPalibiEndString      serialdevice.alibiendstring%type,
                               FPalibiVerifyString   serialdevice.alibiverifystring%type,
                               FPaccuracyLevelWeight serialdevice.accuracylevelweight%type,
                               FPtareInitString      serialdevice.tareinitstring%type,
                               FPtareVerifyString    serialdevice.tareverifystring%type,
                               FPweightseqnrposition serialdevice.weightseqnrposition%type,
                               FPweightseqnrlength   serialdevice.weightseqnrlength%type);

  procedure getISOYearWeekDay(FPdtDate in date,
                              FPnYear  out number,
                              FPnWeek  out number,
                              FPnDay   out number);

  procedure ImportLicenseForEmptyDatabase(FPsCustomerCode databasesettings.code%type,
                                          FPsLanguageCode databasesettings.lancode%type);
  procedure ImportLanguageForEmptyDatabase;
  procedure ImportPlantForEmptyDatabase(FPnPLANT_ID      in out PLANT.PLANT_ID%type,
                                        FPsCode          in plant.code%type,
                                        FPsName          in plant.name%type,
                                        FPnSYSTEMUSER_ID in plant.systemuser_id%type);

  procedure ImportFixedInfo(FPsLastScriptOfCurrentVersion varchar2,
                            fp_isRunForUpdate             number,
                            fp_error                      out number);

  procedure createNoteSequence(FPsSequenceName           in varchar2,
                               FPsExtraCode              in varchar2,
                               FPsTableName              in varchar2,
                               FPsNoteColumnName         in varchar2,
                               FPsBusinessUnitCode       in businessunit.code%type,
                               FPnMinValue               in integer,
                               FPnMaxValue               in integer,
                               FPsBusinessUnitColumnName in varchar2,
                               FPsFilter                 in varchar2);
  procedure createIdCodeSequence(FPsSequenceName           in varchar2,
                                 FPsExtraCode              in varchar2,
                                 FPsTableName              in varchar2,
                                 FPsNoteColumnName         in varchar2,
                                 FPsBusinessUnitCode       in businessunit.code%type,
                                 FPsMinValue               in varchar2,
                                 FPsMaxValue               in varchar2,
                                 FPsBusinessUnitColumnName in varchar2,
                                 FPsFilter                 in varchar2);

  function GetDayNumber(FPdtDate date) return int;

  PRAGMA RESTRICT_REFERENCES(GetDayNumber, WNDS, WNPS);

  procedure InsertReasonCodeDialogs(p_reasoncode_id      in reasoncode.reasoncode_id%type,
                                    rc_garmentreason     in reasoncode.garmentreason%type,
                                    rc_linenreason       in reasoncode.linenreason%type,
                                    rc_orpackreason      in reasoncode.orpackreason%type,
                                    rc_residentialreason in reasoncode.residentialreason%type,
                                    systemUserID         in systemuser.systemuser_id%type);

  procedure InsertRagReasonCodeDialogs(p_ragreason_id in ragreason.ragreason_id%type,
                                       systemUserID   in systemuser.systemuser_id%type);

end PACK_UTILITIES;
/
create or replace PACKAGE BODY PACK_UTILITIES is

  type t_arrayvarchar is table of varchar2(255) index by binary_integer;
  procedure write_log(fp_message  in varchar2,
                      fp_priority in number default 1) is
  begin
    /* Logging: write message in ABSLOG with these priorities:
    1 = Message
    2 = Warning
    3 = Error */
    abslogwrite.abslog_write(5, 'PACK_UTILITIES',null, fp_priority, fp_message,
                             0);
  end write_log;
  procedure CreateSettingGroup(FPgroupName     settinggroup.groupname%type,
                               FPABSAccessOnly settinggroup.absaccessonly%type,
                               FPpassword      settinggroup.password%type) is
  begin
    begin
      insert into settinggroup
        (groupname, absaccessonly, password)
      values
        (FPgroupName, FPABSAccessOnly, FPpassword);
      commit;
    exception
      when dup_val_on_index then
        null;
    end;
  end;

  procedure CreateSystemSetting(FPgroupName      systemsetting.groupname%type,
                                FPname           systemsetting.name%type,
                                FPvalue          systemsetting.value%type,
                                FPtypeOfValue    systemsetting.typeofvalue%type,
                                FPfactoryDefault systemsetting.factorydefault%type,
                                FPdefaultAllowed systemsetting.defaultallowed%type,
                                FPusedAsDefault  systemsetting.usedasdefault%type,
                                FPminValue       systemsetting.minvalue%type,
                                FPmaxValue       systemsetting.maxvalue%type,
                                FPallowedChars   systemsetting.allowedchars%type,
                                FPdescription    long,
                                FPisObsolete     varchar2) is
    systemuserid   int := 0;
    activevalue    varchar2(1);
    oldtypeofvalue systemsetting.typeofvalue%type;
    oldvalue       systemsetting.value%type;
  begin

    execute immediate 'alter session set nls_territory = america';
    if fpisobsolete = 'y' then
      activevalue := 'n';
    else
      activevalue := 'y';
    end if;

    for vcursor in (select plant_id from plant) loop
      begin
        insert into systemsetting
          (plant_id,
           groupname,
           name,
           value,
           typeofvalue,
           factorydefault,
           defaultallowed,
           usedasdefault,
           minvalue,
           maxvalue,
           allowedchars,
           description,
           systemuser_id,
           timestamp,
           active)
        values
          (vcursor.plant_id,
           fpgroupname,
           fpname,
           fpvalue,
           fptypeofvalue,
           fpfactorydefault,
           fpdefaultallowed,
           fpusedasdefault,
           fpminvalue,
           fpmaxvalue,
           fpallowedchars,
           fpdescription,
           systemuserid,
           sysdate,
           activevalue);
      exception
        when dup_val_on_index then

          select typeofvalue, value
            into oldtypeofvalue, oldvalue
            from systemsetting
           where plant_id = vcursor.plant_id
             and name = fpname;

          update systemsetting
             set groupname      = fpgroupname,
                 typeofvalue    = fptypeofvalue,
                 factorydefault = fpfactorydefault,
                 defaultallowed = fpdefaultallowed,
                 minvalue       = fpminvalue,
                 maxvalue       = fpmaxvalue,
                 allowedchars   = fpallowedchars,
                 description    = fpdescription,
                 timestamp      = sysdate,
                 systemuser_id  = systemuserid,
                 active         = activevalue
           where plant_id = vcursor.plant_id
             and name = fpname
             and (groupname != fpgroupname or typeofvalue != fptypeofvalue or
                 factorydefault != fpfactorydefault or
                 defaultallowed != fpdefaultallowed or
                 minvalue != fpminvalue or maxvalue != fpmaxvalue or
                 allowedchars != fpallowedchars or
                 description != fpdescription or active != activevalue);

          -- update the value if the type of value was changed
          if (((oldtypeofvalue != fptypeofvalue) and
             ((fpname = 'defaultcustomermin') or
             (fpname = 'defaultcustomermax')) and
             (oldvalue > fpmaxvalue or oldvalue < fpminvalue)) or
             ((oldtypeofvalue != fptypeofvalue) and
             (fpname != 'defaultcustomermin') and
             (fpname != 'defaultcustomermax'))) then
            update systemsetting
               set value = fpvalue
             where plant_id = vcursor.plant_id
               and name = fpname;
          end if;

      end;
    end loop;
    commit;
    dbms_output.put_line('restart server before ' || fpname ||
                         ' setting takes effect.');
  end;

  procedure CreateSerialDevice(FPbrandType           serialdevice.brandtype%type,
                               FPname                serialdevice.name%type,
                               FPdeviceType          serialdevice.devicetype%type,
                               FPbaudRate            serialdevice.baudrate%type,
                               FPparity              serialdevice.parity%type,
                               FPdataBits            serialdevice.databits%type,
                               FPstopBits            serialdevice.stopbits%type,
                               FPinitString          serialdevice.initstring%type,
                               FPinitChar1           serialdevice.initchar1%type,
                               FPinitChar2           serialdevice.initchar2%type,
                               FPinitChar3           serialdevice.initchar3%type,
                               FPverifyString        serialdevice.verifystring%type,
                               FPverifyPosition      serialdevice.verifyposition%type,
                               FPweightPosition      serialdevice.weightposition%type,
                               FPweightStringSize    serialdevice.weightstringsize%type,
                               FPweightDecimals      serialdevice.weightdecimals%type,
                               FPendCharacter1       serialdevice.endcharacter1%type,
                               FPendCharacter2       serialdevice.endcharacter2%type,
                               FPalibiPrinter        serialdevice.alibiprinter%type,
                               FPalibiInitString     serialdevice.alibiinitstring%type,
                               FPalibiEndString      serialdevice.alibiendstring%type,
                               FPalibiVerifyString   serialdevice.alibiverifystring%type,
                               FPaccuracyLevelWeight serialdevice.accuracylevelweight%type,
                               FPtareInitString      serialdevice.tareinitstring%type,
                               FPtareVerifyString    serialdevice.tareverifystring%type,
                               FPweightseqnrposition serialdevice.weightseqnrposition%type,
                               FPweightseqnrlength   serialdevice.weightseqnrlength%type) is
    serialDeviceID serialdevice.serialdevice_id%type;
  begin
    begin
      select serialdevice_id
        into serialDeviceID
        from serialdevice
       where brandtype = FPbrandType;
      update serialdevice
         set name                = FPname,
             deviceType          = FPdeviceType,
             baudRate            = FPbaudRate,
             parity              = FPparity,
             dataBits            = FPdataBits,
             stopBits            = FPstopBits,
             initString          = FPinitString,
             initChar1           = FPinitChar1,
             initChar2           = FPinitChar2,
             initChar3           = FPinitChar3,
             verifyString        = FPverifyString,
             verifyPosition      = FPverifyPosition,
             weightPosition      = FPweightPosition,
             weightStringSize    = FPweightStringSize,
             weightDecimals      = FPweightDecimals,
             endCharacter1       = FPendCharacter1,
             endCharacter2       = FPendCharacter2,
             alibiPrinter        = FPalibiPrinter,
             alibiInitString     = FPalibiInitString,
             alibiEndString      = FPalibiEndString,
             alibiVerifyString   = FPalibiVerifyString,
             accuracyLevelWeight = FPaccuracyLevelWeight,
             tareInitString      = FPtareInitString,
             tareVerifyString    = FPtareVerifyString,
             weightseqnrposition = FPweightseqnrposition,
             weightseqnrlength   = FPweightseqnrlength
       where serialdevice_id = serialDeviceID
         and not exists
       (select serialdevice_id
                from comportconfiguration
               where serialdevice_id = serialDeviceID);
    exception
      when no_data_found then
        insert into serialdevice
          (serialdevice_id,
           brandtype,
           name,
           devicetype,
           baudrate,
           parity,
           databits,
           stopbits,
           initstring,
           initchar1,
           initchar2,
           initchar3,
           verifystring,
           verifyposition,
           weightposition,
           weightstringsize,
           weightdecimals,
           endcharacter1,
           endcharacter2,
           alibiprinter,
           alibiinitstring,
           alibiendstring,
           alibiverifystring,
           accuracylevelweight,
           tareinitstring,
           tareverifystring,
           weightseqnrposition,
           weightseqnrlength)
        values
          (seq_serialdevice.nextval,
           FPbrandType,
           FPname,
           FPdeviceType,
           FPbaudRate,
           FPparity,
           FPdataBits,
           FPstopBits,
           FPinitString,
           FPinitChar1,
           FPinitChar2,
           FPinitChar3,
           FPverifyString,
           FPverifyPosition,
           FPweightPosition,
           FPweightStringSize,
           FPweightDecimals,
           FPendCharacter1,
           FPendCharacter2,
           FPalibiPrinter,
           FPalibiInitString,
           FPalibiEndString,
           FPalibiVerifyString,
           FPaccuracyLevelWeight,
           FPtareInitString,
           FPtareVerifyString,
           FPweightseqnrposition,
           FPweightseqnrlength);
    end;
    commit;
  end;

  procedure getISOYearWeekDay(FPdtDate in date,
                              FPnYear  out number,
                              FPnWeek  out number,
                              FPnDay   out number) is
  begin
    FPnYear := to_char(FPdtDate, 'IYYY');
    FPnWeek := GetISOWeek(FPdtDate);
    FPnDay  := to_char(FPdtDate, 'D');
  end;

  procedure ImportLicenseForEmptyDatabase(FPsCustomerCode databasesettings.code%type,
                                          FPsLanguageCode databasesettings.lancode%type) is
    languageCode databasesettings.lancode%type;
  begin
    select lancode into languageCode from databasesettings;
  exception
    when no_data_found then
      insert into databasesettings
        (code, lancode, menubaselanguage, referenceyear, referenceweek)
      values
        (FPsCustomerCode, FPsLanguageCode, FPsLanguageCode, 2001, 1);
  end;

  procedure ImportLanguageForEmptyDatabase is
    systemUserID       int := 0;
    languageCode       languages.code%type;
    legacyLanguageCode languages.legacylanguagecode%type;
    description        languages.description%type;
  begin
    select lancode into languageCode from databasesettings;
    if (languageCode = 'NL') then
      languageCode       := 'NL_NL';
      legacyLanguageCode := '1';
      description        := 'Nederlands (Nederland)';
    end if;
    if (languageCode = 'EN') then
      languageCode       := 'EN_US';
      legacyLanguageCode := '2';
      description        := 'English (United States)';
    end if;
    if (languageCode = 'DE') then
      languageCode       := 'DE_DE';
      legacyLanguageCode := '3';
      description        := 'Deutsch (Deutschland)';
    end if;
    if (languageCode = 'DA') then
      languageCode       := 'DA_DK';
      legacyLanguageCode := '4';
      description        := 'Dansk (Danmark)';
    end if;
    if (languageCode = 'ES') then
      languageCode       := 'ES_ES';
      legacyLanguageCode := '5';
      description        := 'Español (España)';
    end if;
    if (languageCode = 'FR') then
      languageCode       := 'FR_FR';
      legacyLanguageCode := '6';
      description        := 'Français (France)';
    end if;
    if (languageCode = 'JA') then
      languageCode       := 'JA_JA';
      legacyLanguageCode := '7';
      description        := 'Japanese (Japan)';
    end if;

    insert into languages
      (LANGUAGE_ID,
       CODE,
       DESCRIPTION,
       LEGACYLANGUAGECODE,
       TRANSLATEDESCRIPTION,
       SYSTEMUSER_ID,
       TIMESTAMP,
       USEFORSYSTEMUSER)
    values
      (seq_languages.nextval,
       languageCode,
       description,
       legacyLanguageCode,
       'Y',
       systemUserID,
       sysdate,
       'Y');
  exception
    when dup_val_on_index then
      null;
  end;

  procedure ImportPlantForEmptyDatabase(FPnPLANT_ID      in out plant.plant_id%type,
                                        FPsCode          in plant.code%type,
                                        FPsName          in plant.name%type,
                                        FPnSYSTEMUSER_ID in plant.systemuser_id%type) is
    languageID        languages.language_id%type;
    businessunitID    businessunit.businessunit_id%type;
    addressMinusID    address.address_id%type;
    currencyDefaultID currency.currency_id%type;
    countryDefaultID  country.country_id%type;
    plantdepartmentID plantdepartment.plantdepartment_id%type;
    regionID          region.region_id%type;
    divisionID        division.division_id%type;
    serviceteamID     serviceteam.serviceteam_id%type;
  begin

    select min(language_id) into languageID from languages;

    -- address '-'
    begin
      select address_id
        into addressMinusID
        from address
       where street = FPsCode
         and zipcode = '-'
         and city = '-';
    exception
      when too_many_rows then
        null;
      when no_data_found then
        insert into address
          (address_id,
           street,
           zipcode,
           city,
           state,
           county,
           systemuser_id,
           timestamp)
        values
          (seq_address.nextval,
           FPsCode,
           '-',
           '-',
           '-',
           '-',
           FPnSYSTEMUSER_ID,
           sysdate)
        returning address_id into addressMinusID;
    end;
    -- currency '-'
    begin
      select currency_id
        into currencyDefaultID
        from currency
       where rownum = 1;
    exception
      when no_data_found then
        insert into currency
          (currency_id,
           code,
           description,
           exchangerate,
           decimals,
           invoiceamountdecimals,
           systemuser_id,
           timestamp)
        values
          (seq_currency.nextval,
           '-',
           '-',
           1,
           2,
           2,
           FPnSYSTEMUSER_ID,
           sysdate)
        returning currency_id into currencyDefaultID;
    end;
    -- country '-'
    begin
      select country_id
        into countryDefaultID
        from country
       where rownum = 1;
    exception
      when no_data_found then
        insert into country
          (country_id,
           code,
           description,
           defaultcurrency_id,
           definetax,
           systemuser_id,
           timestamp)
        values
          (seq_country.nextval,
           '-',
           '-',
           currencyDefaultID,
           'Y',
           FPnSYSTEMUSER_ID,
           sysdate)
        returning country_id into countryDefaultID;
    end;
    -- region '-'
    begin
      select region_id into regionID from region where code = '-';
    exception
      when no_data_found then
        null;
        insert into region
          (region_id, code, systemuser_id, timestamp)
        values
          (seq_region.nextval, '-', FPnSYSTEMUSER_ID, sysdate)
        returning region_id into regionID;
        insert into region_desc
          (region_id, language_id, description, systemuser_id, timestamp)
        values
          (seq_region.currval, languageID, '-', FPnSYSTEMUSER_ID, sysdate);
    end;
    -- division '-'
    begin
      select division_id into divisionID from division where code = '-';
    exception
      when no_data_found then
        null;
        insert into division
          (division_id, code, systemuser_id, timestamp)
        values
          (seq_division.nextval, '-', FPnSYSTEMUSER_ID, sysdate)
        returning division_id into divisionID;
        insert into division_desc
          (division_id, language_id, description, systemuser_id, timestamp)
        values
          (seq_division.currval,
           languageID,
           '-',
           FPnSYSTEMUSER_ID,
           sysdate);
    end;
    -- plant FPsCode
    begin
      select plant_id into FPnPLANT_ID from plant where code = FPsCode;
    exception
      when no_data_found then
        null;
        select seq_plant.nextval into FPnPLANT_ID from dual;
        insert into plant
          (plant_id,
           code,
           name,
           active,
           financechargepercentage,
           language_id,
           address_id,
           country_id,
           headoffice_id,
           systemuser_id,
           timestamp)
        values
          (FPnPLANT_ID,
           FPsCode,
           FPsName,
           'Y',
           0,
           languageID,
           addressMinusID,
           countryDefaultID,
           FPnPLANT_ID,
           FPnSYSTEMUSER_ID,
           sysdate)
        returning plant_id into FPnPLANT_ID;
    end;
    -- plantdepartment '-'
    begin
      select plantdepartment_id
        into plantdepartmentID
        from plantdepartment
       where code = '-'
         and plant_id = FPnPLANT_ID;
    exception
      when no_data_found then
        insert into plantdepartment
          (plantdepartment_id,
           plant_id,
           code,
           description,
           systemuser_id,
           timestamp,
           defaultplantdepartment)
        values
          (seq_plantdepartment.nextval,
           FPnPLANT_ID,
           '-',
           '-',
           FPnSYSTEMUSER_ID,
           sysdate,
           'Y')
        returning plantdepartment_id into plantdepartmentID;
    end;
    -- serviceteam '-'
    begin
      select serviceteam_id
        into serviceteamID
        from serviceteam
       where code = '-'
         and plant_id = FPnPLANT_ID;
    exception
      when no_data_found then
        null;
        insert into serviceteam
          (serviceteam_id,
           plant_id,
           code,
           description,
           systemuser_id,
           timestamp)
        values
          (seq_serviceteam.nextval,
           FPnPLANT_ID,
           '-',
           '-',
           FPnSYSTEMUSER_ID,
           sysdate)
        returning serviceteam_id into serviceteamID;
    end;
    -- businessunit FPsCode
    begin
      select businessunit_id
        into businessunitID
        from businessunit
       where code = FPsCode;
    exception
      when no_data_found then
        insert into businessunit
          (businessunit_id,
           code,
           description,
           plant_id,
           region_id,
           division_id,
           systemuser_id,
           timestamp)
        values
          (seq_businessunit.nextval,
           FPsCode,
           'Default business unit',
           FPnPLANT_ID,
           regionID,
           divisionID,
           FPnSYSTEMUSER_ID,
           sysdate)
        returning businessunit_id into businessunitID;
        -- businessunit extraInfo
        insert into businessunitextrainfo
          (businessunit_id,
           determinestockroomuponreturn,
           systemuser_id,
           timestamp)
        values
          (businessunitID,
           'Y',
           FPnSYSTEMUSER_ID,
           sysdate);
    end;
  end;

procedure ImportFixedInfo(FPsLastScriptOfCurrentVersion varchar2,
                          fp_isRunForUpdate number,
                          fp_error out number) is
    /*
  isRunForUpdate
  1 - called for regular update
  0 - called for create from EmptyDbScript

  fp_error
  1 - error appeared
  0 - run successful
  */
  systemUserID  systemuser.systemuser_id%type;
  absUserID     systemuser.systemuser_id%type;
  languageID    languages.language_id%type;
  userGroupID   usergroup.usergroup_id%type;
  absGroupID    usergroup.usergroup_id%type;
  id            integer;
  type          t_arrayvarchar is table of varchar2(255) index by binary_integer;
  lastScriptNo  int;
  prefixScript  varchar2(50);

  procedure insertFixedInfoForINVOICEFREQUENCY(fp_invoicefrequency_id    invoicefrequency.invoicefrequency_id%type,
                                               fp_invoicefrequencynumber invoicefrequency.invoicefrequencynumber%type,
                                               fp_factorydescription     invoicefrequency.factorydescription%type,
                                               fp_pricefrequencynumber   invoicefrequency.pricefrequencynumber%type) is
  lv_pricefrequencynumber   invoicefrequency.pricefrequencynumber%type;
  begin
    select i.pricefrequencynumber
    into lv_pricefrequencynumber
    from invoicefrequency i
    where invoicefrequency_id = fp_invoicefrequency_id;
    if(fp_pricefrequencynumber <> lv_pricefrequencynumber) then
    update invoicefrequency i
    set i.pricefrequencynumber = fp_pricefrequencynumber, i.systemuser_id = systemUserID, i.timestamp = sysdate
    where i.invoicefrequency_id = fp_invoicefrequency_id;
    end if;
    exception
      when no_data_found then
      insert into invoicefrequency
        (invoicefrequency_id, invoicefrequencynumber, factorydescription, systemuser_id, timestamp, defaultfrequency,
         pricefrequencynumber)
      values
        (fp_invoicefrequency_id, fp_invoicefrequencynumber, fp_factorydescription, systemUserID, sysdate, 'N',
         fp_pricefrequencynumber);

  end insertFixedInfoForINVOICEFREQUENCY;

  procedure fixedInfoForINVOICEFREQUENCY is
  begin
    insertFixedInfoForINVOICEFREQUENCY(0, 0, 'Direct', 0);
    insertFixedInfoForINVOICEFREQUENCY(5, 5, 'Direct with all services', 0);
    insertFixedInfoForINVOICEFREQUENCY(10, 10, 'Weekly', 0);
    insertFixedInfoForINVOICEFREQUENCY(20, 20, 'Every 2 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(30, 30, 'Every 3 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(40, 40, 'Every 4 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(45, 45, '4-4-5 week schedule', 0);
    insertFixedInfoForINVOICEFREQUENCY(50, 50, 'Every 8 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(60, 60, 'Every 13 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(65, 65, 'Every 16 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(70, 70, 'Every 26 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(80, 80, 'Every 52 weeks', 0);
    insertFixedInfoForINVOICEFREQUENCY(105, 105, 'Twice a month', 0);
    insertFixedInfoForINVOICEFREQUENCY(110, 110, 'Monthly', 0);
    insertFixedInfoForINVOICEFREQUENCY(111, 111, 'Monthly (price*1)', 0);
    insertFixedInfoForINVOICEFREQUENCY(112, 112, 'Monthly with coefficient', 110);
    insertFixedInfoForINVOICEFREQUENCY(115, 115, 'Monthly (price*4.33)', 110);
    insertFixedInfoForINVOICEFREQUENCY(120, 120, 'Every 2 months', 0);
    insertFixedInfoForINVOICEFREQUENCY(121, 121, '2 Monthly(price*1)', 110);
    insertFixedInfoForINVOICEFREQUENCY(130, 130, 'Every 3 months', 0);
    insertFixedInfoForINVOICEFREQUENCY(131, 131, '3 Monthly(price*1)', 110);
    insertFixedInfoForINVOICEFREQUENCY(140, 140, 'Every 4 months', 0);
    insertFixedInfoForINVOICEFREQUENCY(141, 141, '4 Monthly(price*1)', 110);
    insertFixedInfoForINVOICEFREQUENCY(160, 160, 'Every 6 months', 0);
    insertFixedInfoForINVOICEFREQUENCY(161, 161, '6 Monthly(price*1)', 110);
    insertFixedInfoForINVOICEFREQUENCY(170, 170, 'Every 12 months', 0);
    insertFixedInfoForINVOICEFREQUENCY(171, 171, '12 Monthly(price*1)', 110);
    insertFixedInfoForINVOICEFREQUENCY(200, 200, 'Manual', 0);
    insert into invoicefrequency_desc
      (invoicefrequency_id, language_id, description, systemuser_id, timestamp)
      select x.invoicefrequency_id, lan.language_id, x.factorydescription, systemUserID, sysdate
        from invoicefrequency x, languages lan
       where lan.translatedescription = 'Y'
         and not exists (select 1
                from invoicefrequency_desc ifd
               where ifd.invoicefrequency_id = x.invoicefrequency_id
                 and ifd.language_id = lan.language_id);
      commit;
  exception
    when others then
      rollback;
      write_log('Error at INVOICEFREQUENCY: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForINVOICEFREQUENCY;

  procedure insertFixedInfoForINVOICELINETYPE(fp_invoicelinetype_id   invoicelinetype.invoicelinetype_id%type,
                                              fp_type                 invoicelinetype.type%type,
                                              fp_factorydescription   invoicelinetype.factorydescription%type,
                                              fp_includeinminimumcalc invoicelinetype.includeinminimumcalc%type,
                                              fp_taxtype              invoicelinetype.taxtype%type,
                                              fp_defineturnovergroup  invoicelinetype.defineturnovergroup%type,
                                              fp_definespecialcharge  invoicelinetype.definespecialcharge%type,
                                              fp_supressprinting      invoicelinetype.supressprinting%type,
                                              fp_includepocheck       invoicelinetype.includepocheck%type) is

  lv_factorydescription   invoicelinetype.factorydescription%type;
  begin
    select i.factorydescription
      into lv_factorydescription
      from invoicelinetype i
     where invoicelinetype_id = fp_invoicelinetype_id;

     if(lv_factorydescription <> fp_factorydescription) then
       update invoicelinetype i
       set i.factorydescription = fp_factorydescription, i.systemuser_id = systemUserID, i.timestamp = sysdate
       where i.invoicelinetype_id = fp_invoicelinetype_id;
       end if;
  exception
    when no_data_found then
      insert into invoicelinetype
        (invoicelinetype_id, type, factorydescription, includeinminimumcalc, taxtype, defineturnovergroup,
         definespecialcharge, supressprinting, includepocheck, systemuser_id, timestamp)
      values
        (fp_invoicelinetype_id, fp_type, fp_factorydescription, fp_includeinminimumcalc, fp_taxtype,
         fp_defineturnovergroup, fp_definespecialcharge, fp_supressprinting, fp_includepocheck, systemUserID, sysdate);
  end insertFixedInfoForINVOICELINETYPE;
  procedure fixedInfoForINVOICELINETYPE is
  begin
    insertFixedInfoForINVOICELINETYPE(1, 1, 'Rent', 'N', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(2, 2, 'Delivery (wash)', 'N', 3, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(3, 3, 'Soil Weight', 'N', 3, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(4, 4, 'Clean Weight', 'N', 3, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(5, 5, 'Sales', 'N', 1, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(6, 6, 'Repair', 'N', 3, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(7, 7, 'Replacement charge', 'N', 1, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(8, 8, 'Automatic Replacement', 'N', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(9, 9, 'Loss charge', 'N', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(10, 10, 'Residual value charge', 'N', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(11, 11, 'Garment Insurance', 'N', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(12, 12, 'Stockroom Handling & Label/Emblem charge', 'N', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(13, 13, 'Finance charge', 'N', 3, 'Y', 'N', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(14, 14, 'Cash Delay line', 'N', 0, 'N', 'N', 0, 'N');
    insertFixedInfoForINVOICELINETYPE(15, 15, 'Miscellaneous Invoice line', 'N', 3, 'Y', 'Y', 2, 'Y');
    insertFixedInfoForINVOICELINETYPE(16, 16, 'Special Charge', 'Y', 3, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(17, 17, 'Minimum invoice amount', 'N', 3, 'Y', 'N', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(18, 18, 'Tax', 'N', 0, 'N', 'N', 0, 'N');
    insertFixedInfoForINVOICELINETYPE(19, 19, 'Emblem Rent', 'N', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(20, 20, 'Locker Rent', 'N', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(21, 21, 'Locker Service', 'N', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(22, 22, 'Lease', 'N', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(23, 23, 'Stock Charge', 'N', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(24, 24, 'Lost Customer Residual Value Charge', 'N', 3, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(25, 25, 'Lost Revenue Charge', 'N', 3, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(26, 26, 'Residential Services Wash', 'Y', 3, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(27, 27, 'Client Labels', 'Y', 1, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(28, 28, 'Service Costs', 'N', 3, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(29, 29, 'Capped Excess Amounts', 'N', 3, 'Y', 'N', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(30, 30, 'Client Rent', 'N', 2, 'N', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(31, 31, 'Budget', 'Y', 3, 'Y', 'N', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(32, 32, 'Down Payment', 'N', 3, 'Y', 'N', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(33, 33, 'Statement fee', 'Y', 3, 'Y', 'N', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(34, 34, 'Custom Garment Charge', 'Y', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(35, 35, 'Service', 'Y', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(36, 36, 'Containers', 'Y', 2, 'Y', 'Y', 0, 'Y');
    insertFixedInfoForINVOICELINETYPE(37, 37, 'Service Event Charge', 'Y', 3, 'Y', 'Y', 0, 'Y');
    insert into invoicelinetype_desc
      (invoicelinetype_id, language_id, description, systemuser_id, timestamp)
      select x.invoicelinetype_id, lan.language_id, x.factorydescription, systemUserID, sysdate
        from invoicelinetype x, languages lan
       where lan.translatedescription = 'Y'
         and not exists (select 1
                from invoicelinetype_desc ild
               where ild.invoicelinetype_id = x.invoicelinetype_id
                 and ild.language_id = lan.language_id);
     commit;
  exception
    when others then
      rollback;
      write_log('Error at INVOICELINETYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForINVOICELINETYPE;

  procedure fixedInfoForINVOICELINETAX is
  begin
    select count(1)
      into id
      from invoicelinetypetax;
    if (id = 0) then
      insert into invoicelinetypetax
        (invoicelinetype_id, country_id, systemuser_id, timestamp)
        select invoicelinetype_id,
               (select min(country_id)
                   from country
                  where definetax = 'Y'), systemUserID, sysdate
          from invoicelinetype;
    end if;
    commit;
    exception
        when others then
      rollback;
      write_log('Error at invoicelinetypetax: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForINVOICELINETAX;

  procedure insertFixedInfoForINVOICELINESUBTYPE(fp_subtype            invoicelinesubtype.subtype%type,
                                                 fp_invoicelinetype_id invoicelinesubtype.invoicelinetype_id%type,
                                                 fp_factorydescription invoicelinesubtype.factorydescription%type) is

  lv_factorydescription invoicelinesubtype.factorydescription%type;

  begin
    select i.factorydescription
    into lv_factorydescription
    from invoicelinesubtype i
    where i.invoicelinetype_id = fp_invoicelinetype_id and i.subtype = fp_subtype;

    if(fp_factorydescription <> lv_factorydescription) then
      update invoicelinesubtype i
      set i.factorydescription = fp_factorydescription, i.systemuser_id = systemUserID, i.timestamp = sysdate
      where i.invoicelinetype_id = fp_invoicelinetype_id and i.subtype = fp_subtype;
      end if;

  exception
    when no_data_found then
      insert into invoicelinesubtype
        (invoicelinesubtype_id, subtype, invoicelinetype_id, factorydescription, systemuser_id, timestamp)
      values
        (seq_invoicelinesubtype.nextval, fp_subtype, fp_invoicelinetype_id, fp_factorydescription, systemUserID,
         sysdate);
  end insertFixedInfoForINVOICELINESUBTYPE;

  procedure fixedInfoForINVOICELINESUBTYPE is
  begin
    insertFixedInfoForINVOICELINESUBTYPE(0, 1, 'Rent Other Items');
    insertFixedInfoForINVOICELINESUBTYPE(0, 2, 'Wash LOG');
    insertFixedInfoForINVOICELINESUBTYPE(0, 4, 'Weight recording');
    insertFixedInfoForINVOICELINESUBTYPE(0, 5, 'Sales Products via Delivery Note ');
    insertFixedInfoForINVOICELINESUBTYPE(0, 6, 'Regular Repair');
    insertFixedInfoForINVOICELINESUBTYPE(0, 7, 'Replacement Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 8, 'Automatic Replace');
    insertFixedInfoForINVOICELINESUBTYPE(0, 9, 'Loss Charge Non Garments');
    insertFixedInfoForINVOICELINESUBTYPE(0, 10, 'Residual Value Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 11, 'Insurance Price per Product');
    insertFixedInfoForINVOICELINESUBTYPE(0, 13, 'Finance Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 15, 'Miscellaneous Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 17, 'Minimum Invoice Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 19, 'Emblem Rent');
    insertFixedInfoForINVOICELINESUBTYPE(0, 20, 'Locker Rent');
    insertFixedInfoForINVOICELINESUBTYPE(0, 21, 'Locker Service');
    insertFixedInfoForINVOICELINESUBTYPE(0, 22, 'Lease Non Garments');
    insertFixedInfoForINVOICELINESUBTYPE(0, 23, 'Stock Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 24, 'Lost Customer Residual Value Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 25, 'Lost Revenue Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 28, 'Service Costs LOG');
    insertFixedInfoForINVOICELINESUBTYPE(0, 29, 'Full credit on client invoice');
    insertFixedInfoForINVOICELINESUBTYPE(0, 30, 'Client Rent');
    insertFixedInfoForINVOICELINESUBTYPE(0, 31, 'Budget');
    insertFixedInfoForINVOICELINESUBTYPE(0, 32, 'Down Payment Debit');
    insertFixedInfoForINVOICELINESUBTYPE(0, 33, 'Statement Fee');
    insertFixedInfoForINVOICELINESUBTYPE(0, 34, 'Custom Garment Charge');
    insertFixedInfoForINVOICELINESUBTYPE(0, 36, 'Container Rent');
    insertFixedInfoForINVOICELINESUBTYPE(1, 1, 'Rent by Wearer Product');
    insertFixedInfoForINVOICELINESUBTYPE(1, 2, 'Wash specified by Wearer');
    insertFixedInfoForINVOICELINESUBTYPE(1, 5, 'Garment Sales via automatic sales during issue');
    insertFixedInfoForINVOICELINESUBTYPE(1, 6, 'Regular Repair COG');
    insertFixedInfoForINVOICELINESUBTYPE(1, 7, 'Loss (replacement)');
    insertFixedInfoForINVOICELINESUBTYPE(1, 9, 'Loss Charge Garments - Loan products');
    insertFixedInfoForINVOICELINESUBTYPE(1, 13, 'Cash Delay Charge');
    insertFixedInfoForINVOICELINESUBTYPE(1, 22, 'Lease Garments');
    insertFixedInfoForINVOICELINESUBTYPE(1, 28, 'Service Costs COG');
    insertFixedInfoForINVOICELINESUBTYPE(1, 29, 'Credit Excess Amount on client invoice');
    insertFixedInfoForINVOICELINESUBTYPE(1, 32, 'Down Payment Credit');
    insertFixedInfoForINVOICELINESUBTYPE(1, 34, 'Special Size Charge');
    insertFixedInfoForINVOICELINESUBTYPE(1, 36, 'Container Delivery Fee');
    insertFixedInfoForINVOICELINESUBTYPE(2, 1, 'Rent by Wearer Item Condensed');
    insertFixedInfoForINVOICELINESUBTYPE(2, 6, 'Service Charge');
    insertFixedInfoForINVOICELINESUBTYPE(2, 16, 'Postage & Transport costs');
    insertFixedInfoForINVOICELINESUBTYPE(2, 28, 'Service Costs for max inventory');
    insertFixedInfoForINVOICELINESUBTYPE(2, 29, 'Full debit to customer');
    insertFixedInfoForINVOICELINESUBTYPE(2, 36, 'Container Return Credit');
    insertFixedInfoForINVOICELINESUBTYPE(3, 1, 'Rent by Total Wearer');
    insertFixedInfoForINVOICELINESUBTYPE(3, 6, 'Service Charge COG');
    insertFixedInfoForINVOICELINESUBTYPE(3, 16, 'Direct Sales Handling Charge');
    insertFixedInfoForINVOICELINESUBTYPE(3, 28, 'Product list specific Service Costs LOG');
    insertFixedInfoForINVOICELINESUBTYPE(3, 29, 'Debit Excess Amount to customer');
    insertFixedInfoForINVOICELINESUBTYPE(4, 1, 'Rent by Product');
    insertFixedInfoForINVOICELINESUBTYPE(4, 6, 'Modification Charge');
    insertFixedInfoForINVOICELINESUBTYPE(4, 28, 'Product list specific Service Costs COG');
    insertFixedInfoForINVOICELINESUBTYPE(5, 1, 'Rent by Wearer Summary');
    insertFixedInfoForINVOICELINESUBTYPE(5, 5, 'General Sales Order Discount');
    insertFixedInfoForINVOICELINESUBTYPE(5, 6, 'Modification Charge COG');
    insertFixedInfoForINVOICELINESUBTYPE(5, 28, 'Product list specific Service Costs for max inventory');
    insertFixedInfoForINVOICELINESUBTYPE(6, 1, 'Under Use');
    insertFixedInfoForINVOICELINESUBTYPE(10, 6, 'Residential Repair');
    insertFixedInfoForINVOICELINESUBTYPE(6, 6, 'Summarized per Repairtype');
    insertFixedInfoForINVOICELINESUBTYPE(7, 1, 'Rent in Advance');
    insertFixedInfoForINVOICELINESUBTYPE(7, 6, 'Summarized per Repairtype - COG');
    insertFixedInfoForINVOICELINESUBTYPE(8, 1, 'Correction Rent');
    insertFixedInfoForINVOICELINESUBTYPE(8, 6, 'Detailed per Wearer');
    insertFixedInfoForINVOICELINESUBTYPE(9, 6, 'Detailed per Wearer - COG');
    insertFixedInfoForINVOICELINESUBTYPE(9, 12, 'Prep Charges');
    insertFixedInfoForINVOICELINESUBTYPE(10, 12, 'Emblem Charges');
    insertFixedInfoForINVOICELINESUBTYPE(11, 12, 'Code Label');
    insertFixedInfoForINVOICELINESUBTYPE(12, 12, 'Restocking Fee');
    insertFixedInfoForINVOICELINESUBTYPE(13, 2, 'Changes per Week');
    insertFixedInfoForINVOICELINESUBTYPE(14, 1, 'Rent Deposit Stock');
    insertFixedInfoForINVOICELINESUBTYPE(15, 2, 'Wash COG');
    insertFixedInfoForINVOICELINESUBTYPE(16, 9, 'Loss Credit');
    insertFixedInfoForINVOICELINESUBTYPE(17, 5, 'Garment Sales via Sales Note');
    insertFixedInfoForINVOICELINESUBTYPE(18, 5, 'Garment Sales Credit');
    insertFixedInfoForINVOICELINESUBTYPE(19, 11, 'Garment insurance for Repair ');
    insertFixedInfoForINVOICELINESUBTYPE(20, 11, 'Garment insurance for Loss');
    insertFixedInfoForINVOICELINESUBTYPE(21, 11, 'Garment insurance for Repair and Loss');
    insertFixedInfoForINVOICELINESUBTYPE(22, 11, 'Garment insurance for Residual Value ');
    insertFixedInfoForINVOICELINESUBTYPE(23, 11, 'Garment insurance for Repair and Residual Value');
    insertFixedInfoForINVOICELINESUBTYPE(24, 11, 'Garment insurance for Loss and Residual Value');
    insertFixedInfoForINVOICELINESUBTYPE(25, 11, 'Garment insurance for Loss, Repair and Residual Value');
    insertFixedInfoForINVOICELINESUBTYPE(26, 10, 'Contract Change');
    insertFixedInfoForINVOICELINESUBTYPE(26, 11, 'Material Maintenance Protection (MMP)');
    insertFixedInfoForINVOICELINESUBTYPE(27, 10, 'Replacement');
    insertFixedInfoForINVOICELINESUBTYPE(27, 11, 'Garment Maintenance Protection (GMP)');
    insertFixedInfoForINVOICELINESUBTYPE(28, 10, 'Out Of Circulation');
    insertFixedInfoForINVOICELINESUBTYPE(28, 11, 'Garment Setup Protection (GSP)');
    insertFixedInfoForINVOICELINESUBTYPE(29, 11, 'Garment Loss Protection (GLP)');
    insertFixedInfoForINVOICELINESUBTYPE(29, 26, 'Laundry');
    insertFixedInfoForINVOICELINESUBTYPE(30, 11, 'Garment Repair Protection (GRP)');
    insertFixedInfoForINVOICELINESUBTYPE(30, 26, 'Dry clean');
    insertFixedInfoForINVOICELINESUBTYPE(31, 9, 'Merchandise Buyout Charge (MBYO)');
    insertFixedInfoForINVOICELINESUBTYPE(31, 11, 'Merchandise Buyout Protection (MBYOP)');
    insertFixedInfoForINVOICELINESUBTYPE(31, 27, 'Labels Charged');
    insertFixedInfoForINVOICELINESUBTYPE(32, 11, 'Garment Emblem Protection (GEP)');
    insertFixedInfoForINVOICELINESUBTYPE(32, 27, 'Labels Free of Charge');
    insertFixedInfoForINVOICELINESUBTYPE(33, 9, 'Loss Charge Garments - Product list per Customer Inactive');
    insertFixedInfoForINVOICELINESUBTYPE(33, 27, 'Labels Patching');
    insertFixedInfoForINVOICELINESUBTYPE(33, 11, 'Material Loss Protection (MLP)');
    insertFixedInfoForINVOICELINESUBTYPE(34, 9, 'Loss Charge Garments - Wearer Inventory Inactive');
    insertFixedInfoForINVOICELINESUBTYPE(35, 9, 'Loss Charge Garments - Wearer Inactive');
    insertFixedInfoForINVOICELINESUBTYPE(36, 9, 'Loss Charge Garments - Replacement');
    insertFixedInfoForINVOICELINESUBTYPE(37, 9, 'Loss for pool');
    insertFixedInfoForINVOICELINESUBTYPE(37, 16, 'Client Charge');
    insertFixedInfoForINVOICELINESUBTYPE(38, 9, 'Credit for pool');
    insertFixedInfoForINVOICELINESUBTYPE(38, 12, 'COG Code Label');
    insertFixedInfoForINVOICELINESUBTYPE(39, 2, 'Wash based on soiled registered items');
    insertFixedInfoForINVOICELINESUBTYPE(39, 9, 'Loss Charge Garments - Decrease Max Inventory');
    insertFixedInfoForINVOICELINESUBTYPE(39, 12, 'Curtain Labels');
    insertFixedInfoForINVOICELINESUBTYPE(40, 1, 'Sample products');
    insertFixedInfoForINVOICELINESUBTYPE(40, 9, 'Loss Charge Garments - Replacement with no ragging of old');
    insertFixedInfoForINVOICELINESUBTYPE(40, 12, 'Exchange Charge');
    insertFixedInfoForINVOICELINESUBTYPE(41, 1, 'New Loan');
    insertFixedInfoForINVOICELINESUBTYPE(41, 2, 'Wash No Delivery');
    insertFixedInfoForINVOICELINESUBTYPE(41, 12, 'COG Name Label');
    insertFixedInfoForINVOICELINESUBTYPE(42, 1, 'Outstanding Loan');
    insertFixedInfoForINVOICELINESUBTYPE(42, 4, 'Special use');
    insertFixedInfoForINVOICELINESUBTYPE(42, 12, 'Specific Label');
    insertFixedInfoForINVOICELINESUBTYPE(43, 1, 'Excess');
    insertFixedInfoForINVOICELINESUBTYPE(43, 2, 'Heavy Soil');
    insertFixedInfoForINVOICELINESUBTYPE(43, 4, 'Curtains');
    insertFixedInfoForINVOICELINESUBTYPE(44, 1, 'Rent Not Returned items');
    insertFixedInfoForINVOICELINESUBTYPE(44, 2, 'Rent Not Returned items');
    insertFixedInfoForINVOICELINESUBTYPE(45, 1, 'Rent by Wearer Product Free of Charge');
    insertFixedInfoForINVOICELINESUBTYPE(46, 2, 'Wash No Delivery COG');
    insertFixedInfoForINVOICELINESUBTYPE(47, 2, 'Wash overuse');
    insertFixedInfoForINVOICELINESUBTYPE(48, 10, 'Damage Charge');
    insertFixedInfoForINVOICELINESUBTYPE(49, 1, 'Rental charge for lost garments');
    insertFixedInfoForINVOICELINESUBTYPE(50, 1, 'Rent per Changes per week per Max Inv based on Real Qty');
    insertFixedInfoForINVOICELINESUBTYPE(51, 1, 'Rent per Changes per week per Max Inv based on Max Qty');
    insertFixedInfoForINVOICELINESUBTYPE(52, 1, 'In Adv. Rent per Changes/Week per Max Inv based on Real Qty');
    insertFixedInfoForINVOICELINESUBTYPE(53, 1, 'In Adv. Rent per Changes/Week per Max Inv based on Max Qty');
    insertFixedInfoForINVOICELINESUBTYPE(54, 1, 'Rent per Changes per week per Max Inv movement in the period');
    insertFixedInfoForINVOICELINESUBTYPE(1, 37, 'Increase in Circulating Inventory');
    insertFixedInfoForINVOICELINESUBTYPE(2, 37, 'Decrease in Circulating Inventory');
    insert into invoicelinesubtype_desc
      (invoicelinesubtype_id, language_id, description, systemuser_id, timestamp)
      select i.invoicelinesubtype_id, l.language_id, i.factorydescription, systemUserID, sysdate
        from invoicelinesubtype i, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from invoicelinesubtype_desc ild
               where ild.invoicelinesubtype_id = i.invoicelinesubtype_id
                 and ild.language_id = l.language_id);
   commit;
  exception
    when others then
      rollback;
      write_log('Error at INVOICELINESUBTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForINVOICELINESUBTYPE;

  procedure insertFixedInfoForINVOICECORRECTIONTYPE(fp_code               invoicecorrectiontype.code%type,
                                                    fp_factorydescription invoicecorrectiontype.factorydescription%type,
                                                    fp_debitcredit        invoicecorrectiontype.debitcredit%type,
                                                    fp_sequencenumber     invoicecorrectiontype.sequencenumber%type,
                                                    fp_active             invoicecorrectiontype.active%type) is
    lv_code invoicecorrectiontype.code%type;
  begin
    select code
    into lv_code
    from invoicecorrectiontype
    where code = fp_code;
  exception
    when no_data_found then
      insert into invoicecorrectiontype
        (invoicecorrectiontype_id, code, factorydescription, systemuser_id, timestamp, debitcredit, sequencenumber,
         active)
      values
        (seq_invoicelinesubtype.nextval, fp_code, fp_factorydescription, systemUserID, sysdate, fp_debitcredit,
         fp_sequencenumber, fp_active);
  end insertFixedInfoForINVOICECORRECTIONTYPE;

  procedure fixedInfoForINVOICECORRECTIONTYPE is
  begin
    insertFixedInfoForINVOICECORRECTIONTYPE(101, 'Credit due to changes in quantity', 'C', 1, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(102, 'Correction due to changes in quantity', 'D', 2, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(103, 'Credit due to price changes', 'C', 3, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(104, 'Correction due to price changes', 'D', 4, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(105, 'Credit due to discount changes', 'C', 5, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(106, 'Correction due to discount changes', 'D', 6, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(107, 'Credit due to multiple changes', 'C', 7, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(108, 'Correction due to multiple changes', 'D', 8, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(109, 'Credit due to changes in rent stops', 'C', 9, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(110, 'Correction due to changes in rent stops', 'D', 10, 'Y');
    insertFixedInfoForINVOICECORRECTIONTYPE(111, 'Correction for not yet invoiced period', 'D', 11, 'Y');
    insert into invoicecorrectiontype_desc
      (invoicecorrectiontype_id, language_id, description, systemuser_id, timestamp)
      select i.invoicecorrectiontype_id, l.language_id, i.factorydescription, systemUserID, sysdate
        from invoicecorrectiontype i, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from invoicecorrectiontype_desc id
               where id.invoicecorrectiontype_id = i.invoicecorrectiontype_id
                 and id.language_id = l.language_id);
    commit;
  exception
    when others then
      rollback;
      write_log('Error at INVOICECORRECTIONTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForINVOICECORRECTIONTYPE;

  procedure insertFixedInfoForARTRANSACTIONTYPE(fp_debitcredit        artransactiontype.debitcredit%type,
                                                fp_typenumber         artransactiontype.typenumber%type,
                                                fp_factorydescription artransactiontype.factorydescription%type,
                                                fp_code               artransactiontype.code%type,
                                                fp_predefined         artransactiontype.predefined%type) is
    lv_factorydescription artransactiontype.factorydescription%type;
  begin
    select a.factorydescription
      into lv_factorydescription
      from artransactiontype a
     where a.debitcredit = fp_debitcredit
       and a.typenumber = fp_typenumber;
  exception
    when no_data_found then
      insert into artransactiontype
        (artransactiontype_id, debitcredit, typenumber, factorydescription, code, predefined, systemuser_id, timestamp)
      values
        (seq_artransactiontype.nextval, fp_debitcredit, fp_typenumber, fp_factorydescription, fp_code, fp_predefined,
         systemUserID, sysdate);
  end insertFixedInfoForARTRANSACTIONTYPE;
  procedure fixedInfoForARTRANSACTIONTYPE is
  begin
    insertFixedInfoForARTRANSACTIONTYPE('D', 1, 'Invoice', 'INV', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('D', 2, 'Open Difference', 'DIF', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('D', 3, 'Statement', 'STA', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('D', 4, 'Discount Charge', 'DIS', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('C', 1, 'Credit Invoice', 'CRD', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('C', 2, 'Open Difference Credit', 'DIF', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('C', 3, 'Statement Credit', 'STA', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('C', 4, 'Discount', 'DIS', 'Y');
    insertFixedInfoForARTRANSACTIONTYPE('C', 5, 'Payment', 'PAY', 'Y');
    insert into artransactiontype_desc
      (artransactiontype_id, language_id, description, systemuser_id, timestamp)
      select a.artransactiontype_id, l.language_id, a.factorydescription, systemUserID, sysdate
        from artransactiontype a, languages l
       where l.translatedescription = 'Y'
       and a.factorydescription is not null
         and not exists (select 1
                from artransactiontype_desc ad
               where ad.artransactiontype_id = a.artransactiontype_id
                 and ad.language_id = l.language_id);
    commit;
  exception
    when others then
      rollback;
      write_log('Error at ARTRANSACTIONTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForARTRANSACTIONTYPE;
  procedure insertFixedInfoForSTATUS(fp_statustype         status.statustype%type,
                                     fp_code               status.code%type,
                                     fp_legacystatuscode   status.legacystatuscode%type,
                                     fp_factorydescription status.factorydescription%type) is
    lv_factorydescription status.factorydescription%type;
    lv_code status.code%type;
  begin
    select s.factorydescription, s.code
      into lv_factorydescription, lv_code
      from status s
     where s.statustype = fp_statustype
       and s.code = fp_code;

      if(fp_factorydescription <> lv_factorydescription) then
        update status s
        set s.factorydescription = fp_factorydescription, s.systemuser_id = systemUserID, s.timestamp = sysdate
        where s.statustype = fp_statustype
        and s.code = fp_code;
        end if;

      if(fp_code <> lv_code) then
        update status s
        set s.code = fp_code, s.systemuser_id = systemUserID, s.timestamp = sysdate
        where s.statustype = fp_statustype
        and s.code = fp_code;
        end if;
  exception
    when no_data_found then
      insert into status
        (status_id, statustype, code, legacystatuscode, factorydescription, systemuser_id, timestamp)
      values
        (seq_status.nextval, fp_statustype, fp_code, fp_legacystatuscode, fp_factorydescription, systemUserID, sysdate);
  end insertFixedInfoForSTATUS;
  procedure fixedInfoForSTATUS is
  begin
    insertFixedInfoForSTATUS('IN', '1', null, 'Not Settled (US) / Test invoice (EU)');
    insertFixedInfoForSTATUS('IN', '2', null, 'Settled (US) / Final Invoice (EU)');
    insertFixedInfoForSTATUS('IN', '3', null, 'Cancelled');
    insertFixedInfoForSTATUS('PN', '5', null, 'Special Order');
    insertFixedInfoForSTATUS('PN', '10', null, 'Packing note');
    insertFixedInfoForSTATUS('PN', '20', null, 'In progress');
    insertFixedInfoForSTATUS('PN', '25', null, 'Packed');
    insertFixedInfoForSTATUS('PN', '30', null, 'Processed');
    insertFixedInfoForSTATUS('PN', '40', null, 'Cancelled');
    insertFixedInfoForSTATUS('PN', '50', null, 'Postponed');
    insertFixedInfoForSTATUS('WN', '20', null, 'In progress');
    insertFixedInfoForSTATUS('WN', '30', null, 'Processed');
    insertFixedInfoForSTATUS('WN', '40', null, 'Cancelled');
    insertFixedInfoForSTATUS('ST', '1', null, 'In Progress');
    insertFixedInfoForSTATUS('ST', '2', null, 'Processed');
    insertFixedInfoForSTATUS('ST', '3', null, 'Cancelled');
    insertFixedInfoForSTATUS('RB', '1', null, 'In Progress');
    insertFixedInfoForSTATUS('RB', '2', null, 'Completed');
    insertFixedInfoForSTATUS('WO', '3', null, 'Waiting Supervisor Approval');
    insertFixedInfoForSTATUS('WO', '05', null, 'Waiting for approval');
    insertFixedInfoForSTATUS('WO', '10', '1', 'New');
    insertFixedInfoForSTATUS('WO', '15', '1', 'Picked');
    insertFixedInfoForSTATUS('WO', '20', null, 'In Progress');
    insertFixedInfoForSTATUS('WO', '25', null, 'In Progress with Priority');
    insertFixedInfoForSTATUS('WO', '30', '3', 'Completed');
    insertFixedInfoForSTATUS('WO', '40', '4', 'Cancelled');
    insertFixedInfoForSTATUS('UI', '10', null, 'Stock');
    insertFixedInfoForSTATUS('UI', '20', null, 'In Circulation');
    insertFixedInfoForSTATUS('UI', '25', null, 'Picked');
    insertFixedInfoForSTATUS('UI', '30', null, 'Assigned');
    insertFixedInfoForSTATUS('UI', '35', null, 'Transfer Stock');
    insertFixedInfoForSTATUS('UI', '40', null, 'Ragged');
    insertFixedInfoForSTATUS('UI', '50', null, 'Sold');
    insertFixedInfoForSTATUS('UI', '60', null, 'Returned to Supplier');
    insertFixedInfoForSTATUS('UI', '70', null, 'Returned by customer');
    insertFixedInfoForSTATUS('UI', '80', null, 'Route Returned to Stock');
    insertFixedInfoForSTATUS('SR', '10', null, 'Outstanding');
    insertFixedInfoForSTATUS('SR', '20', null, 'Processed');
    insertFixedInfoForSTATUS('SR', '30', null, 'Cancel');
    insertFixedInfoForSTATUS('GD', '10', null, 'New');
    insertFixedInfoForSTATUS('GD', '11', null, 'Reset');
    insertFixedInfoForSTATUS('GD', '20', null, 'Export Created');
    insertFixedInfoForSTATUS('GD', '30', null, 'Export Sent');
    insertFixedInfoForSTATUS('GD', '40', null, 'Accepted');
    insertFixedInfoForSTATUS('GD', '50', null, 'Rejected');
    insertFixedInfoForSTATUS('GD', '60', null, 'Ignored/Not supported');
    insertFixedInfoForSTATUS('PO', '05', null, 'Waiting for approval');
    insertFixedInfoForSTATUS('PO', '10', null, 'New (approved)');
    insertFixedInfoForSTATUS('PO', '20', null, 'Sent');
    insertFixedInfoForSTATUS('PO', '25', null, 'Confirmed');
    insertFixedInfoForSTATUS('PO', '30', null, 'Partly received');
    insertFixedInfoForSTATUS('PO', '40', null, 'Completed (receiving)');
    insertFixedInfoForSTATUS('PO', '50', null, 'Cancelled');
    insertFixedInfoForSTATUS('BN', '10', null, 'New');
    insertFixedInfoForSTATUS('BN', '12', null, 'Repair Needed');
    insertFixedInfoForSTATUS('BN', '14', null, 'Rewash Needed');
    insertFixedInfoForSTATUS('BN', '16', null, 'Ragging Needed');
    insertFixedInfoForSTATUS('BN', '20', null, 'Scanned out');
    insertFixedInfoForSTATUS('UR', '10', null, 'In Circulation');
    insertFixedInfoForSTATUS('UR', '20', null, 'No product assigned');
    insertFixedInfoForSTATUS('UR', '30', null, 'Out of Circulation');
    insertFixedInfoForSTATUS('PL', '10', null, 'Proposal');
    insertFixedInfoForSTATUS('PL', '20', null, 'Picking in Progress');
    insertFixedInfoForSTATUS('PL', '30', null, 'Picking Confirmed');
    insertFixedInfoForSTATUS('PL', '40', null, 'Cancelled');
    insertFixedInfoForSTATUS('PL', '50', null, 'Issuing in Progress');
    insertFixedInfoForSTATUS('PL', '60', null, 'Issue Completed');
    insertFixedInfoForSTATUS('MO', '05', null, 'Waiting for approval');
    insertFixedInfoForSTATUS('MO', '10', null, 'New');
    insertFixedInfoForSTATUS('MO', '12', null, 'Not available');
    insertFixedInfoForSTATUS('MO', '15', null, 'Picked');
    insertFixedInfoForSTATUS('MO', '20', null, 'In progress');
    insertFixedInfoForSTATUS('MO', '25', null, 'In progress with priority');
    insertFixedInfoForSTATUS('MO', '30', null, 'Completed');
    insertFixedInfoForSTATUS('MO', '40', null, 'Cancelled');
    insertFixedInfoForSTATUS('MO', '50', null, 'Confirmed');
    insertFixedInfoForSTATUS('CA', '10', null, 'Available');
    insertFixedInfoForSTATUS('CA', '20', null, 'Loaded');
    insertFixedInfoForSTATUS('CA', '30', null, 'Ready for Sterilization');
    insertFixedInfoForSTATUS('CA', '40', null, 'Docked');
    insertFixedInfoForSTATUS('OR', '10', null, 'Generated(label)');
    insertFixedInfoForSTATUS('OR', '20', null, 'Assembled');
    insertFixedInfoForSTATUS('OR', '25', null, 'Loaded on Cart');
    insertFixedInfoForSTATUS('OR', '30', null, 'Sterilized');
    insertFixedInfoForSTATUS('OR', '40', null, 'Delivered');
    insertFixedInfoForSTATUS('OR', '50', null, 'Used');
    insertFixedInfoForSTATUS('OR', '60', null, 'Cancelled');
    insertFixedInfoForSTATUS('OR', '70', null, 'Recalled');
    insertFixedInfoForSTATUS('SL', '10', null, 'New');
    insertFixedInfoForSTATUS('SL', '20', null, 'In Progress');
    insertFixedInfoForSTATUS('SL', '30', null, 'Completed');
    insertFixedInfoForSTATUS('SL', '40', null, 'Closed');
    insertFixedInfoForSTATUS('PN', '60', null, 'Pre-packingnote');
    insertFixedInfoForSTATUS('CO', '10', null, 'New / Not yet approved');
    insertFixedInfoForSTATUS('CO', '20', null, 'Approved');
    insertFixedInfoForSTATUS('CO', '30', null, 'Extended');
    insertFixedInfoForSTATUS('CO', '40', null, 'Expired');
    insertFixedInfoForSTATUS('CO', '50', null, 'Terminated');
    insertFixedInfoForSTATUS('CN', '10', null, 'New');
    insertFixedInfoForSTATUS('CN', '20', null, 'In progress');
    insertFixedInfoForSTATUS('CN', '30', null, 'Processed');
    insertFixedInfoForSTATUS('CN', '40', null, 'Cancelled');
    insertFixedInfoForSTATUS('US', '1', null, 'No Action');
    insertFixedInfoForSTATUS('US', '2', null, 'Installation');
    insertFixedInfoForSTATUS('US', '3', null, 'Removal');
    insertFixedInfoForSTATUS('US', '4', null, 'Delivery');
    insertFixedInfoForSTATUS('US', '5', null, 'Deleted');
    insertFixedInfoForSTATUS('US', '6', null, 'Installed');
    insertFixedInfoForSTATUS('US', '7', null, 'Delivered');
    insertFixedInfoForSTATUS('US', '8', null, 'Contents Ordered');
    insertFixedInfoForSTATUS('US', '9', null, 'Removal Postponed');
    insertFixedInfoForSTATUS('US', '20', null, 'Service');
    insertFixedInfoForSTATUS('US', '21', null, 'Service Needed');
    insertFixedInfoForSTATUS('US', '22', null, 'Serviced');
    insertFixedInfoForSTATUS('US', '23', null, 'No Service needed');
    insert into status_desc
      (status_id, language_id, description, systemuser_id, timestamp)
      select s.status_id, l.language_id, s.factorydescription, systemUserID, sysdate
        from status s, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from status_desc sd
               where sd.status_id = s.status_id
                 and sd.language_id = l.language_id);
     commit;
  exception
    when others then
      rollback;
      write_log('Error at STATUS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSTATUS;

  procedure insertFixedInfoForSTAY(fp_staytype           stay.staytype%type,
                                   fp_staynr             stay.staynr%type,
                                   fp_factorydescription stay.factorydescription%type,
                                   fp_location           stay.location%type) is
    lv_factorydescription stay.factorydescription%type;

  begin
    select s.factorydescription
      into lv_factorydescription
      from stay s
     where s.staytype = fp_staytype
       and s.staynr = fp_staynr;
    if (fp_factorydescription <> lv_factorydescription) then
      update stay s
         set s.factorydescription = fp_factorydescription, s.systemuser_id = systemUserID, s.timestamp = sysdate
       where s.staytype = fp_staytype
         and s.staynr = fp_staynr;
    end if;

  exception
    when no_data_found then
      insert into stay
        (stay_id, staytype, staynr, factorydescription, systemuser_id, timestamp, location)
      values
        (seq_stay.nextval, fp_staytype, fp_staynr, fp_factorydescription, systemUserID, sysdate, fp_location);
  end insertFixedInfoForSTAY;
  procedure fixedInfoForSTAY is
  begin
    insertFixedInfoForSTAY(1, 10, 'In Stockroom', 1);
    insertFixedInfoForSTAY(1, 11, 'Stockroom/Picked', 1);
    insertFixedInfoForSTAY(1, 20, 'Outscan/At Customer', 2);
    insertFixedInfoForSTAY(1, 22, 'Clean in Garment Dispenser', 2);
    insertFixedInfoForSTAY(1, 23, 'Desk Scan/Issue to Wearer', 2);
    insertFixedInfoForSTAY(1, 24, 'Out of Garment Dispenser', 2);
    insertFixedInfoForSTAY(1, 25, 'Soiled in Garment Dispenser', 2);
    insertFixedInfoForSTAY(1, 26, 'Outscan/Transfer stock', 2);
    insertFixedInfoForSTAY(1, 27, 'On-site at Customer', 2);
    insertFixedInfoForSTAY(1, 28, 'Sent to Laundry', 4);
    insertFixedInfoForSTAY(1, 29, 'Returned / In Transit', 4);
    insertFixedInfoForSTAY(1, 30, 'In Scan/Soiled Received', 1);
    insertFixedInfoForSTAY(1, 31, 'Rewash', 1);
    insertFixedInfoForSTAY(1, 32, 'Repair/Mending', 3);
    insertFixedInfoForSTAY(1, 33, 'Checkpoint/Inspection', 1);
    insertFixedInfoForSTAY(1, 34, 'Sorted', 1);
    insertFixedInfoForSTAY(1, 35, 'OR Packing', 1);
    insertFixedInfoForSTAY(1, 36, 'Late Piece', 1);
    insertFixedInfoForSTAY(1, 37, 'Deposit Stock', 1);
    insertFixedInfoForSTAY(1, 38, 'Treatment', 1);
    insertFixedInfoForSTAY(1, 39, 'Bundle Scan', 1);
    insertFixedInfoForSTAY(1, 40, 'On shelf', 2);
    insertFixedInfoForSTAY(1, 41, 'Inscan / Clean Return', 1);
    insertFixedInfoForSTAY(1, 42, 'Locker Fed', 2);
    insertFixedInfoForSTAY(1, 44, 'Rejected from Customer / At Inscan', 1);
    insertFixedInfoForSTAY(1, 45, 'Route Returned', 1);
    insertFixedInfoForSTAY(1, 46, 'On-site Delivery Scan at Customer', 2);
    insertFixedInfoForSTAY(1, 47, 'Loaded on mat carry unit', 1);
    insertFixedInfoForSTAY(1, 48, 'Picked Up at Customer', 2);
    insertFixedInfoForSTAY(2, 10, 'InScan', 0);
    insertFixedInfoForSTAY(2, 20, 'OutScan/At Customer', 0);
    insertFixedInfoForSTAY(2, 21, 'On-site at customer', 0);
    insertFixedInfoForSTAY(2, 22, 'Picked Up at Customer', 0);
    insertFixedInfoForSTAY(2, 23, 'Received from Laundry', 0);
    insertFixedInfoForSTAY(2, 24, 'Sent to Laundry', 0);
    insertFixedInfoForSTAY(2, 30, 'Disinfection', 0);
    insertFixedInfoForSTAY(2, 40, 'OR Load', 0);
    insertFixedInfoForSTAY(2, 41, 'OR Sterile', 0);
    insertFixedInfoForSTAY(2, 43, 'Mat Loading', 0);
    insertFixedInfoForSTAY(2, 50, 'Maintenance', 0);
    insertFixedInfoForSTAY(2, 60, 'Truck', 0);
    insertFixedInfoForSTAY(2, 61, 'Loaded in Truck', 0);
    insertFixedInfoForSTAY(2, 65, 'Loading / Unloading Area', 0);
    insertFixedInfoForSTAY(3, 10, 'Label Printed', 0);
    insertFixedInfoForSTAY(3, 20, 'OutScan/At Customer', 0);
    insertFixedInfoForSTAY(3, 30, 'Assemble pack', 0);
    insertFixedInfoForSTAY(3, 35, 'OR Load', 0);
    insertFixedInfoForSTAY(3, 40, 'Confirm Sterilization', 0);
    insertFixedInfoForSTAY(3, 45, 'Deposit', 0);
    insertFixedInfoForSTAY(3, 46, 'Transit', 0);
    insertFixedInfoForSTAY(3, 50, 'Inscan', 0);
    insertFixedInfoForSTAY(4, 10, 'In Production', 0);
    insertFixedInfoForSTAY(4, 20, 'At Customer', 0);
    insertFixedInfoForSTAY(5, 10, 'Inscan/in laundry', 0);
    insertFixedInfoForSTAY(5, 15, 'Inscan/Returned from Sub Contractor', 0);
    insertFixedInfoForSTAY(5, 20, 'Outscan/at customer', 0);
    insertFixedInfoForSTAY(5, 25, '(Send to) Sub Contractor', 0);
    insertFixedInfoForSTAY(5, 30, 'Checkpoint', 0);
    insertFixedInfoForSTAY(5, 40, 'Repair', 0);
    insertFixedInfoForSTAY(5, 50, 'Rewash', 0);
    insertFixedInfoForSTAY(5, 55, 'Infectious Wash', 0);
    insertFixedInfoForSTAY(5, 60, 'In Laundry/delayed', 0);
    insertFixedInfoForSTAY(5, 65, 'Wrongly received', 0);
    insertFixedInfoForSTAY(5, 70, 'In Laundry/ready for delivery', 0);
    insertFixedInfoForSTAY(5, 90, 'Not scanned (Label)', 0);
    insertFixedInfoForSTAY(6, 10, 'New (not scanned)', 0);
    insertFixedInfoForSTAY(6, 20, 'Scanned at conveyor belt', 0);
    insertFixedInfoForSTAY(6, 30, 'Received at shipping', 0);
    insertFixedInfoForSTAY(6, 40, 'Delivered at customer', 0);
    insertFixedInfoForSTAY(6, 50, 'Picked up at customer', 0);
    insertFixedInfoForSTAY(6, 60, 'Unloaded from truck', 0);
    insertFixedInfoForSTAY(6, 70, 'Soil sorted', 0);
    insertFixedInfoForSTAY(7, 10, 'Scanned in / In Laundry', 0);
    insertFixedInfoForSTAY(7, 20, 'Scanned out / At Customer', 0);
    insertFixedInfoForSTAY(7, 30, 'Repair', 0);
    insertFixedInfoForSTAY(7, 40, 'Rewash', 0);
    insertFixedInfoForSTAY(2, 11, 'Manual Count (Exchange Cart)', 0);
    insertFixedInfoForSTAY(2, 42, 'Packing (Exchange Cart)', 0);
    insertFixedInfoForSTAY(2, 51, 'Packing (Production Zone)', 0);
    insertFixedInfoForSTAY(2, 53, 'Packed (Production Zone)', 0);
    insertFixedInfoForSTAY(2, 55, 'Buffer Zone', 0);
    insertFixedInfoForSTAY(2, 70, 'Expedition Zone', 0);
    insertFixedInfoForSTAY(4, 30, 'In Buffer', 0);
    insert into stay_desc
      (stay_id, language_id, description, systemuser_id, timestamp)
      select s.stay_id, l.language_id, s.factorydescription, systemUserID, sysdate
        from stay s, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from stay_desc sd
               where sd.stay_id = s.stay_id
                 and sd.language_id = l.language_id);
    commit;
  exception
    when others then
      rollback;
      write_log('Error at STAY: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSTAY;
  procedure insertFixedInfoForTRANSACTIONTYPE(fp_transactiontype_id transactiontype.transactiontype_id%type,
                                              fp_factorydescription transactiontype.factorydescription%type) is
    lv_factorydescription transactiontype.factorydescription%type;
  begin
    select t.factorydescription
      into lv_factorydescription
      from transactiontype t
     where t.transactiontype_id = fp_transactiontype_id;
    if (lv_factorydescription <> fp_factorydescription) then
      update transactiontype t
         set t.factorydescription = fp_factorydescription, t.systemuser_id = systemUserID, t.timestamp = sysdate
       where t.transactiontype_id = fp_transactiontype_id;
    end if;
  exception
    when no_data_found then
      insert into transactiontype
        (transactiontype_id, factorydescription, systemuser_id, timestamp)
      values
        (fp_transactiontype_id, fp_factorydescription, systemUserID, sysdate);
  end insertFixedInfoForTRANSACTIONTYPE;

  procedure fixedInfoForTRANSACTIONTYPE is
  begin
    insertFixedInfoForTRANSACTIONTYPE(0, 'Scan Cancelled');
    insertFixedInfoForTRANSACTIONTYPE(1, 'In Scan');
    insertFixedInfoForTRANSACTIONTYPE(2, 'Out Scan');
    insertFixedInfoForTRANSACTIONTYPE(3, 'Repair Scan');
    insertFixedInfoForTRANSACTIONTYPE(4, 'Rewash Scan');
    insertFixedInfoForTRANSACTIONTYPE(5, 'Late Piece Scan');
    insertFixedInfoForTRANSACTIONTYPE(6, 'Checkpoint Scan');
    insertFixedInfoForTRANSACTIONTYPE(7, 'Storage Scan');
    insertFixedInfoForTRANSACTIONTYPE(8, 'Outscan (from active stock)');
    insertFixedInfoForTRANSACTIONTYPE(9, 'Outscan (bulk put up per route)');
    insertFixedInfoForTRANSACTIONTYPE(10, 'Put On Stock New');
    insertFixedInfoForTRANSACTIONTYPE(11, 'Record On Stock');
    insertFixedInfoForTRANSACTIONTYPE(12, 'Receive in Stock from Purchase Order');
    insertFixedInfoForTRANSACTIONTYPE(13, 'Undo rag / Put on stock ragged item');
    insertFixedInfoForTRANSACTIONTYPE(14, 'Rejected from Customer Scan');
    insertFixedInfoForTRANSACTIONTYPE(15, 'Return to Stock');
    insertFixedInfoForTRANSACTIONTYPE(16, 'Return to Stock (Assigned)');
    insertFixedInfoForTRANSACTIONTYPE(17, 'Image Capture');
    insertFixedInfoForTRANSACTIONTYPE(18, 'Return to stock (Returned by customer)');
    insertFixedInfoForTRANSACTIONTYPE(19, 'Production Process Scan');
    insertFixedInfoForTRANSACTIONTYPE(20, 'In Circ via Direct Issue with WO');
    insertFixedInfoForTRANSACTIONTYPE(21, 'In Circ via Direct Issue without WO');
    insertFixedInfoForTRANSACTIONTYPE(22, 'In Circ via Issue from Stock with WO');
    insertFixedInfoForTRANSACTIONTYPE(23, 'In Circ via Issue from Stock without WO');
    insertFixedInfoForTRANSACTIONTYPE(24, 'In Circ by Delivery Assigned Item');
    insertFixedInfoForTRANSACTIONTYPE(25, 'In Circ by Start Date Assigned Item');
    insertFixedInfoForTRANSACTIONTYPE(26, 'In Circ by Record In Use of Assigned Itm');
    insertFixedInfoForTRANSACTIONTYPE(27, 'In Circ by re-issuing ragged item');
    insertFixedInfoForTRANSACTIONTYPE(28, 'In Circ by Garment Dispenser');
    insertFixedInfoForTRANSACTIONTYPE(29, 'In Circ via InScan make cust owned item');
    insertFixedInfoForTRANSACTIONTYPE(30, 'Assigned via Direct Issue with WO');
    insertFixedInfoForTRANSACTIONTYPE(31, 'Assigned via Direct Issue without WO');
    insertFixedInfoForTRANSACTIONTYPE(32, 'Assigned via Issue from Stock with WO');
    insertFixedInfoForTRANSACTIONTYPE(33, 'Assigned via Issue from Stock without WO');
    insertFixedInfoForTRANSACTIONTYPE(34, 'Assign Product');
    insertFixedInfoForTRANSACTIONTYPE(35, 'Property Start Rent changed by Del Note');
    insertFixedInfoForTRANSACTIONTYPE(36, 'Assign and In Circ Via Stack Check');
    insertFixedInfoForTRANSACTIONTYPE(37, 'In Circ via Bundle Sort Scan');
    insertFixedInfoForTRANSACTIONTYPE(38, 'Stockroom Shipping Scan');
    insertFixedInfoForTRANSACTIONTYPE(39, 'Unattended secondary inscan workspot');
    insertFixedInfoForTRANSACTIONTYPE(40, 'Ragged from Stock');
    insertFixedInfoForTRANSACTIONTYPE(41, 'Ragged from Stock via Batch Rag');
    insertFixedInfoForTRANSACTIONTYPE(42, 'Ragged while In Circ.');
    insertFixedInfoForTRANSACTIONTYPE(43, 'Ragged while In Circ. via Batch Rag');
    insertFixedInfoForTRANSACTIONTYPE(44, 'Ragged via Stock Correction');
    insertFixedInfoForTRANSACTIONTYPE(45, 'Rag by Garment Dispenser');
    insertFixedInfoForTRANSACTIONTYPE(47, 'Ragged while in circ., returned from customer');
    insertFixedInfoForTRANSACTIONTYPE(48, 'Ragged while in circ., returned from customer via Rag in Batch');
    insertFixedInfoForTRANSACTIONTYPE(50, 'Sold from Stock');
    insertFixedInfoForTRANSACTIONTYPE(51, 'Sold while In Circulation');
    insertFixedInfoForTRANSACTIONTYPE(53, 'Undo Sales');
    insertFixedInfoForTRANSACTIONTYPE(54, 'Return to Supplier');
    insertFixedInfoForTRANSACTIONTYPE(55, 'Clean Return Scan');
    insertFixedInfoForTRANSACTIONTYPE(56, 'Season Scan');
    insertFixedInfoForTRANSACTIONTYPE(57, 'Send to Sub Contractor');
    insertFixedInfoForTRANSACTIONTYPE(58, 'Received from Sub Contractor');
    insertFixedInfoForTRANSACTIONTYPE(60, 'Sort Scan');
    insertFixedInfoForTRANSACTIONTYPE(61, 'Bundle Scan');
    insertFixedInfoForTRANSACTIONTYPE(62, 'Deposit Stock Scan');
    insertFixedInfoForTRANSACTIONTYPE(63, 'Quality Test Scan');
    insertFixedInfoForTRANSACTIONTYPE(64, 'Assemble pack scan');
    insertFixedInfoForTRANSACTIONTYPE(65, 'Stock Inventory Scan');
    insertFixedInfoForTRANSACTIONTYPE(66, 'Infectious scan');
    insertFixedInfoForTRANSACTIONTYPE(67, 'Wrong received scan');
    insertFixedInfoForTRANSACTIONTYPE(68, 'Send to Laundry');
    insertFixedInfoForTRANSACTIONTYPE(69, 'Received at Customer');
    insertFixedInfoForTRANSACTIONTYPE(70, 'Clean in Garment Dispenser');
    insertFixedInfoForTRANSACTIONTYPE(71, 'Desk Scan/Issue to Wearer');
    insertFixedInfoForTRANSACTIONTYPE(72, 'Out of Garment Dispenser');
    insertFixedInfoForTRANSACTIONTYPE(73, 'Soiled in Garment Dispenser');
    insertFixedInfoForTRANSACTIONTYPE(74, 'Stock Count Scan');
    insertFixedInfoForTRANSACTIONTYPE(75, 'Onsite soil scan (PDA)');
    insertFixedInfoForTRANSACTIONTYPE(76, 'On-site Inventory Scan');
    insertFixedInfoForTRANSACTIONTYPE(77, 'Changed to Customer related');
    insertFixedInfoForTRANSACTIONTYPE(78, 'Changed to Bill to Customer related');
    insertFixedInfoForTRANSACTIONTYPE(79, 'Changed to Master Account related');
    insertFixedInfoForTRANSACTIONTYPE(80, 'Item Properties Changed');
    insertFixedInfoForTRANSACTIONTYPE(81, 'Product Changed');
    insertFixedInfoForTRANSACTIONTYPE(82, 'Size Changed');
    insertFixedInfoForTRANSACTIONTYPE(83, 'Move Wearer');
    insertFixedInfoForTRANSACTIONTYPE(84, 'Stock Correction');
    insertFixedInfoForTRANSACTIONTYPE(85, 'Changed to customer owned');
    insertFixedInfoForTRANSACTIONTYPE(86, 'Changed to laundry owned');
    insertFixedInfoForTRANSACTIONTYPE(87, 'Inventory move');
    insertFixedInfoForTRANSACTIONTYPE(88, 'Move garment to another customer');
    insertFixedInfoForTRANSACTIONTYPE(89, 'Move garment back to original customer');
    insertFixedInfoForTRANSACTIONTYPE(90, 'Replaced ID Code (old)');
    insertFixedInfoForTRANSACTIONTYPE(91, 'Replacement ID Code (new)');
    insertFixedInfoForTRANSACTIONTYPE(92, 'Made Unique');
    insertFixedInfoForTRANSACTIONTYPE(93, 'Move Stock');
    insertFixedInfoForTRANSACTIONTYPE(94, 'Move Single Garment');
    insertFixedInfoForTRANSACTIONTYPE(95, 'Outscan via Outscan Work Order in Batch');
    insertFixedInfoForTRANSACTIONTYPE(96, 'Bundle Outscan');
    insertFixedInfoForTRANSACTIONTYPE(97, 'System Generated Outscan');
    insertFixedInfoForTRANSACTIONTYPE(98, 'Wrong BusinessUnit Scanned');
    insertFixedInfoForTRANSACTIONTYPE(99, 'Not Applicable');
    insertFixedInfoForTRANSACTIONTYPE(100, 'Flag Scan');
    insertFixedInfoForTRANSACTIONTYPE(102, 'Undo Stock Reception from PO');
    insertFixedInfoForTRANSACTIONTYPE(103, 'BPA Outscan via no scanner button');
    insertFixedInfoForTRANSACTIONTYPE(104, 'BPA Outscan via active stock location scan');
    insertFixedInfoForTRANSACTIONTYPE(105, 'Loaded on Mat Carry Unit');
    insertFixedInfoForTRANSACTIONTYPE(106, 'Unloaded from Mat Carry Unit');
    insertFixedInfoForTRANSACTIONTYPE(110, 'Placed in Locker');
    insertFixedInfoForTRANSACTIONTYPE(200, 'Confirm Loaded in Truck');
    insertFixedInfoForTRANSACTIONTYPE(201, 'Extra Mat Carry Unit');
    insertFixedInfoForTRANSACTIONTYPE(202, 'Unload from Truck');
    insertFixedInfoForTRANSACTIONTYPE(203, 'Mark Mat Carry Unit as Soil');
    insertFixedInfoForTRANSACTIONTYPE(204, 'Mark Mat Carry Unit as Clean');
    insertFixedInfoForTRANSACTIONTYPE(205, 'Returned (Route close)');
    insertFixedInfoForTRANSACTIONTYPE(400, 'Receive Used Items in Stock from PO');
    insertFixedInfoForTRANSACTIONTYPE(401, 'Put Used item in stock');
    insertFixedInfoForTRANSACTIONTYPE(402, 'Put Defect item in stock');
    insertFixedInfoForTRANSACTIONTYPE(403, 'Move Defect item to New stock');
    insertFixedInfoForTRANSACTIONTYPE(404, 'Move Defect item to Used stock');
    insertFixedInfoForTRANSACTIONTYPE(405, 'Move New item to Truck stock');
    insertFixedInfoForTRANSACTIONTYPE(406, 'Move Used Item To Truck Stock');
    insertFixedInfoForTRANSACTIONTYPE(407, 'Move New item to Blocked stock');
    insertFixedInfoForTRANSACTIONTYPE(408, 'Move Defect item to Blocked stock');
    insertFixedInfoForTRANSACTIONTYPE(409, 'Transit-Out via Issue of SDO');
    insertFixedInfoForTRANSACTIONTYPE(410, 'Register Picking Items From Stock');
    insertFixedInfoForTRANSACTIONTYPE(411, 'Transit-In via internal PO');
    insertFixedInfoForTRANSACTIONTYPE(412, 'Undo Pick and Return to Stock');
    insertFixedInfoForTRANSACTIONTYPE(413, 'Stockroom Scan');
    insertFixedInfoForTRANSACTIONTYPE(414, 'Add To Truck Stock (Correction)');
    insertFixedInfoForTRANSACTIONTYPE(415, 'Move New Item From Truck Stock');
    insertFixedInfoForTRANSACTIONTYPE(416, 'Move Used Item From Truck Stock');
    insertFixedInfoForTRANSACTIONTYPE(417, 'Transit-Out via Shipment List');
    insertFixedInfoForTRANSACTIONTYPE(418, 'Transit-In via Shipment List');
    insertFixedInfoForTRANSACTIONTYPE(419, 'Emblems TRANSIT Stock via ShipmentList');
    insertFixedInfoForTRANSACTIONTYPE(422, 'In Circ Via Issue From Truck Stock (WO)');
    insertFixedInfoForTRANSACTIONTYPE(423, 'In Circ Via Issue From Truck Stock (MO)');
    insertFixedInfoForTRANSACTIONTYPE(424, 'In Circ Via Issue From Truck Stock (PN)');
    insertFixedInfoForTRANSACTIONTYPE(444, 'Ragged From Truck Stock (Correction)');
    insertFixedInfoForTRANSACTIONTYPE(450, 'Sold From Truck Stock');
    insertFixedInfoForTRANSACTIONTYPE(453, 'Sold From Truck Stock With MO');
    insertFixedInfoForTRANSACTIONTYPE(454, 'Sold From Truck Stock With PN');
    insertFixedInfoForTRANSACTIONTYPE(490, 'Stock value change');
    insertFixedInfoForTRANSACTIONTYPE(493, 'Move Truck Stock(From Truck To Truck)');
    insertFixedInfoForTRANSACTIONTYPE(510, 'In Scan via Soil Weighing');
    insertFixedInfoForTRANSACTIONTYPE(511, 'In Scan Empty');
    insertFixedInfoForTRANSACTIONTYPE(512, 'In Scan Empty + Tare Check');
    insertFixedInfoForTRANSACTIONTYPE(514, 'In scan Clean Return (Exchange Cart)');
    insertFixedInfoForTRANSACTIONTYPE(515, 'In Scan via Item Dispense App');
    insertFixedInfoForTRANSACTIONTYPE(520, 'Disinfection Scan');
    insertFixedInfoForTRANSACTIONTYPE(521, 'Clean Count (Exchange Cart)');
    insertFixedInfoForTRANSACTIONTYPE(530, 'OR Load');
    insertFixedInfoForTRANSACTIONTYPE(531, 'OR Sterilize');
    insertFixedInfoForTRANSACTIONTYPE(532, 'Start Filling (Exchange Cart)');
    insertFixedInfoForTRANSACTIONTYPE(533, 'Put on Hold (Exchange Cart)');
    insertFixedInfoForTRANSACTIONTYPE(534, 'Release (Exchange Cart)');
    insertFixedInfoForTRANSACTIONTYPE(540, 'Out Scan via Delivery Note');
    insertFixedInfoForTRANSACTIONTYPE(541, 'Out Scan via Clean Weighing');
    insertFixedInfoForTRANSACTIONTYPE(542, 'Out Scan Empty');
    insertFixedInfoForTRANSACTIONTYPE(543, 'Out Scan Empty + Tare Check');
    insertFixedInfoForTRANSACTIONTYPE(545, 'Outscan / Shipping');
    insertFixedInfoForTRANSACTIONTYPE(546, 'On-Site Delivery Scan');
    insertFixedInfoForTRANSACTIONTYPE(547, 'Pick Up at Customer');
    insertFixedInfoForTRANSACTIONTYPE(548, 'Receive from Laundry');
    insertFixedInfoForTRANSACTIONTYPE(549, 'Send to Laundry');
    insertFixedInfoForTRANSACTIONTYPE(550, 'Create Container');
    insertFixedInfoForTRANSACTIONTYPE(551, 'Exchange Cart');
    insertFixedInfoForTRANSACTIONTYPE(552, 'Container Repair');
    insertFixedInfoForTRANSACTIONTYPE(553, 'Start Packing Container (Production Zone)');
    insertFixedInfoForTRANSACTIONTYPE(554, 'Finished Packing Container (Production Zone)');
    insertFixedInfoForTRANSACTIONTYPE(555, 'Move Container to Buffer Zone');
    insertFixedInfoForTRANSACTIONTYPE(556, 'Move Container to Expedition Zone');
    insertFixedInfoForTRANSACTIONTYPE(560, 'Inactivate Container');
    insertFixedInfoForTRANSACTIONTYPE(570, 'Mark as Mat Transport Unit');
    insertFixedInfoForTRANSACTIONTYPE(571, 'Unmark as Mat Transport Unit');
    insertFixedInfoForTRANSACTIONTYPE(572, 'Put item on Mat Transport Unit');
    insertFixedInfoForTRANSACTIONTYPE(573, 'Remove item from Mat Transport Unit');
    insertFixedInfoForTRANSACTIONTYPE(574, 'Remove All from Mat Transport Unit');
    insertFixedInfoForTRANSACTIONTYPE(575, 'Merge Mat Transport Unit');
    insertFixedInfoForTRANSACTIONTYPE(576, 'Put on Sort Position');
    insertFixedInfoForTRANSACTIONTYPE(577, 'Scan on Mat Shipment List');
    insertFixedInfoForTRANSACTIONTYPE(578, 'Undo scan on Mat Shipment List');
    insertFixedInfoForTRANSACTIONTYPE(579, 'Receive Mat Shipment List');
    insertFixedInfoForTRANSACTIONTYPE(580, 'Change Container Properties');
    insertFixedInfoForTRANSACTIONTYPE(581, 'Undo Receive Mat Shipment List');
    insertFixedInfoForTRANSACTIONTYPE(582, 'Pack container via Bulk Packing Assistant');
    insertFixedInfoForTRANSACTIONTYPE(590, 'Replace ID Code (old)');
    insertFixedInfoForTRANSACTIONTYPE(591, 'Replacement ID Code (new)');
    insertFixedInfoForTRANSACTIONTYPE(600, 'Generate OR Pack label');
    insertFixedInfoForTRANSACTIONTYPE(610, 'Assemble pack');
    insertFixedInfoForTRANSACTIONTYPE(612, 'Quick Load');
    insertFixedInfoForTRANSACTIONTYPE(615, 'Assemble + load pack');
    insertFixedInfoForTRANSACTIONTYPE(620, 'Load pack');
    insertFixedInfoForTRANSACTIONTYPE(621, 'Cleanroom Charge Scan');
    insertFixedInfoForTRANSACTIONTYPE(630, 'Sterilization - Approved');
    insertFixedInfoForTRANSACTIONTYPE(631, 'Sterilization - Rejected');
    insertFixedInfoForTRANSACTIONTYPE(632, 'Sterilization - Rejected + cancel');
    insertFixedInfoForTRANSACTIONTYPE(633, 'Sterilization - Rejected + unload');
    insertFixedInfoForTRANSACTIONTYPE(634, 'Clean Room Batch Reject');
    insertFixedInfoForTRANSACTIONTYPE(640, 'Outscan on delivery note');
    insertFixedInfoForTRANSACTIONTYPE(645, 'Delivery note cancelled');
    insertFixedInfoForTRANSACTIONTYPE(650, 'Used scan');
    insertFixedInfoForTRANSACTIONTYPE(660, 'Cancel pack');
    insertFixedInfoForTRANSACTIONTYPE(670, 'Recall pack');
    insertFixedInfoForTRANSACTIONTYPE(700, 'Created new');
    insertFixedInfoForTRANSACTIONTYPE(701, 'Modify');
    insertFixedInfoForTRANSACTIONTYPE(702, 'Conversion');
    insertFixedInfoForTRANSACTIONTYPE(703, 'Approved');
    insertFixedInfoForTRANSACTIONTYPE(704, 'Contract termination');
    insertFixedInfoForTRANSACTIONTYPE(705, 'Contract extension');
    insertFixedInfoForTRANSACTIONTYPE(706, 'Contract renewal');
    insertFixedInfoForTRANSACTIONTYPE(707, 'Price update');
    insertFixedInfoForTRANSACTIONTYPE(850, 'Top-up delivery');
    insertFixedInfoForTRANSACTIONTYPE(851, 'Installation');
    insertFixedInfoForTRANSACTIONTYPE(852, 'Modification');
    insertFixedInfoForTRANSACTIONTYPE(853, 'Deletion');
    insertFixedInfoForTRANSACTIONTYPE(854, 'Confirmation of Removal');
    insertFixedInfoForTRANSACTIONTYPE(855, 'Service Scan');
    insertFixedInfoForTRANSACTIONTYPE(856, 'Service Delivery');
    insertFixedInfoForTRANSACTIONTYPE(857, 'Service no scan - damaged barcode');
    insertFixedInfoForTRANSACTIONTYPE(858, 'Service no scan - no access');
    insertFixedInfoForTRANSACTIONTYPE(1000, 'Check-in new items');
    insertFixedInfoForTRANSACTIONTYPE(1001, 'Check-in used items');
    insertFixedInfoForTRANSACTIONTYPE(1005, 'Correct checked-in new items');
    insertFixedInfoForTRANSACTIONTYPE(1006, 'Correct checked-in used items');
    insertFixedInfoForTRANSACTIONTYPE(1010, 'Make checked-in new items unique');
    insertFixedInfoForTRANSACTIONTYPE(1011, 'Make checked-in used items unique');
    insertFixedInfoForTRANSACTIONTYPE(1015, 'Undo make checked-in new items unique');
    insertFixedInfoForTRANSACTIONTYPE(1016, 'Undo make checked-in used items unique');
    insertFixedInfoForTRANSACTIONTYPE(1020, 'Put away checked-in new items');
    insertFixedInfoForTRANSACTIONTYPE(1021, 'Put away checked-in used items');
    insertFixedInfoForTRANSACTIONTYPE(1025, 'Issue WO from checked-in new items');
    insertFixedInfoForTRANSACTIONTYPE(1026, 'Issue WO from checked-in used items');
    insertFixedInfoForTRANSACTIONTYPE(1030, 'Correct received new items from SDO Push');
    insertFixedInfoForTRANSACTIONTYPE(1031, 'Correct received used items from SDO Push');
    insertFixedInfoForTRANSACTIONTYPE(1032, 'Correct received defect items from SDO Push');
    insertFixedInfoForTRANSACTIONTYPE(1033, 'Cancel expected items from SDO Push');
    insertFixedInfoForTRANSACTIONTYPE(1034, 'Loaded into truck');
    insertFixedInfoForTRANSACTIONTYPE(1035, 'Merge container');
    insertFixedInfoForTRANSACTIONTYPE(1036, 'Unloaded from Truck');
    insert into transactiontype_desc
      (transactiontype_id, language_id, description, systemuser_id, timestamp)
      select t.transactiontype_id, l.language_id, t.factorydescription, systemUserID, sysdate
        from transactiontype t, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from transactiontype_desc td
               where td.transactiontype_id = t.transactiontype_id
                 and td.language_id = l.language_id);
    commit;
  exception
    when others then
      rollback;
      write_log('Error at TRANSACTIONTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForTRANSACTIONTYPE;
  procedure insertFixedInfoForRESPONSECODETRANSLATION(fp_responsecode responsecodetranslation.responsecode%type,
                                                      fp_description  responsecodetranslation.description%type,
                                                      fp_remark       responsecodetranslation.remark%type) is
    lv_description responsecodetranslation.description%type;
    lv_remark      responsecodetranslation.remark%type;
  begin
    select r.description, r.remark
      into lv_description, lv_remark
      from responsecodetranslation r
     where r.responsecode = fp_responsecode;
    if (lv_description <> fp_description) then
      update responsecodetranslation r
         set r.description = fp_description, r.systemuser_id = systemUserID, r.timestamp = sysdate
         where r.responsecode = fp_responsecode;
    end if;
    if (lv_remark <> fp_remark) then
      update responsecodetranslation r
         set r.remark = fp_remark, r.systemuser_id = systemUserID, r.timestamp = sysdate
         where r.responsecode = fp_responsecode;
    end if;
  exception
    when no_data_found then
      insert into responsecodetranslation
        (responsecode, description, remark, systemuser_id, timestamp)
      values
        (fp_responsecode, fp_description, fp_remark, systemUserID, sysdate);
  end insertFixedInfoForRESPONSECODETRANSLATION;

  procedure fixedInfoForRESPONSECODETRANSLATION is
  begin
    insertFixedInfoForRESPONSECODETRANSLATION(100, 'Approved ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(101,
                                              'One or more required fields missing from the request ',
                                              'Consult the missingFields entry in the reply ');
    insertFixedInfoForRESPONSECODETRANSLATION(102,
                                              'One or more fields in the request contain invalid data ',
                                              'Consult the invalidFields entry in the reply ');
    insertFixedInfoForRESPONSECODETRANSLATION(103, 'An invalid combination of services was requested ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(104, 'Duplicate transaction ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(111, 'One or more fields contains invalid data ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(112, 'One or more required fields missing ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(149,
                                              'Issue occurred processing request. Unknown error ',
                                              'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(150,
                                              'Issue occurred processing request. Application error ',
                                              'A fatal error occurred while processing the request. Do not retry the transaction. Contact Freedompay immediately. ');
    insertFixedInfoForRESPONSECODETRANSLATION(151,
                                              'An internal timeout occurred while processing the request ',
                                              'Try again ');
    insertFixedInfoForRESPONSECODETRANSLATION(152,
                                              'An internal error occurred while communicating with the card processor ',
                                              'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(153, 'Unable to communicate with card processor Try again ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(154,
                                              'Invalid card processor configuration Contact Freedompay immediately ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(155, 'Internal communication failure Try again ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(161, 'Business date required ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(162, 'Business Date is earlier than the most recent date ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(201, 'Call issuing bank for authorization ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(202,
                                              'Expired card (or mismatched expiry date provided) Obtain an updated card ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(203, 'Declined by issuing bank - unspecified reason ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(204,
                                              'Insufficient funds Some issuers return this for over-limit credit cards ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(205, 'Lost or stolen card ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(206, 'Stolen card ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(207, 'Issuing bank unavailable to authorize request ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(208, 'The card is not active or not eligible for ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(209,
                                              'Incorrect PIN ',
                                              'Some issuers return this if the number of failed PIN attempts is exceeded ');
    insertFixedInfoForRESPONSECODETRANSLATION(210, 'Card over limit ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(211, 'Incorrect card verification number (CVC/CVV2/CID) ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(212, 'Invalid PIN Data ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(213, 'Card not valid at this location ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(214, 'Invalid Track Data ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(215,
                                              'Invalid amount (gift cards only) ',
                                              'For cashout, may indicate that the balance is too high to be cashed out. For other transactions, may indicate that the requested amount is not allowed. ');
    insertFixedInfoForRESPONSECODETRANSLATION(216,
                                              'Revert to contact ',
                                              'Issuer requests that the customer insert their card (and not tap) ');
    insertFixedInfoForRESPONSECODETRANSLATION(220,
                                              'Issuing bank rejected the transaction due to generic account problem ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(221, 'Suspected fraud ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(222, 'Account is frozen ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(229, 'Merchant Configuration error ', 'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(231, 'Invalid account number ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(232,
                                              'Card Type not enabled for merchant ',
                                              'Contact FreedomPay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(233,
                                              'Processor rejected the transaction due to an issue with the request ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(234, 'Invalid merchant credentials ', 'Contact FreedomPay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(235,
                                              'Return amount exceeds the amount of original authorization ',
                                              'Currently applicable to stored value cards only ');
    insertFixedInfoForRESPONSECODETRANSLATION(236,
                                              'Processor reported an error while attempting to process the request ',
                                              'Try again ');
    insertFixedInfoForRESPONSECODETRANSLATION(237,
                                              'Processor reported an error while attempting to process the request ',
                                              'Contact FreedomPay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(238, 'The authorization has already been captured ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(239,
                                              'The capture amount was for more than the authorization amount ',
                                              'Capture amount > Auth amount is not necessarily an error. This is returned when it is. ');
    insertFixedInfoForRESPONSECODETRANSLATION(241, 'Invalid Request ID ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(242, 'No un-captured authorization record was found ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(243, 'The transaction is already settled ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(245,
                                              'The transaction contains both card data and an orderRequestID, but the card data does not match that from the original transcation ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(246, 'The transaction cannot be voided ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(247, 'The transaction has already been voided ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(248, 'The authorization for this transaction is no longer valid ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(249,
                                              'Unable to reverse off authorization No action required ',
                                              q'[The transaction has been removed from the batch (so it won't settle) ]');
    insertFixedInfoForRESPONSECODETRANSLATION(250,
                                              'A timeout occurred while waiting for a response from the processor ',
                                              'Try again ');
    insertFixedInfoForRESPONSECODETRANSLATION(251,
                                              'Processor or issuing bank does not support this transaction ',
                                              'EMV transactions that are processed with an AID that is not valid for the card type (debit vs credit) will return this code. ');
    insertFixedInfoForRESPONSECODETRANSLATION(252, 'The processor is not available ', 'Try again ');
    insertFixedInfoForRESPONSECODETRANSLATION(253, 'Merchant is not allowed to perform this transaction ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(254, 'Process rejected transaction, invalid data ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(261, 'Track Data decryption error ', 'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(262, 'Device Not Supported ', 'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(263,
                                              'Encryption Mode Not Supported ',
                                              'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(264, 'Key set not registered ', 'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(265,
                                              'Internal error while decrypting ',
                                              'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(266, 'P2PE encryption required ', 'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(271, 'Invalid or inactive moniker ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(281, 'Private Label account bankrupt ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(282, 'Private Label account closed ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(284, 'Private Label card is revoked ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(285, 'Private Label card is charged off ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(286, 'Unbalanced tax details (private label only) ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(287, 'AVS/CVN Validation code not whitelisted ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(288, 'Rejected due to fraud checking ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(300,
                                              'An error occurred in communicating with the Promotion Engine ',
                                              'Try again ');
    insertFixedInfoForRESPONSECODETRANSLATION(301,
                                              'The submitted transaction contains more than one promotion, but the remote system supports only one promotion code per transaction ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(302, 'The invoice would have zero value ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(310,
                                              'Requested promotion(s) failed validation. ',
                                              'Check requirements for the promotion ');
    insertFixedInfoForRESPONSECODETRANSLATION(311, 'The available window for this promotion has expired ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(312,
                                              'This card is not eligible for this promotion ',
                                              'Check requirements for the promotion ');
    insertFixedInfoForRESPONSECODETRANSLATION(313,
                                              'This merchant is not eligible for this promotion ',
                                              'Check requirements for the promotion ');
    insertFixedInfoForRESPONSECODETRANSLATION(314,
                                              'The promotion is not valid at this time ',
                                              'Check requirements for the promotion ');
    insertFixedInfoForRESPONSECODETRANSLATION(315,
                                              'The scenario code specified for this promotion was not valid ',
                                              'Check requirements for the promotion ');
    insertFixedInfoForRESPONSECODETRANSLATION(316,
                                              'The merchant has not opted-in for the promotion ',
                                              'Check requirements for the promotion ');
    insertFixedInfoForRESPONSECODETRANSLATION(317,
                                              'The promotion engine found different available promotions than the one specified ',
                                              'Returned only for lookups ');
    insertFixedInfoForRESPONSECODETRANSLATION(320,
                                              'The merchant is not correctly configured for discounts (Program not found) ',
                                              'Indicates a configuration error in Freeway ');
    insertFixedInfoForRESPONSECODETRANSLATION(322, 'This card is not eligible for any terms promotions ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(323, 'This merchant is not registered for this program ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(324, 'The entered promotion was not found ', '(Validates only)');
    insertFixedInfoForRESPONSECODETRANSLATION(330,
                                              'The invoice did not satisfy the rules of the promotion requested ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(335,
                                              'The qualifying subtotal is not within the purchase amount bounds of this promotion ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(336,
                                              'The qualifying quantity is not within the amount bounds of this promotion ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(337,
                                              'The eligible subtotal is not within the purchase amount bounds of this promotion ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(338,
                                              'The qualifying subtotal is not within the percentage purchase amount bounds of this promotion ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(339,
                                              'The invoice amount is not within the purchase amount bounds of this promotion ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(340,
                                              'No products on the invoice qualify for the promotion requested ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(341, 'The product does not qualify for the promotion requested ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(342, 'The product does not qualify for the promotion requested ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(343, 'The product does not qualify for the promotion requested ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(344, 'The sale code did not apply for the promotion requested ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(345,
                                              'The unit price submitted was either too high or too low for the promotion requested ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(346,
                                              'The quantity submitted was either too high or too low for the promotion requested ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(347,
                                              'The subtotal submitted was either too high or too low for the promotion requested ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(348,
                                              'The non-qualifying items exceeded the threshold amount allowed by this promotion ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(401,
                                              'Try again later Error retrieving payment information from Token service Try again later ',
                                              'Try again later ');
    insertFixedInfoForRESPONSECODETRANSLATION(402, 'Expired token (mobile only) ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(408, 'Disabled token (mobile only) ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(410, 'Token over limit (mobile only) ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(431, 'Invalid token ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(451, 'Unsupported request ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(491,
                                              'Type of card backed by token does not match the type of card sent to Freway ',
                                              null);
    insertFixedInfoForRESPONSECODETRANSLATION(501, 'MuleSoft Returned Error', 'Consult with the MuleSoft team');
    insertFixedInfoForRESPONSECODETRANSLATION(701,
                                              'Successful retrieval of DCC Information Card is eligible ',
                                              'Ask if customer wants to use DCC rates ');
    insertFixedInfoForRESPONSECODETRANSLATION(702, 'Card is not eligible for DCC ', null);
    insertFixedInfoForRESPONSECODETRANSLATION(703, 'Invalid DCC Credentials ', 'Contact Freedompay immediately ');
    insertFixedInfoForRESPONSECODETRANSLATION(999, 'MuleSoft Error', 'Contact UniFirst IT');
    commit;
  exception
    when others then
      rollback;
      write_log('Error at RESPONSECODETRANSLATION: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForRESPONSECODETRANSLATION;
  procedure insertFixedInfoForSPECIALSCANS(fp_specialscans_id    specialscans.specialscans_id%type,
                                           fp_transactiontype_id specialscans.transactiontype_id%type,
                                           fp_staytype           stay.staytype%type,
                                           fp_staynr             stay.staynr%type) is
  begin
    select sp.specialscans_id
      into id
      from specialscans sp
     where sp.specialscans_id = fp_specialscans_id;
  exception
    when no_data_found then
      insert into specialscans sp
        (specialscans_id, transactiontype_id, stay_id, systemuser_id, timestamp)
      values
        (fp_specialscans_id, fp_transactiontype_id,
         (select s.stay_id
             from stay s
            where s.staytype = fp_staytype
              and s.staynr = fp_staynr), systemUserID, sysdate);
  end insertFixedInfoForSPECIALSCANS;
  procedure fixedInfoForSPECIALSCANS is
  begin
    insertFixedInfoForSPECIALSCANS(1, 6, 5, 30);
    insertFixedInfoForSPECIALSCANS(2, 5, 5, 70);
    insertFixedInfoForSPECIALSCANS(3, 4, 5, 50);
    insertFixedInfoForSPECIALSCANS(4, 66, 5, 55);
    insertFixedInfoForSPECIALSCANS(5, 67, 5, 65);
    insertFixedInfoForSPECIALSCANS(6, 57, 5, 25);
    insertFixedInfoForSPECIALSCANS(7, 58, 5, 15);
    commit;
  exception
    when others then
      rollback;
      write_log('Error at SPECIALSCANS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSPECIALSCANS;
  procedure insertFixedInfoForSOUNDCONFIGURATION(fp_categorydescription   soundconfiguration.categorydescription%type,
                                                 fp_eventdescription      soundconfiguration.eventdescription%type,
                                                 fp_sound_id              soundconfiguration.sound_id%type) is
  begin
    select s.soundconfiguration_id
    into id
    from soundconfiguration s
    where s.categorydescription = fp_categorydescription and s.eventdescription = fp_eventdescription;
  exception
    when no_data_found then
      insert into soundconfiguration
        (soundconfiguration_id, categorydescription, eventdescription, systemuser_id, timestamp, sound_id)
      values
        (seq_soundconfiguration.nextval, fp_categorydescription, fp_eventdescription, systemUserID, sysdate, fp_sound_id);
  end insertFixedInfoForSOUNDCONFIGURATION;
  procedure fixedInfoForSOUNDCONFIGURATION is
  begin
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Good Scan', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Error Scan', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Good Scan, Delivery from Stock', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Flag', null);
    insertFixedInfoForSOUNDCONFIGURATION('Messages', 'Information', null);
    insertFixedInfoForSOUNDCONFIGURATION('Messages', 'Error', null);
    insertFixedInfoForSOUNDCONFIGURATION('Messages', 'Warning', null);
    insertFixedInfoForSOUNDCONFIGURATION('Messages', 'Question', null);
    insertFixedInfoForSOUNDCONFIGURATION('Miscellaneous', 'Process Finished Successfully', null);
    insertFixedInfoForSOUNDCONFIGURATION('Miscellaneous', 'Process Finished with Error', null);
    insertFixedInfoForSOUNDCONFIGURATION('Miscellaneous', 'New Follow Up Action Request Notification', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Mat Type Changed', null);
    insertFixedInfoForSOUNDCONFIGURATION('Miscellaneous', 'Touchscreen Button Pressed', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Good Scan, Final Inspection', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Error Scan, Final Inspection', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Washing Process Change', null);
    insertFixedInfoForSOUNDCONFIGURATION('Miscellaneous', 'Right Rail Button Pressed', null);
    insertFixedInfoForSOUNDCONFIGURATION('Miscellaneous', 'Wrong Rail Button Pressed', null);
    insertFixedInfoForSOUNDCONFIGURATION('Scanning', 'Cleanroom Batch Buffer Scan', null);
    commit;
  exception
    when others then
      rollback;
      write_log('Error at SOUNDCONFIGURATION: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSOUNDCONFIGURATION;

  procedure insertFixedInfoForROUTETRANSACTIONCATEGORY(fp_routetransactioncategory_id routetransactioncategory.routetransactioncategory_id%type,
                                                       fp_factorydescription          routetransactioncategory.factorydescription%type,
                                                       fp_showtab_yn                  routetransactioncategory.showtab_yn%type) is

    lv_factorydescription          routetransactioncategory.factorydescription%type;
  begin
    select r.factorydescription
      into lv_factorydescription
      from routetransactioncategory r
     where r.routetransactioncategory_id = fp_routetransactioncategory_id;

    if(lv_factorydescription <> fp_factorydescription) then
      update routetransactioncategory r
        set r.factorydescription = fp_factorydescription, r.systemuser_id = systemUserID, r.timestamp = sysdate
        where r.routetransactioncategory_id = fp_routetransactioncategory_id;
    end if;
  exception
    when no_data_found then
      insert into routetransactioncategory
        (routetransactioncategory_id, factorydescription, showtab_yn, systemuser_id, timestamp)
      values
        (fp_routetransactioncategory_id, fp_factorydescription, fp_showtab_yn, systemUserID, sysdate);
  end insertFixedInfoForROUTETRANSACTIONCATEGORY;
  procedure fixedInfoForROUTETRANSACTIONCATEGORY is
  begin
    insertFixedInfoForROUTETRANSACTIONCATEGORY(0, 'No Tab', 'N');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(1, 'Invoice Adjustments', 'Y');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(2, 'Orders', 'Y');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(3, 'Proof of Visit Anomalies', 'N');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(4, 'Contract Adjustments', 'Y');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(5, 'Contact Messages', 'N');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(6, 'Deliver/Pickup Anomalies', 'N');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(7, 'Container Scans', 'N');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(8, 'Contact Persons', 'N');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(9, 'Garment Scans', 'Y');
    insertFixedInfoForROUTETRANSACTIONCATEGORY(10, 'Unique Item Service', 'Y');
    insert into routetransactioncategory_desc
      (routetransactioncategory_id, language_id, description, systemuser_id, timestamp)
      select rtc.routetransactioncategory_id, l.language_id, rtc.factorydescription, systemUserID, sysdate
        from routetransactioncategory rtc, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from routetransactioncategory_desc rd
               where rd.routetransactioncategory_id = rtc.routetransactioncategory_id
                 and rd.language_id = l.language_id);
   commit;
  exception
    when others then
      rollback;
      write_log('Error at ROUTETRANSACTIONCATEGORY: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForROUTETRANSACTIONCATEGORY;
  procedure insertFixedInfoForROUTETRANSACTIONTYPE(fp_routetransactiontype_id     routetransactiontype.routetransactiontype_id%type,
                                                   fp_factorydescription          routetransactiontype.factorydescription%type,
                                                   fp_allowmanualapproval_yn      routetransactiontype.allowmanualapproval_yn%type,
                                                   fp_approvemanually_yn          routetransactiontype.approvemanually_yn%type,
                                                   fp_routetransactioncategory_id routetransactiontype.routetransactioncategory_id%type) is
    lv_factorydescription routetransactiontype.factorydescription%type;
    lv_allowmanualapproval_yn      routetransactiontype.allowmanualapproval_yn%type;
  begin
    select r.factorydescription, r.allowmanualapproval_yn
      into lv_factorydescription, lv_allowmanualapproval_yn
      from routetransactiontype r
     where r.routetransactiontype_id = fp_routetransactiontype_id;
    if (lv_factorydescription <> fp_factorydescription) then
      update routetransactiontype r
         set r.factorydescription = fp_factorydescription, r.systemuser_id = systemUserID, r.timestamp = sysdate
       where r.routetransactiontype_id = fp_routetransactiontype_id;
    end if;
  exception
    when no_data_found then
      insert into routetransactiontype
        (routetransactiontype_id, factorydescription, allowmanualapproval_yn, approvemanually_yn,
         routetransactioncategory_id, systemuser_id, timestamp)
      values
        (fp_routetransactiontype_id, fp_factorydescription, fp_allowmanualapproval_yn, fp_approvemanually_yn,
         fp_routetransactioncategory_id, systemUserID, sysdate);
  end insertFixedInfoForROUTETRANSACTIONTYPE;
  procedure fixedInfoForROUTETRANSACTIONTYPE is
  begin
    insertFixedInfoForROUTETRANSACTIONTYPE(100, 'Start Route', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(101, 'End Route', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(102, 'Safety Check', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(103, 'Safety Remarks', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(200, 'Arrive at Stop', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(201, 'Depart from Stop', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(202, 'Undeliverable Stop', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(203, 'Move Stop Permanent', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(204, 'Add New Contact Message', 'N', 'N', 5);
    insertFixedInfoForROUTETRANSACTIONTYPE(205, 'Update Existing Contact Message', 'N', 'N', 5);
    insertFixedInfoForROUTETRANSACTIONTYPE(206, 'Proof of Visit Scan', 'N', 'N', 3);
    insertFixedInfoForROUTETRANSACTIONTYPE(207, 'Signature Capture', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(208, 'Move Stop Temporarily', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(209, 'Change GPS Coordinates', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(212, 'Unload (container) Scan', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(213, 'Return Container Scan', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(214, 'Add Contact Person', 'N', 'N', 8);
    insertFixedInfoForROUTETRANSACTIONTYPE(215, 'Edit Contact Person', 'N', 'N', 8);
    insertFixedInfoForROUTETRANSACTIONTYPE(216, 'Replace Contact Person', 'N', 'N', 8);
    insertFixedInfoForROUTETRANSACTIONTYPE(217, 'Combined Move Stop (Permanent and Temporarily)', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(220, 'Consumption Point Proof of Visit Scan', 'N', 'N', 3);
    insertFixedInfoForROUTETRANSACTIONTYPE(221, 'Add Delivery Point Image', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(222, 'Delete Delivery Point Image', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(300, 'Add Wearer', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(301, 'Quit Wearer', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(302, 'Add Product Existing Wearer', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(303, 'Quit Product Existing Wearer', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(304, 'Style Exchange', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(305, 'Size Exchange', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(306, 'Decrease Wearer Inventory', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(307, 'Increase Wearer Inventory', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(308, 'Decrease inventory', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(309, 'Increase inventory', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(310, 'One Time Order', 'Y', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(311, 'Modify Wearer', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(312, 'Replace Wearer Inventory', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(313, 'Replace Lost Items', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(350, 'Wearer Transfer', 'Y', 'Y', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(360, 'One Off Order', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(361, 'Order, deliver now, invoice later', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(362, 'Order, deliver now, signature', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(400, 'Change Delivered Qty', 'N', 'N', 6);
    insertFixedInfoForROUTETRANSACTIONTYPE(401, 'Pick Up Qty (SER)', 'N', 'N', 6);
    insertFixedInfoForROUTETRANSACTIONTYPE(402, 'Soil Count per Cons. Point', 'N', 'N', 6);
    insertFixedInfoForROUTETRANSACTIONTYPE(403, 'Soil Count per Soil Ticket', 'N', 'N', 6);
    insertFixedInfoForROUTETRANSACTIONTYPE(420, 'Confirm mat carry unit', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(421, 'Extra unit', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(422, 'Unload from truck', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(423, 'Deliver Mat from MCU', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(424, 'Receive Soil Mat on MCU', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(425, 'Mark Mat Carry Unit as Soil', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(426, 'Mark Mat Carry Unit as Clean', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(427, 'Change Mat Carry Unit to Regular Container', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(428, 'Change Regular Container to MCU', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(429, 'Missing mat carry units on route assistant', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(430, 'Load Clean Return Mat', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(431, 'Disconnected Mat', 'N', 'N', 7);
    insertFixedInfoForROUTETRANSACTIONTYPE(500, 'Add Product', 'Y', 'Y', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(501, 'Quit Product', 'Y', 'Y', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(502, 'Modify Quantity', 'N', 'N', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(503, 'Add Temporary Delivery Stop', 'N', 'N', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(504, 'Modify Product', 'Y', 'Y', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(505, 'Add delivery / collection', 'Y', 'Y', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(506, 'Quit delivery / collection day', 'Y', 'Y', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(507, 'Modify delivery / collection', 'Y', 'Y', 4);
    insertFixedInfoForROUTETRANSACTIONTYPE(600, 'On Site Soil Scan', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(601, 'Flag unique item', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(602, 'Mark for replacement', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(700, 'Settle Invoice', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(701, 'Minus Adjustment', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(702, 'Plus Adjustment', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(703, 'Loss Charge Invoice Line Adjustment', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(704, 'Returned Item Invoice Line Adjustment', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(705, 'Bill damage now Invoice Line Adjustment', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(706, 'Replace Loss Charge Invoice Line Adjustment', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(707, 'Full Invoice Credit', 'N', 'N', 1);
    insertFixedInfoForROUTETRANSACTIONTYPE(750, 'Email Statement', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(751, 'Email Invoice', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(752, 'Apply Payment', 'N', 'N', 0);
    insertFixedInfoForROUTETRANSACTIONTYPE(800, 'Scan Garment Place Flag', 'N', 'N', 9);
    insertFixedInfoForROUTETRANSACTIONTYPE(801, 'Scan Garment Replace', 'N', 'N', 9);
    insertFixedInfoForROUTETRANSACTIONTYPE(802, 'Scan Garment Rag', 'N', 'N', 9);
    insertFixedInfoForROUTETRANSACTIONTYPE(804, 'Scan Returned Item', 'N', 'N', 9);
    insertFixedInfoForROUTETRANSACTIONTYPE(805, 'Garment Scan Replace Overruled Grade', 'Y', 'Y', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(806, 'Scan Garment Damaged', 'N', 'N', 9);
    insertFixedInfoForROUTETRANSACTIONTYPE(807, 'Scan Garment Damaged Overruled Grade', 'Y', 'Y', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(850, 'TopUp order', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(851, 'Install', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(852, 'Modify', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(853, 'Delete', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(854, 'Confirm Removal', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(855, 'Service', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(856, 'Top Up Delivery', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(857, 'Service, no scan - damaged barcode', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(858, 'Service, no scan - no access', 'N', 'N', 10);
    insertFixedInfoForROUTETRANSACTIONTYPE(314, 'Modify Wearer Inventory', 'N', 'N', 2);
    insertFixedInfoForROUTETRANSACTIONTYPE(803, 'Scan Garment Soiled', 'N', 'N', 9);
    insertFixedInfoForROUTETRANSACTIONTYPE(808, 'Scan Garment Delivery', 'N', 'N', 9);
    insert into routetransactiontype_desc

      (routetransactiontype_ID, language_id, description, systemuser_id, timestamp)
      select r.routetransactiontype_ID, l.language_id, r.factorydescription, systemUserID, sysdate
        from routetransactiontype r, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from routetransactiontype_desc rd
               where rd.routetransactiontype_id = r.routetransactiontype_id
                 and l.language_id = rd.language_id);
     commit;
  exception
    when others then
      rollback;
      write_log('Error at ROUTETRANSACTIONTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForROUTETRANSACTIONTYPE;

  procedure insertFixedInfoForAUTOMATICFLAG(fp_automaticflag_id automaticflag.automaticflag_id%type,
                                            fp_event            automaticflag.event%type,
                                            fp_selectable       automaticflag.selectable%type,
                                            fp_deletable        automaticflag.deletable%type,
                                            fp_transferable     automaticflag.transferable%type,
                                            fp_flagtype         automaticflag.flagtype%type) is
    lv_deletable        automaticflag.deletable%type;
    lv_transferable     automaticflag.transferable%type;
  begin
    select af.deletable, af.transferable
      into lv_deletable, lv_transferable
      from automaticflag af
     where af.automaticflag_id = fp_automaticflag_id;
    if (lv_deletable <> fp_deletable) then
      update automaticflag af
         set af.deletable = fp_deletable, af.systemuser_id = systemUserID, af.timestamp = sysdate
       where af.automaticflag_id = fp_automaticflag_id;
    end if;
    if (lv_transferable <> fp_transferable) then
      update automaticflag af
         set af.transferable = fp_transferable, af.systemuser_id = systemUserID, af.timestamp = sysdate
       where af.automaticflag_id = fp_automaticflag_id;
    end if;

  exception
    when no_data_found then
      insert into automaticflag
        (automaticflag_id, event, systemuser_id, timestamp, selectable, deletable, transferable, flagtype)
      values
        (fp_automaticflag_id, fp_event, systemUserID, sysdate, fp_selectable, fp_deletable, fp_transferable, fp_flagtype);
  end insertFixedInfoForAUTOMATICFLAG;

  procedure fixedInfoForAUTOMATICFLAG is
  begin
      insertFixedInfoForAUTOMATICFLAG (1, 'Maximum number of washes reached', 'N', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (2, 'End of norm life time reached, auto replacement', 'N', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (3, 'Repair requested by repair pointer', 'N', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (4, 'Replacement requested using replacement button', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (5, 'Return free of charge item', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (6, 'Every xx washes reached', 'N', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (7, 'Flag for return to stock due to manual decrease of max inv', 'Y', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (8, 'Quit wearer', 'Y', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (9, 'End of Season', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (10, 'Start of Season', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (11, 'Missing emblem', 'N', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (12, 'Substitute garment', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (13, 'Quit Mat', 'Y', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (14, 'Charged for Loss', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (15, 'Temporary wearer inventory rent stop', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (16, 'Decrease max inv. after return to stock items with this flag', 'Y', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (17, 'Product contract ended for customer', 'N', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (18, 'Customer no longer active', 'N', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (19, 'Rewash', 'Y', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (20, 'Show on replaced item before replacement is active', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (21, 'Saving changed wearer data', 'Y', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (22, 'Rewashed', 'Y', 'Y', 'Y', 4);
      insertFixedInfoForAUTOMATICFLAG (23, 'Garment Dispenser', 'Y', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (24, 'Quit Wearer Inventory', 'Y', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (25, 'Direct Sales Only', 'Y', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (26, 'Returned', 'N', 'N', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (27, 'Maximum Number of Repairs', 'N', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (29, 'Repair requested by Web', 'N', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (30, 'Repair', 'Y', 'Y', 'Y', 4);
      insertFixedInfoForAUTOMATICFLAG (31, 'Temporary assign pool items', 'Y', 'Y', 'Y', 1);
      insertFixedInfoForAUTOMATICFLAG (32, 'Scanned Damaged', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (33, 'Lost phone', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (34, 'Lost earphones', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (35, 'Lost keys', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (36, 'Lost pen', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (37, 'Lost USB stick', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (38, 'Lost ID card', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (39, 'Lost wallet', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (40, 'Lost other', 'N', 'N', 'N', 1);
      insertFixedInfoForAUTOMATICFLAG (41, 'Assigned by Customer', 'N', 'N', 'Y', 4);
      insertFixedInfoForAUTOMATICFLAG (42, 'Product contract ended for customer', 'N', 'Y', 'Y', 5);
      insertFixedInfoForAUTOMATICFLAG (43, 'Duplicate ID Code', 'N', 'N', 'Y', 1);
      commit;
  exception
    when others then
      rollback;
      write_log('Error at AUTOMATICFLAG: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForAUTOMATICFLAG;

  procedure fixedInfoForSIZEDEFINITION is
  begin
    select sd.sizedefinition_id
      into id
      from sizedefinition sd
     where sd.code = '*';
  exception
    when no_data_found then
      insert into sizedefinition
        (sizedefinition_id, code, unfinishedlength, usedforemblem, systemuser_id, timestamp)
      values
        (seq_sizedefinition.nextval, '*', 'N', 'N', systemUserID, sysdate);
      insert into sizedefinition_desc
        (sizedefinition_id, language_id, description, systemuser_id, timestamp)
      values
        (seq_sizedefinition.currval, languageid, 'All', systemUserID, sysdate);
      insert into sizedefinition_link
        (sizedefinition_link_id, sizedefinition_id, code, systemuser_id, timestamp)
      values
        (seq_sizedefinition.currval, seq_sizedefinition.currval, '*', systemUserID, sysdate);
      insert into sizedefinition_link_desc
        (sizedefinition_link_id, language_id, description, systemuser_id, timestamp)
      values
        (seq_sizedefinition.currval, languageid, 'All', systemUserID, sysdate);
    commit;
    when others then
      rollback;
      write_log('Error at SIZEDEFINITION: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSIZEDEFINITION;

  procedure insertFixedInfoForLABELPRINTENGINE(fp_labelprintengine_id labelprintengine.labelprintengine_id%type,
                                               fp_description         labelprintengine.description%type) is
    lv_description labelprintengine.description%type;
  begin
    select lp.description
      into lv_description
      from labelprintengine lp
     where lp.labelprintengine_id = fp_labelprintengine_id;
    if (lv_description <> fp_description) then
      update labelprintengine lp
         set lp.description = fp_description, lp.systemuser_id = systemUserID, lp.timestamp = sysdate
       where lp.labelprintengine_id = fp_labelprintengine_id;
    end if;
  exception
    when no_data_found then
      insert into labelprintengine
        (labelprintengine_id, description, systemuser_id, timestamp)
      values
        (fp_labelprintengine_id, fp_description, systemUserID, sysdate);
  end insertFixedInfoForLABELPRINTENGINE;

  procedure fixedInfoForLABELPRINTENGINE is
  begin
    insertFixedInfoForLABELPRINTENGINE(1, 'Spark');
    insertFixedInfoForLABELPRINTENGINE(2, 'Labserv');
    insertFixedInfoForLABELPRINTENGINE(3, 'Label Designer');
    commit;
  exception
    when others then
      rollback;
      write_log('Error at LABELPRINTENGINE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForLABELPRINTENGINE;

  procedure fixedInfoForDAYS is
    dayID   day.day_id%type;
    dayCode t_arrayvarchar;
    dayDesc t_arrayvarchar;
  begin
    dayCode(1) := 'MO';
    dayDesc(1) := 'Monday';
    dayCode(2) := 'TU';
    dayDesc(2) := 'Tuesday';
    dayCode(3) := 'WE';
    dayDesc(3) := 'Wednesday';
    dayCode(4) := 'TH';
    dayDesc(4) := 'Thursday';
    dayCode(5) := 'FR';
    dayDesc(5) := 'Friday';
    dayCode(6) := 'SA';
    dayDesc(6) := 'Saturday';
    dayCode(7) := 'SU';
    dayDesc(7) := 'Sunday';
    for i in 1 .. 7
    loop
      begin
        select day_id
          into dayID
          from day
         where daynumber = i;
      exception
        when no_data_found then
          insert into day
            (day_id, daynumber, systemuser_id, timestamp)
          values
            (i, i, systemUserID, sysdate);
          insert into day_desc
            (day_id, language_id, code, description, systemuser_id, timestamp)
          values
            (i, languageID, dayCode(i), dayDesc(i), systemUserID, sysdate);
      end;
    end loop;
  commit;
  exception
    when others then
      rollback;
      write_log('Error at DAYS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDAYS;
  procedure insertFixedInfoForPROCESS(fp_process_id  process.process_id%type,
                                      fp_description process.description%type) is
    lv_description process.description%type;
  begin
    select p.description
      into lv_description
      from process p
     where p.process_id = fp_process_id;
    if (lv_description <> fp_description) then
      update process p
         set p.description = fp_description
       where p.process_id = fp_process_id;
    end if;
  exception
    when no_data_found then
      insert into process
        (process_id, description, active)
      values
        (fp_process_id, fp_description, 'Y');
  end insertFixedInfoForPROCESS;


  procedure fixedInfoForPROCESS is
  begin
    insertFixedInfoForPROCESS(1, 'Status Quo Pieces in Circulation');
    insertFixedInfoForPROCESS(2, 'Status Quo Sets in Circulation');
    insertFixedInfoForPROCESS(3, 'Status Quo Wearers');
    insertFixedInfoForPROCESS(4, 'Status Quo Stockroom Quantity');
    insertFixedInfoForPROCESS(5, 'Status Quo Residual Value');
    insertFixedInfoForPROCESS(6, 'Status Quo Circulating Inventory');
    insertFixedInfoForPROCESS(7, 'Status Quo Max Items in Circulation');
    insertFixedInfoForPROCESS(12, 'Put Assigned items into circulation');
    insertFixedInfoForPROCESS(13, 'Flag items beyound contract weeks for replacement');
    insertFixedInfoForPROCESS(14, 'Import stock counts from handheld terminal');
    insertFixedInfoForPROCESS(15, 'Price Update at Anniversary Date');
    insertFixedInfoForPROCESS(16, 'Import from EASy & MobiDiK');
    insertFixedInfoForPROCESS(17, 'Export info for Line Cards');
    insertFixedInfoForPROCESS(18, 'Import soil counts');
    insertFixedInfoForPROCESS(19, 'Export info to Garment Dispenser');
    insertFixedInfoForPROCESS(20, 'Import info from Garment Dispenser');
    insertFixedInfoForPROCESS(21, 'Email Invoices');
    insertFixedInfoForPROCESS(22, 'Email Statements');
    insertFixedInfoForPROCESS(23, 'Status Quo Leasing');
    insertFixedInfoForPROCESS(24, 'Status Quo Stock Charge');
    insertFixedInfoForPROCESS(25, 'E-mail Direct Invoices');
    insertFixedInfoForPROCESS(29, 'Automatic Flag Seasonal Items');
    insertFixedInfoForPROCESS(30, 'Status Quo On Site Inventory');
    insertFixedInfoForPROCESS(31, 'Rag after Grace Period');
    insertFixedInfoForPROCESS(32, 'Sort Batch Preparation');
    insertFixedInfoForPROCESS(33, 'Clean Up Garment Scans');
    insertFixedInfoForPROCESS(34, 'Clean Up Container Scans');
    insertFixedInfoForPROCESS(35, 'Generate Turnover Forecast');
    insertFixedInfoForPROCESS(36, 'Generate Cost Information');
    insertFixedInfoForPROCESS(37, 'Internal Value Calculation');
    insertFixedInfoForPROCESS(38, 'Clean Up Status Quo Information');
    insertFixedInfoForPROCESS(39, 'Compress Status Quo Items and Sets in Circulation');
    insertFixedInfoForPROCESS(40, 'Import Account Receivable Late charge');
    insertFixedInfoForPROCESS(41, 'Export Account Receivable Customer Information');
    insertFixedInfoForPROCESS(42, 'Export Account Receivable Information');
    insertFixedInfoForPROCESS(43, 'Flag Items with Temp. Wearer Inventory Rent Stop');
    insertFixedInfoForPROCESS(44, 'Import Payment Conditions from Axapta');
    insertFixedInfoForPROCESS(45, 'Import Work Orders from Axapta');
    insertFixedInfoForPROCESS(46, 'Export Invoices to Axapta');
    insertFixedInfoForPROCESS(47, 'Export Stock Transactions');
    insertFixedInfoForPROCESS(48, 'Automatic disable soil count/product when no recent soil count');
    insertFixedInfoForPROCESS(49, 'Import Products from Axapta');
    insertFixedInfoForPROCESS(50, 'Move Garments to Original Customer');
    insertFixedInfoForPROCESS(51, 'Calculate Commission');
    insertFixedInfoForPROCESS(52, 'Export to DocuWare');
    insertFixedInfoForPROCESS(53, 'Average Calculation Standard Deliveries');
    insertFixedInfoForPROCESS(54, 'Export to Cobra');
    insertFixedInfoForPROCESS(55, 'Export Invoices to Stralfors');
    insertFixedInfoForPROCESS(56, 'Process Wearer Garments Budgets');
    insertFixedInfoForPROCESS(57, 'Process Export EDI-OIO');
    insertFixedInfoForPROCESS(58, 'Export POS Customers');
    insertFixedInfoForPROCESS(59, 'Export POS Invoices');
    insertFixedInfoForPROCESS(60, 'Export POS Purchase Orders');
    insertFixedInfoForPROCESS(61, 'Export POS Receipts');
    insertFixedInfoForPROCESS(62, 'Process Export Invoices Daily System');
    insertFixedInfoForPROCESS(63, 'Import POS Payments');
    insertFixedInfoForPROCESS(64, 'Update Contract prices');
    insertFixedInfoForPROCESS(65, 'Automatic Contract Extension');
    insertFixedInfoForPROCESS(66, 'Import Orders');
    insertFixedInfoForPROCESS(67, 'Import HL7 Connections');
    insertFixedInfoForPROCESS(68, 'Export to delivery notes');
    insertFixedInfoForPROCESS(69, 'Process Import DW');
    insertFixedInfoForPROCESS(70, 'Clean up web service log');
    insertFixedInfoForPROCESS(71, 'Reference SQ items in circulation');
    insertFixedInfoForPROCESS(72, 'Reference SQ mats in circulation');
    insertFixedInfoForPROCESS(73, 'Generate Internal Stock Delivery Orders');
    insertFixedInfoForPROCESS(74, 'Clean up delivery scans');
    insertFixedInfoForPROCESS(75, 'Invoice Job');
    insertFixedInfoForPROCESS(76, 'Check Mounting Order Availability');
    insertFixedInfoForPROCESS(77, 'Export Indaut');
    insertFixedInfoForPROCESS(78, 'Import scans Indaut');
    insertFixedInfoForPROCESS(79, 'Import soil scans');
    insertFixedInfoForPROCESS(80, 'Automatic Billing');
    insertFixedInfoForPROCESS(81, 'Import Route Info from PDS');
    insertFixedInfoForPROCESS(82, 'Clean up Log');
    insertFixedInfoForPROCESS(83, 'Collect HTS Financial Stock Transactions');
    insertFixedInfoForPROCESS(84, 'Export HTS Financial Stock Transactions');
    insertFixedInfoForPROCESS(85, 'Settle Web Catalog Routes');
    insertFixedInfoForPROCESS(86, 'Clean up wearers');
    insertFixedInfoForPROCESS(87, 'Revenue Growth Calculation');
    insertFixedInfoForPROCESS(88, 'AR Snapshot');
    insertFixedInfoForPROCESS(90, 'User defined database script');
    insertFixedInfoForPROCESS(91, 'Export Invoices To Etra');
    insertFixedInfoForPROCESS(92, 'Import WMU Web Sales');
    insertFixedInfoForPROCESS(93, 'Export WMU Web Sales');
    insertFixedInfoForPROCESS(94, 'Export Invoices To Itella');
    insertFixedInfoForPROCESS(95, 'Clean Up Historical Invoice Data');
    insertFixedInfoForPROCESS(96, 'Import LCT transactions');
    insertFixedInfoForPROCESS(97, 'Generic purge');
    insertFixedInfoForPROCESS(98, 'Export Credit Card transactions for authorization and capture');
    insertFixedInfoForPROCESS(99, 'Import Credit Card Transactions authorization and capture results');
    insertFixedInfoForPROCESS(100, 'Send email with PDF delivery notes in attachment');
    insertFixedInfoForPROCESS(101, 'Send email with PDF consignment notes in attachment');
    insertFixedInfoForPROCESS(102, 'Inactivate Customer Delivery Schemes');
    insertFixedInfoForPROCESS(103, 'Print Pick Orders');
    insertFixedInfoForPROCESS(104, 'Loss for pool');
    insertFixedInfoForPROCESS(105, 'Generate finance charges');
    insertFixedInfoForPROCESS(106, 'Generate and print monthly statements');
    insertFixedInfoForPROCESS(107, 'Export Invoices (Postings) to GP');
    insertFixedInfoForPROCESS(108, 'Export Invoices (PDF)');
    insertFixedInfoForPROCESS(109, 'Import Customers on Hold from GP');
    insertFixedInfoForPROCESS(110, 'Import Sales Item Cost from GP');
    insertFixedInfoForPROCESS(111, 'Import Direct Sales Item from GP');
    insertFixedInfoForPROCESS(112, 'Export Dispatched Sales Items to GP');
    insertFixedInfoForPROCESS(113, 'Export Invoices for External Printing');
    insertFixedInfoForPROCESS(114, 'Generate finance charges and generate and print monthly statements');
    insertFixedInfoForPROCESS(115, 'Email POD');
    insertFixedInfoForPROCESS(116, 'Fill Size Ratio for size breakdown');
    insertFixedInfoForPROCESS(117, 'PDF Archiving');
    insertFixedInfoForPROCESS(118, 'Update Delivery Variations Delivery Date LLG');
    insertFixedInfoForPROCESS(119, 'Scrutiny');
    insertFixedInfoForPROCESS(120, 'Determine Slow and Fast Movers per Stockroom');
    insertFixedInfoForPROCESS(121, 'COMPLETE WEIGHINGTICKETS');
    insertFixedInfoForPROCESS(122, 'Add OR Delivery Variations to Existing Packing Notes');
    insertFixedInfoForPROCESS(123, 'Auto Complete Cleanroom Charges');
    insertFixedInfoForPROCESS(124, 'Status Quo Historic Residual value');
    insertFixedInfoForPROCESS(125, 'Import Contract Purchase Order');
    insertFixedInfoForPROCESS(126, 'Delivered Quantities Planned Data');
    insertFixedInfoForPROCESS(127, 'Recalculate Norm Stock');
    insertFixedInfoForPROCESS(128, 'Recalculate Standard Deliveries');
    insertFixedInfoForPROCESS(129, 'Fill Weight Based Delivery History');
    insertFixedInfoForPROCESS(130, 'Send Container Usage Report by E-mail');
    insertFixedInfoForPROCESS(131, 'Import Perl Stock Counts');
    insertFixedInfoForPROCESS(132, 'Delivery Efficiency Check');
    insertFixedInfoForPROCESS(133, 'Charge to Product Weekly');
    insertFixedInfoForPROCESS(134, 'Charge to Product Daily');
    insertFixedInfoForPROCESS(135, 'Close remit batch portal');
    insertFixedInfoForPROCESS(136, 'Production Process Buffer Snapshot');
    insertFixedInfoForPROCESS(137, 'Settle Subcontractor Routes');
    insertFixedInfoForPROCESS(138, 'Send Client Invoices by Email');
    insertFixedInfoForPROCESS(139, 'Fill Delivery Average');
    insertFixedInfoForPROCESS(140, 'Create Residential Inscan');
    insertFixedInfoForPROCESS(141, 'Chipping Rate Standard');
    insertFixedInfoForPROCESS(142, 'Chipping Rate Stock Level');
    insertFixedInfoForPROCESS(143, 'Automatic renewal of periodical free-of-charge adjustments');
    insertFixedInfoForPROCESS(144, 'Send document via email');
    insertFixedInfoForPROCESS(145, 'Settle Credit Card Transactions EBizCharge Gateway');
    insertFixedInfoForPROCESS(146, 'Tax Export (Online)');
    insertFixedInfoForPROCESS(147, 'Generate finance charges and statements (no printing)');
    insertFixedInfoForPROCESS(148, 'Generate Delivery Lot');
    insertFixedInfoForPROCESS(149, 'Fill Route Status Control');
    insertFixedInfoForPROCESS(150, 'Tax Export via XML');
    insertFixedInfoForPROCESS(151, 'Mark pool items lost in plant');
    insertFixedInfoForPROCESS(152, 'Found pool items lost in plant');
    insertFixedInfoForPROCESS(153, 'Automatic Close Reviewed Contacts');
    insertFixedInfoForPROCESS(154, 'Export Delivery Notes to Galaxie');
    insertFixedInfoForPROCESS(155, 'Create Credit Card transactions from payment schedule');
    insertFixedInfoForPROCESS(156, 'Clean up lost items flags');
    insertFixedInfoForPROCESS(157, 'Take Electronic Payment');
    insertFixedInfoForPROCESS(158, 'Refresh Credit Card Token');
    insertFixedInfoForPROCESS(159, 'Generate Work Order for Replenishment');
    insertFixedInfoForPROCESS(160, 'Import Vertex BCI Tax Response');
    insertFixedInfoForPROCESS(161, 'Automatic Settlement');
    insertFixedInfoForPROCESS(162, 'Vertex Address Cleaning');
    insertFixedInfoForPROCESS(163, 'Billing Method 6 Recalculation');
    insertFixedInfoForPROCESS(164, 'AutoSoil Recalculation');
    insertFixedInfoForPROCESS(165, 'Status Quo Wearer Inventory');
    insertFixedInfoForPROCESS(166, 'Export Info To Garment Dispenser via Message Broker');
    insertFixedInfoForPROCESS(167, 'Import Info From Garment Dispenser via Message Broker');
    insertFixedInfoForPROCESS(168, 'Generate Garment delivery notes by route');
    insertFixedInfoForPROCESS(169, 'Create Wearer Inventory Movement History');
    insertFixedInfoForPROCESS(170, 'Clean up negative delivery variations');
    insertFixedInfoForPROCESS(171, 'Generate Route Control records');
    insertFixedInfoForPROCESS(172, 'Oracle Teleservices Import');
    insertFixedInfoForPROCESS(173, 'Oracle Teleservices Export');
    insertFixedInfoForPROCESS(175, q'[Automatically generate putup docs and store PDF's in a folder]');
    insertFixedInfoForPROCESS(176, q'[Automatically generate direct invoices and store PDF's in a folder]');
    insertFixedInfoForPROCESS(177, 'Automatically Settle Route Controls for Previous Week');
    insertFixedInfoForPROCESS(178, 'Automatically write off small value ARTransactions');
    insertFixedInfoForPROCESS(179, 'Tax and assign imported invoices to routes');
    insertFixedInfoForPROCESS(180, 'Check / unmark duplicates');
    insertFixedInfoForPROCESS(181, 'Cancel and regenerate US direct invoices for late delivery notes');
    insertFixedInfoForPROCESS(182, 'Clean up audit trail tables');
    insertFixedInfoForPROCESS(183, 'Generate Weighing Tickets');

    commit;
  exception
    when others then
      rollback;
      write_log('Error at PROCESS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForPROCESS;

  procedure fixedInfoForRESIDUALVALUESCHEME is
  begin
    select residualvaluescheme_id
      into id
      from residualvaluescheme
     where code = '-';
  exception
    when no_data_found then
      insert into residualvaluescheme
        (residualvaluescheme_id, code, calculationweeks, calculationbasis, systemuser_id, timestamp)
      values
        (seq_residualvaluescheme.nextval, '-', 0, 1, systemUserID, sysdate);
      insert into residualvaluescheme_desc
        (residualvaluescheme_id, language_id, description, systemuser_id, timestamp)
      values
        (seq_residualvaluescheme.currval, languageID, '-', systemUserID, sysdate);
    commit;
    when others then
      rollback;
      write_log('Error at RESIDUALVALUESCHEME: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForRESIDUALVALUESCHEME;

  procedure fixedInfoForQUALITYGRADE is
  begin
    select count(1)
    into id
    from qualitygrade;
    if (id = 0) then
        insert into qualitygrade
          (qualitygrade_id, code, priority, defaultqualitygrade, newgarment, minwashes, maxwashes, minweeksinuse,
           maxweeksinuse, systemuser_id, timestamp)
        values
          (seq_qualitygrade.nextval, 'N', 1, 'N', 'Y', 0, 999, 0, 999, systemUserID, sysdate);
        insert into qualitygrade_desc
          (qualitygrade_id, language_id, description, systemuser_id, timestamp)
        values
          (seq_qualitygrade.currval, languageID, 'New', systemUserID, sysdate);
        insert into qualitygrade
          (qualitygrade_id, code, priority, defaultqualitygrade, newgarment, minwashes, maxwashes, minweeksinuse,
           maxweeksinuse, internalvaluepercentage, systemuser_id, timestamp)
        values
          (seq_qualitygrade.nextval, 'U', 2, 'Y', 'N', 0, 999, 0, 999, 50, systemUserID, sysdate);
        insert into qualitygrade_desc
          (qualitygrade_id, language_id, description, systemuser_id, timestamp)
        values
          (seq_qualitygrade.currval, languageID, 'Used', systemUserID, sysdate);
     end if;
      commit;
      exception
      when others then
       rollback;
      write_log('Error at QUALITYGRADE_U: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForQUALITYGRADE;
  procedure insertFixedInfoForCONVERTPRODUCTTABLELIST(fp_tablename convertproducttablelist.tablename%type,
                                                      fp_tabletype convertproducttablelist.tabletype%type) is

  begin
    select c.tabletype
    into id
    from convertproducttablelist c
    where c.tablename = fp_tablename;
    exception
      when no_data_found then
        insert into convertproducttablelist(tablename, tabletype)
        values(fp_tablename, fp_tabletype);
  end insertFixedInfoForCONVERTPRODUCTTABLELIST;

  procedure fixedInfoForCONVERTPRODUCTTABLELIST is
  begin
    insertFixedInfoForCONVERTPRODUCTTABLELIST('DELIVERYVARIATIONS', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALRENTDISCOUNT', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALRENTPRICE', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALWASHDISCOUNT', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALWASHPRICE', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PACKINGNOTELINE', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PRODUCTLISTPERCUSTOMER', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PRODUCTLISTPERDISTRIBPOINT', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SOILTICKETLINE', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('UNIQUEITEM', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('WEARERINVENTORY', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALEMBLEMPRICE', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALREPLACEMENTPRICE', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GENERALSALESPRICE', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('CUSTOMERREPLACEMENTPRICE', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('CUSTOMERSALESPRICE', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PACKCONTENTS', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('WORKORDERLINEEMBLEM', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('WORKORDERLINE', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('DELIVERYSCAN', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('INTERNETORDERLINE', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('INVOICELINEPRODUCT', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PACKINGNOTELINECONTENT', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PURCHASEORDERLINE', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SOILCOUNTLINE', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('STANDARDINVENTORY', 5);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('STANDARDLOCATIONPERPRODUCT', 5);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('STOCKDEFINITIONPERITEM', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('STRAIGHTEVENRETURN', 1);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('UNRELATEDLOAN', 2);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('DELIVERYHISTORY', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SQITEMINCIRCULATION', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SQSETINCIRCULATION', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SOILREASONABILITY', 3);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('EMBLEMHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('GARMENTSALESHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('ISSUEHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('OUTOFCIRCULATIONHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('OUTOFSTOCKHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('PRINTQUEUE', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('RAGGEDITEM', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('RECEIVEINSTOCKHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SCAN', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SOILHISTORY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('SQSTOCKQUANTITY', 4);
    insertFixedInfoForCONVERTPRODUCTTABLELIST('REPAIRHISTORY', 6);
    commit;
    exception
    when others then
      rollback;
      write_log('Error at CONVERTPRODUCTTABLELIST: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForCONVERTPRODUCTTABLELIST;

  procedure fixedInfoForPAYMENTTERMS is
  begin
    select pt.paymentterms_id
      into id
      from paymentterms pt
     where pt.code = '-';
  exception
    when no_data_found then
      insert into paymentterms
        (paymentterms_id, code, active, defaultpaymentterm, discountdays, netpaymentdays, discountdays2,
         paymentdiscount, paymentdiscount2, systemuser_id, timestamp)
      values
        (seq_paymentterms.nextval, '-', 'Y', 'Y', 0, 0, 0, 0, 0, systemUserID, sysdate);
        commit;
    when others then
      rollback;
      write_log('Error at PAYMENTTERMS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForPAYMENTTERMS;

  procedure fixedInfoForADDRESS is
  begin
    select count(1)
      into id
      from address;
    if (id = 0) then
      insert into address
        (address_id, street, zipcode, city, state, county, systemuser_id, timestamp)
      values
        (seq_address.nextval, '-', '-', '-', '-', '-', systemUserID, sysdate);
    end if;
    commit;
    exception
        when others then
      rollback;
      write_log('Error at ADDRESS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForADDRESS;

  procedure fixedInfoForSUPPLIER is
  begin
    select count(1)
      into id
      from supplier;
    if (id = 0) then
      insert into supplier
        (supplier_id, suppliernumber, name, address_id, currency_id, country_id, averageshipmentcosts,
         sendpurchaseorder, printpriceonpo, discountpercdays, discountwithindays, discountpercoverall, filelayout,
         shipmenttype_id, systemuser_id, timestamp)
      values
        (seq_supplier.nextval, 0, '-',
         (select max(address_id)
             from address),
         (select currency_id
             from currency
            where code = '-'),
         (select country_id
             from country
            where code = '-'), 0, 1, 'Y', 0, 0, 0, 0, null, systemUserID, sysdate);
    end if;
    commit;
    exception
        when others then
      rollback;
      write_log('Error at SUPPLIER: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSUPPLIER;
  procedure insertFixedInfoForLOCATIONTYPE(fp_code               locationtype.code%type,
                                           fp_factorydescription locationtype.factorydescription%type,
                                           fp_pickinglocation    locationtype.pickinglocation%type,
                                           fp_valuecontribution  locationtype.valuecontribution%type,
                                           fp_priority           locationtype.priority%type,
                                           fp_active             locationtype.active%type) is
  begin
    select count(1)
      into id
      from locationtype l
      where l. code = fp_code;
    if (id = 0) then
      insert into locationtype
        (locationtype_id, code, factorydescription, systemuser_id, timestamp, pickinglocation, valuecontribution,
         priority, active)
      values
        (seq_locationtype.nextval, fp_code, fp_factorydescription, systemUserID, sysdate, fp_pickinglocation,
         fp_valuecontribution, fp_priority, fp_active);
     end if;
  end insertFixedInfoForLOCATIONTYPE;

  procedure fixedInfoForLOCATIONTYPE is
  begin
    insertFixedInfoForLOCATIONTYPE('INSPECT', 'Inspection', 'N', 'Y', 0, 'N');
    insertFixedInfoForLOCATIONTYPE('QA', 'Quarantine', 'N', 'Y', 0, 'N');
    insertFixedInfoForLOCATIONTYPE('BULK', 'Bulk', 'N', 'Y', 0, 'N');
    insertFixedInfoForLOCATIONTYPE('PICK', 'Picking', 'Y', 'Y', 1, 'Y');
    insertFixedInfoForLOCATIONTYPE('OVERFLOW', 'Overflow', 'Y', 'Y', 2, 'Y');
    insertFixedInfoForLOCATIONTYPE('DEFECT', 'Defect', 'N', 'Y', 0, 'Y');
    insertFixedInfoForLOCATIONTYPE('SHOP', 'Shop Floor', 'N', 'Y', 0, 'N');
    insertFixedInfoForLOCATIONTYPE('SERVICE', 'Service Truck', 'N', 'Y', 0, 'Y');
    insertFixedInfoForLOCATIONTYPE('REPAIR', 'Repair', 'N', 'Y', 0, 'N');
    insertFixedInfoForLOCATIONTYPE('RAG', 'Ragged', 'N', 'Y', 0, 'N');
    insertFixedInfoForLOCATIONTYPE('BLOCK', 'Blocked', 'N', 'Y', 0, 'Y');
    insertFixedInfoForLOCATIONTYPE('TRANSIT', 'Transit', 'N', 'Y', 0, 'Y');
    insertFixedInfoForLOCATIONTYPE('CHECKIN', 'Check-in', 'N', 'Y', 0, 'Y');
    insert into locationtype_desc
      (locationtype_id, language_id, description, systemuser_id, timestamp)
      select l.locationtype_id, lan.language_id, l.code, systemUserID, sysdate
        from locationtype l, languages lan
       where lan.translatedescription = 'Y'
         and not exists (select 1
                from locationtype_desc ld
               where ld.locationtype_id = l.locationtype_id
                 and ld.language_id = lan.language_id);
     commit;
    exception
     when others then
      rollback;
      write_log('Error at LOCATIONTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForLOCATIONTYPE;

  procedure fixedInfoForTAXGROUP is
    lv_taxgroup_id taxgroup.taxgroup_id%type;
  begin
    select count(tg.taxgroup_id)
      into lv_taxgroup_id
      from taxgroup tg;
     if(lv_taxgroup_id = 0) then
      insert into taxgroup
      (taxgroup_id, code, description, active, taxrate, oldtaxrate, startdatetaxrate, country_id, systemuser_id,
       timestamp)
    values
      (seq_taxgroup.nextval, '-', '-', 'Y', 0, 0, sysdate,
       (select country_id
           from country
          where code = '-'), systemUserID, sysdate);
     end if;
     commit;
     exception
     when others then
      rollback;
      write_log('Error at TAXGROUP: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForTAXGROUP;

  procedure insertFixedInfoForDBCONSISTENCYCHECK(fp_dbconsistencycheck_id  dbconsistencycheck.dbconsistencycheck_id%type,
                                                 fp_description            dbconsistencycheck.description%type,
                                                 fp_sqlstatement           dbconsistencycheck.sqlstatement%type,
                                                 fp_errormessage           dbconsistencycheck.errormessage%type,
                                                 fp_exactlyonerow          dbconsistencycheck.exactlyonerow%type,
                                                 fp_additionalerrormessage dbconsistencycheck.additionalerrormessage%type,
                                                 fp_active                 dbconsistencycheck.active%type) is
    lv_description            dbconsistencycheck.description%type;
    lv_sqlstatement           dbconsistencycheck.sqlstatement%type;
    lv_errormessage           dbconsistencycheck.errormessage%type;
    lv_exactlyonerow          dbconsistencycheck.exactlyonerow%type;
    lv_additionalerrormessage dbconsistencycheck.additionalerrormessage%type;
    lv_active                 dbconsistencycheck.active%type;
  begin
    select d.description, d.sqlstatement, d.errormessage, d.exactlyonerow, d.additionalerrormessage, d.active
      into lv_description, lv_sqlstatement, lv_errormessage, lv_exactlyonerow, lv_additionalerrormessage, lv_active
      from dbconsistencycheck d
     where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    if (lv_description <> fp_description) then
      update dbconsistencycheck d
         set d.description = fp_description
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    end if;
    if (fp_sqlstatement <> lv_sqlstatement) then
      update dbconsistencycheck d
         set d.sqlstatement = fp_sqlstatement
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    end if;
    if (fp_errormessage <> lv_errormessage) then
      update dbconsistencycheck d
         set d.errormessage = fp_errormessage
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    end if;
    if (fp_exactlyonerow <> lv_exactlyonerow) then
      update dbconsistencycheck d
         set d.exactlyonerow = fp_exactlyonerow
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    end if;
    if (fp_additionalerrormessage <> lv_additionalerrormessage) then
      update dbconsistencycheck d
         set d.additionalerrormessage = fp_additionalerrormessage
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    end if;
    if (fp_active <> lv_active) then
      update dbconsistencycheck d
         set d.active = fp_active
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id;
    end if;
  exception
    when no_data_found then
      insert into dbconsistencycheck
        (dbconsistencycheck_id, description, sqlstatement, errormessage, exactlyonerow, additionalerrormessage, active)
      values
        (fp_dbconsistencycheck_id, fp_description, fp_sqlstatement, fp_errormessage, fp_exactlyonerow,
         fp_additionalerrormessage, fp_active);
  end insertFixedInfoForDBCONSISTENCYCHECK;

  procedure fixedInfoForDBCONSISTENCYCHECK is
  begin
    insertFixedInfoForDBCONSISTENCYCHECK(1,
                                         'All debtors have CustomerBillingInfo records',
                                         'select d.customer_id debtor_id, d.customernumber debtornumber, c.customer_id customer_id, c.customernumber customernumber' ||
                                         chr(10) || 'from customer c, customer d' || chr(10) ||
                                         'where c.debtor_id = d.customer_id' || chr(10) ||
                                         'and not exists(select b.customer_id from customerbillinginfo b where d.customer_id= b.customer_id)',
                                         'There are debtors without CustomerBillingInfo records!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(2,
                                         'Invoice address does not exists for Customer or Debtor ',
                                         'select c.customer_id customerid, c.customernumber customernumber,' || chr(10) ||
                                         ' d.customer_id debtorid, d.customernumber debtornumber' || chr(10) ||
                                         'from customer c, customer d' || chr(10) || 'where c.debtor_id = d.customer_id' ||
                                         chr(10) || 'and c.invoiceaddress_id is  null' || chr(10) ||
                                         'and d.invoiceaddress_id is  null',
                                         'There should be at least one invoice address defined for customer and debtor!',
                                         'N',
                                         'Please define invoiceaddress on customer level or debtor level!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(3,
                                         'Customers that are not debtors don''t have CustomerBillingInfo records',
                                         'select c.customer_id customerid, c.customernumber customernumber, c.debtor_id debtorid' ||
                                         chr(10) || 'from customer c, customerbillinginfo b' || chr(10) ||
                                         'where c.customer_id = b.customer_id' || chr(10) ||
                                         'and not exists (select cc.customer_id from customer cc, customer d' || chr(10) ||
                                         'where cc.debtor_id = d.customer_id' || chr(10) ||
                                         'and cc.debtor_id = c.customer_id)',
                                         'Customers that are not debtors should not have CustomerBillingInfo records',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(4,
                                         'Products from productlistpercustomer has corresponding records in productgroups per customer',
                                         'select a.productlistpercustomer_id, a.product_id, b.code, b.productgroup_id' ||
                                         chr(10) || 'from productlistpercustomer a, product b' || chr(10) ||
                                         'where a.product_id = b.product_id ' || chr(10) ||
                                         'and a.dateinactive = to_date(''31.12.2099 '','' dd.mm.yyyy '')' || chr(10) ||
                                         ' and not exists (select pgpc.productgroup_id ' || chr(10) ||
                                         'from productgrouppercustomer pgpc ' || chr(10) ||
                                         'where pgpc.customer_id = a.customer_id and ' || chr(10) ||
                                         'pgpc.productgroup_id = b.productgroup_id) ',
                                         'There are productlistpercustomer records with products that do not have productgroups in productgrouppercustomer table',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(5,
                                         'Correspondence plpc billingmethod with type of merchandise',
                                         'select a.productlistpercustomer_id,(select cu.customernumber  from customer cu where cu.customer_id = a.customer_id) customernumber,
          a.billingmethod, a.changesperweek, b.product_id, b.code,
          (select sz.code from sizedefinition sz where sz.sizedefinition_id = a.sizedefinition_id) SizedefinitionCode,
          (select fm.code from finishingmethod fm where fm.finishingmethod_id = a.finishingmethod_id) finishingmethodCode,
          b.typeofmerchandise, a.dateactive, a.dateinactive' || chr(10) ||
                                         'from productlistpercustomer a, product b' || chr(10) ||
                                         'where a.product_id = b.product_id' || chr(10) ||
                                         'and not exists (select plpc.productlistpercustomer_id' || chr(10) ||
                                         'from productlistpercustomer plpc, product p' || chr(10) ||
                                         'where plpc.customer_id = a.customer_id and ' || chr(10) ||
                                         'plpc.product_id = a.product_id and ' || chr(10) ||
                                         ' plpc.dateactive = a.dateactive and ' || chr(10) ||
                                         ' plpc.dateinactive = a.dateinactive and ' || chr(10) ||
                                         ' plpc.product_id = p.product_id' || chr(10) || 'and (' || chr(10) ||
                                         '(plpc.billingmethod = 1 and ' || chr(10) || '(' || chr(10) ||
                                         '(plpc.changesperweek = ''N''and p.typeofmerchandise in(1,2)) or' || chr(10) ||
                                         '(plpc.changesperweek = ''Y''and p.typeofmerchandise = 2)' || chr(10) || ')' ||
                                         chr(10) || ')' || chr(10) ||
                                         'or (plpc.billingmethod = 2 and p.typeofmerchandise in (1,2))' || chr(10) ||
                                         'or (plpc.billingmethod = 3 and p.typeofmerchandise in (1,2))' || chr(10) ||
                                         'or (plpc.billingmethod = 4 and p.typeofmerchandise in (1,2,3,5))' || chr(10) ||
                                         'or (plpc.billingmethod = 5 and (' || chr(10) ||
                                         '(plpc.changesperweek = ''N''and p.typeofmerchandise in(1,2)) or' || chr(10) ||
                                         '(plpc.changesperweek = ''Y''and p.typeofmerchandise = 2)' || chr(10) || '))' ||
                                         chr(10) || '))',
                                         'There are wrong combination of billingmethod with type of merchandise in product list per customer records!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(6,
                                         'CUSTOMER_LINK table is correctly filled',
                                         'select customernumber, name custName, customer_id, timestamp' || chr(10) ||
                                         'from customer a' || chr(10) ||
                                         'where not exists (select x.customer_id from customer_link x ' || chr(10) ||
                                         '                  where x.customer_id = a.customer_id)' || chr(10) ||
                                         'order by 1' || chr(9) || '' || chr(9) || '' || chr(9) || '' || chr(9) || '' ||
                                         chr(9) || '' || chr(9) || '' || chr(9) || '' || chr(9) || '' || chr(9) || '',
                                         'There are records in CUSTOMER table with no related record in CUSTOMER_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(7,
                                         'DEPARTMENT_LINK table is correctly filled',
                                         'select b.customernumber, b.name customerName, departmentnumber, a.description departmentDesc, department_id, a.timestamp' ||
                                         chr(10) || 'from department a, customer b' || chr(10) ||
                                         'where a.customer_id = b.customer_id and' || chr(10) ||
                                         '      not exists (select x.department_id from department_link x where x.department_id = a.department_id)' ||
                                         chr(10) || 'order by 1, 3',
                                         'There are records in DEPARTMENT table with no related record in DEPARTMENT_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(8,
                                         'DISTRIBUTIONPOINT_LINK table is correctly filled',
                                         'select customernumber, c.name customerName, departmentnumber, distributionpointnumber, distributionpoint_id, a.timestamp' ||
                                         chr(10) || 'from distributionpoint a, department b, customer c' || chr(10) ||
                                         'where a.department_id = b.department_id and' || chr(10) ||
                                         '      b.customer_id = c.customer_id and' || chr(10) ||
                                         '      not exists (select x.distributionpoint_id from distributionpoint_link x where x.distributionpoint_id = a.distributionpoint_id)' ||
                                         chr(10) || 'order by 1, 3, 4',
                                         'There are records in DISTRIBUTIONPOINT table with no related record in DISTRIBUTIONPOINT_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(9,
                                         'COSTCENTER_LINK table is correctly filled',
                                         'select customernumber, c.name customerName, a.code costCenterCode, a.description costCenterDesc, costcenter_id, a.timestamp' ||
                                         chr(10) || 'from costcenter a, customer c' || chr(10) ||
                                         'where a.customer_id = c.customer_id and' || chr(10) ||
                                         '      not exists (select x.costcenter_id from costcenter_link x where a.costcenter_id = x.costcenter_id)' ||
                                         chr(10) || 'order by 1, 3',
                                         'There are records in COSTCENTER table with no related record in COSTCENTER_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(10,
                                         'DELIVERYPOINT_LINK table is correctly filled',
                                         'select customernumber, c.name customerName, a.code deliveryPointCode, a.description deliveryPointDesc, deliverypoint_id, a.timestamp' ||
                                         chr(10) || 'from deliverypoint a, customer c' || chr(10) ||
                                         'where a.customer_id = c.customer_id and' || chr(10) ||
                                         '      not exists (select x.deliverypoint_id from deliverypoint_link x where a.deliverypoint_id = x.deliverypoint_id)' ||
                                         chr(10) || 'order by 1, 3',
                                         'There are records in DELIVERYPOINT table with no related record in DELIVERYPOINT_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(11,
                                         'PRODUCT_LINK table is correctly filled',
                                         'select a.code productCode, product_id, a.timestamp' || chr(10) ||
                                         'from product a' || chr(10) ||
                                         'where not exists (select x.product_id from product_link x where x.product_id = a.product_id)' ||
                                         chr(10) || 'order by 1',
                                         'There are records in PRODUCT table with no related record in PRODUCT_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(12,
                                         'SIZEDEFINITION_LINK table is correctly filled',
                                         'select code sizeDefinitionCode, sizedefinition_id, timestamp' || chr(10) ||
                                         'from sizedefinition a' || chr(10) ||
                                         'where not exists (select x.sizedefinition_id from sizedefinition_link x where x.sizedefinition_id = a.sizedefinition_id)' ||
                                         chr(10) || 'order by 1',
                                         'There are records in SIZEDEFINITION table with no related record in SIZEDEFINITION_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(13,
                                         'WEAREREMPLOYMENT_LINK table is correctly filled',
                                         'select customernumber, c.name customerName, wearernumber, b.fullname wearerName, a.sequencenumber employment, weareremployment_id, a.timestamp' ||
                                         chr(10) || 'from weareremployment a, wearer b, customer c' || chr(10) ||
                                         'where a.wearer_id = b.wearer_id and' || chr(10) || '' || chr(9) || '' ||
                                         chr(9) || '' || chr(9) || 'b.customer_id = c.customer_id and' || chr(10) ||
                                         '      not exists (select x.weareremployment_id from weareremployment_link x where x.weareremployment_id = a.weareremployment_id)' ||
                                         chr(10) || 'order by 1, 3, 5',
                                         'There are records in WEAREREMPLOYMENT table with no related record in WEAREREMPLOYMENT_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(14,
                                         'WEIGHINGCATEGORY_LINK table is correctly filled',
                                         'select code weighingCategoryCode, weighingcategory_id, timestamp' || chr(10) ||
                                         'from weighingcategory a' || chr(10) ||
                                         'where not exists (select x.weighingcategory_id from weighingcategory_link x where x.weighingcategory_id = a.weighingcategory_id)' ||
                                         chr(10) || 'order by 1',
                                         'There are records in WEIGHINGCATEGORY table with no related record in WEIGHINGCATEGORY_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(15,
                                         'CLIENT_LINK table is correctly filled',
                                         'select customernumber, b.name customerName, clientnumber, a.name clientName, client_id, a.timestamp' ||
                                         chr(10) || 'from client a, customer b' || chr(10) ||
                                         'where a.customer_id = b.customer_id and' || chr(10) ||
                                         '      not exists (select x.client_id from client_link x where x.client_id = a.client_id)' ||
                                         chr(10) || 'order by 1, 3',
                                         'There are records in CLIENT table with no related record in CLIENT_LINK table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(16,
                                         'Every consumption point has at least one standard delivery record',
                                         'select customernumber, name customername, departmentnumber, distributionpointnumber' ||
                                         chr(10) || 'from distributionpoint d, department dep, customer c' || chr(10) ||
                                         'where d.department_id = dep.department_id and' || chr(10) ||
                                         '      dep.customer_id = c.customer_id and' || chr(10) ||
                                         '      not exists (select s.standarddelivery_id from standarddelivery s where s.distributionpoint_id = d.distributionpoint_id)' ||
                                         chr(10) || 'order by 1, 3, 4',
                                         'There ate consumption points with no standard delivery!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(17,
                                         'Every customer has at least one department',
                                         'select customernumber, c.name customerName' || chr(10) || 'from customer c ' ||
                                         chr(10) ||
                                         'where not exists (select d.department_id from department d where d.customer_id = c.customer_id)' ||
                                         chr(10) || 'order by 1',
                                         'There are customers with no department!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(18,
                                         'Every department has at least one consumption point',
                                         'select customernumber, c.name customerName, departmentnumber' || chr(10) ||
                                         'from customer c, department d' || chr(10) ||
                                         'where c.customer_id = d.customer_id and' || chr(10) ||
                                         '      not exists (select dip.distributionpoint_id from distributionpoint dip ' ||
                                         chr(10) || '                  where dip.department_id = d.department_id)' ||
                                         chr(10) || 'order by 1, 3',
                                         'There are departments with no consumption point!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(19,
                                         'One default quality grade exists',
                                         'select count(q.qualitygrade_id)' || chr(10) || 'from qualitygrade q ' ||
                                         chr(10) ||
                                         'where q.defaultqualitygrade = ''Y'' and (select count(*) from qualitygrade) > 0',
                                         'There is no default quality grade!',
                                         'Y',
                                         'There is more than one default quality grade!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(20,
                                         'Each product has at least one product size',
                                         'select p.code productcode' || chr(10) || 'from product p' || chr(10) ||
                                         'where not exists (select ps.product_id from productsize ps where ps.product_id = p.product_id)' ||
                                         chr(10) || 'order by 1',
                                         'There are products with no product size!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(21,
                                         'Each defined tax group has a turnover group and a not allocable turnover group defined when UseTurnverGroup = ''Y''',
                                         'select tx.code taxCode, tx.description taxDescription, tx.turnovergroup_id, tx.notallocatableturnover_id' ||
                                         chr(10) ||
                                         'from taxgroup tx where tx.turnovergroup_id is null or tx.notallocatableturnover_id is null' ||
                                         chr(10) || 'order by 1',
                                         'There are tax groups with no turnover group or not allocable turnovergroup defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(22,
                                         'Product groups per customer have corresponding record in activities per customer',
                                         'select a.customer_id, a.productgroup_id, b.code, c.activity_id, c.code' ||
                                         chr(10) || ' from productgrouppercustomer a, productgroup b, activity c' ||
                                         chr(10) ||
                                         ' where a.productgroup_id = b.productgroup_id and b.activity_id = c.activity_id and' ||
                                         chr(10) || ' not exists ' || chr(10) || ' (select pgpc.productgroup_id' ||
                                         chr(10) ||
                                         ' from productgrouppercustomer pgpc, productgroup pg, customeractivities ca' ||
                                         chr(10) || ' where pgpc.productgroup_id = pg.productgroup_id and' || chr(10) ||
                                         ' pg.activity_id = ca.activity_id and' || chr(10) ||
                                         ' pgpc.customer_id = ca.customer_id and' || chr(10) ||
                                         ' a.productgroup_id = pgpc.productgroup_id and' || chr(10) ||
                                         ' a.customer_id = pgpc.customer_id)',
                                         'There are productgrouppercustomer records with productsgroups that do not have activities in customeractivities table!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(23,
                                         'Type of merchandise should be equal for product and its models',
                                         'select p.product_id, p.code, p.typeofmerchandise, m.product_id, m.code, m.typeofmerchandise' ||
                                         chr(10) || ' from product p, product m' || chr(10) ||
                                         ' where p.product_id = m.parentproduct_id and' || chr(10) ||
                                         ' m.product_id != m.parentproduct_id and' || chr(10) ||
                                         ' p.typeofmerchandise != m.typeofmerchandise' || chr(10) || ' order by 2, 5',
                                         'There are models with a different type of merchandise than parent product!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(24,
                                         'One default transport article exists',
                                         'select count(t.transportarticle_id)' || chr(10) || 'from transportarticle t' ||
                                         chr(10) ||
                                         'where t.defaulttransportarticle = ''Y'' and (select count(*) from transportarticle) > 0',
                                         'There is no default transport article!',
                                         'Y',
                                         'There is more than one default transport article!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(25,
                                         'Check if there is more than one default paymentterms!',
                                         'select case when (select count(pt.paymentterms_id)' || chr(10) ||
                                         'from paymentterms pt' || chr(10) ||
                                         'where pt.defaultpaymentterm =''Y'') > 1 then 0' || chr(10) ||
                                         'when (select count(pt.paymentterms_id) from paymentterms pt) = 0 then 0  else 1 end countdefault from dual',
                                         'There is no record in paymentterms table!',
                                         'Y',
                                         'There is more than one default payment terms!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(26,
                                         'Only one country has the flag for define tax set',
                                         'select count(c.country_id)' || chr(10) || 'from country c' || chr(10) ||
                                         'where c.definetax = ''Y'' and (select count(*) from country) > 0',
                                         'There is no country which has the flag for define tax set!',
                                         'Y',
                                         'There is more than one country which has the flag for define tax set!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(27,
                                         'One default invoice frequency exists',
                                         'select count(f.invoicefrequency_id)' || chr(10) || 'from invoicefrequency f' ||
                                         chr(10) ||
                                         'where f.defaultfrequency = ''Y'' and (select count(*) from invoicefrequency) > 0',
                                         'There is no default invoice frequency!',
                                         'Y',
                                         'There is more than one default invoice frequency!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(28,
                                         'Check if turnover group is defined for invoice line type - when it is a must',
                                         'select i.type, i.factorydescription' || chr(10) || 'from invoicelinetype i ' ||
                                         chr(10) ||
                                         'where i.defineturnovergroup = ''Y'' and i.turnovergroup_id is null and i.invoicelinetype_id <> 15',
                                         'There are invoice line types where turnover group is not defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(29,
                                         'Check if taxgroup is defined for invoice line type - when it is a must',
                                         'select ilt.type, ilt.factorydescription' || chr(10) ||
                                         'from invoicelinetype ilt' || chr(10) || 'where ilt.taxtype != 0 and ' ||
                                         chr(10) ||
                                         'not exists (select iltt.invoicelinetype_id from invoicelinetypetax iltt, country c' ||
                                         chr(10) ||
                                         '            where ilt.invoicelinetype_id = iltt.invoicelinetype_id and' ||
                                         chr(10) ||
                                         '                  iltt.country_id = c.country_id and c.definetax = ''Y'')',
                                         'There are invoice line types where taxgroup is not defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(30,
                                         'Check if a turnover group for credit squeeze is defined when UseTurnverGroup = ''Y''',
                                         'select p.code plantcode from plant p where p.creditsqueezeturnovergroup_id is null',
                                         'There are plants where no turnover group for credit squeeze is defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(31,
                                         'Check if per plant at least one invoice line type is defined',
                                         'select p.code plantcode from plant p ' || chr(10) ||
                                         'where not exists (select pilt.plant_id from plantinvoicelinetype pilt where p.plant_id = pilt.plant_id)',
                                         'There are plants where no invoice line type is defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(32,
                                         'Check if per plant at least one invoice frequency is defined',
                                         'select p.code plantcode from plant p ' || chr(10) ||
                                         'where not exists (select pif.plant_id from plantinvoicefrequency pif ' ||
                                         chr(10) ||
                                         '                  where p.plant_id = pif.plant_id and pif.documenttype = 1)',
                                         'There are plants where no invoice frequency is defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(33,
                                         'Check if per plant at least one statement frequency is defined',
                                         'select p.code plantcode from plant p ' || chr(10) ||
                                         'where not exists (select pif.plant_id from plantinvoicefrequency pif ' ||
                                         chr(10) ||
                                         '                  where p.plant_id = pif.plant_id and pif.documenttype = 2)',
                                         'There are plants where no invoice statement is defined!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(34,
                                         'If there are emblem templates defined check if the fabric has the flag UsedForEmblem checked',
                                         'select e.code emblemtemplatecode, e.description, c.customernumber, ff.code' ||
                                         chr(10) ||
                                         'from emblemtemplate e, emblemtemplateline el, customer c, fabric ff' ||
                                         chr(10) || 'where e.emblemtemplate_id = el.emblemtemplate_id and ' || chr(10) ||
                                         '      e.customer_id = c.customer_id and' || chr(10) ||
                                         '      el.fabric_id = ff.fabric_id and' || chr(10) ||
                                         '      ff.usedforemblem = ''N'' ' || chr(10) || 'order by 1, 2, 4 ',
                                         'There are emblem templates having UsedForEmblem flag unchecked for the fabric!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(35,
                                         'If there are emblem templates defined check if the size definition has the flag UsedForEmblem checked',
                                         'select c.customernumber, e.code emblemtemplatecode, e.description, ss.code' ||
                                         chr(10) ||
                                         'from emblemtemplate e, emblemtemplateline el, customer c, sizedefinition ss' ||
                                         chr(10) || 'where e.emblemtemplate_id = el.emblemtemplate_id and ' || chr(10) ||
                                         '      e.customer_id = c.customer_id and' || chr(10) ||
                                         '      el.sizedefinition_id = ss.sizedefinition_id and' || chr(10) ||
                                         '      ss.usedforemblem =  ''N'' ' || chr(10) || 'order by 1, 2, 4 ',
                                         'There are emblem templates having UsedForEmblem flag unchecked for the size definition!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(36,
                                         'If there are emblem templates defined check if the text color has the flag UsedForEmblem checked',
                                         'select e.code emblemtemplatecode, e.description, c.customernumber, cc.code' ||
                                         chr(10) || 'from emblemtemplate e, emblemtemplateline el, customer c, color cc' ||
                                         chr(10) || 'where e.emblemtemplate_id = el.emblemtemplate_id and ' || chr(10) ||
                                         '      e.customer_id = c.customer_id and' || chr(10) ||
                                         '      el.textcolor_id = cc.color_id and' || chr(10) ||
                                         '      cc.usedforemblem = ''N'' ',
                                         'There are emblem templates having UsedForEmblem flag unchecked for the text color!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(37,
                                         'If there are emblem templates defined check if the border color has the flag UsedForEmblem checked',
                                         'select e.code emblemtemplatecode, e.description, c.customernumber, cc.code' ||
                                         chr(10) || 'from emblemtemplate e, emblemtemplateline el, customer c, color cc' ||
                                         chr(10) || 'where e.emblemtemplate_id = el.emblemtemplate_id and ' || chr(10) ||
                                         '      e.customer_id = c.customer_id and' || chr(10) ||
                                         '      el.bordercolor_id = cc.color_id and' || chr(10) ||
                                         '      cc.usedforemblem = ''N'' ',
                                         'There are emblem templates having UsedForEmblem flag unchecked for the border color!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(38,
                                         'If there are emblem templates defined check if the background color has the flag UsedForEmblem checked',
                                         'select e.code emblemtemplatecode, e.description, c.customernumber, cc.code' ||
                                         chr(10) || 'from emblemtemplate e, emblemtemplateline el, customer c, color cc' ||
                                         chr(10) || 'where e.emblemtemplate_id = el.emblemtemplate_id and ' || chr(10) ||
                                         '      e.customer_id = c.customer_id and' || chr(10) ||
                                         '      el.bkgcolor_id = cc.color_id and' || chr(10) ||
                                         '      cc.usedforemblem = ''N'' ',
                                         'There are emblem templates having UsedForEmblem flag unchecked for the background color!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(39,
                                         'Check if for active wearer inventory lines active plpc records exist (also size *)',
                                         'select c.customernumber, w.wearernumber, we.sequencenumber, p.code productCode, s.code sizeCode, f.code finishingmethodCode,' ||
                                         'to_char(plpc.dateactive,''DD-MON-yyyy'') plpcDateactive, to_char(plpc.dateinactive,''DD-MON-yyyy'') plpcDateinactive, plpc.productlistpercustomer_id ' ||
                                         chr(10) ||
                                         'from wearerinventory wi, weareremployment we, wearer w, customer c, product p, sizedefinition s, finishingmethod f, productlistpercustomer plpc' ||
                                         chr(10) || 'where wi.weareremployment_id = we.weareremployment_id and ' ||
                                         chr(10) || '      we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      wi.product_id = p.product_id and' || chr(10) ||
                                         '      wi.sizedefinition_id = s.sizedefinition_id and' || chr(10) ||
                                         '      wi.finishingmethod_id = f.finishingmethod_id and' || chr(10) ||
                                         '      sysdate between wi.dateactive and wi.dateinactive and' || chr(10) ||
                                         '       plpc.customer_id = c.customer_id and ' || chr(10) ||
                                         '       plpc.product_id = p.product_id and' || chr(10) ||
                                         '       plpc.sizedefinition_id = s.sizedefinition_id ' || chr(10) ||
                                         '       and not exists ' || chr(10) || ' (select productlistpercustomer_id ' ||
                                         chr(10) || ' from productlistpercustomer ' || chr(10) ||
                                         ' where customer_id = c.customer_id ' || chr(10) ||
                                         ' and product_id = p.product_id ' || chr(10) || ' and sizedefinition_id = ' ||
                                         chr(10) || ' (select ss.sizedefinition_id ' || chr(10) ||
                                         '  from sizedefinition ss ' || chr(10) || '  where ss.code = ''*'')  ' ||
                                         chr(10) || '  and sysdate between dateactive and dateinactive) and' || chr(10) ||
                                         '        plpc.finishingmethod_id = f.finishingmethod_id and' || chr(10) ||
                                         '        sysdate not between plpc.dateactive and plpc.dateinactive' || chr(10) ||
                                         'union ' ||
                                         'select c.customernumber, w.wearernumber, we.sequencenumber, p.code productCode, s.code sizeCode, f.code finishingmethodCode,' ||
                                         'to_char(plpc.dateactive,''DD-MON-yyyy'') plpcDateactive, to_char(plpc.dateinactive,''DD-MON-yyyy'') plpcDateinactive, plpc.productlistpercustomer_id ' ||
                                         chr(10) ||
                                         'from wearerinventory wi, weareremployment we, wearer w, customer c, product p, sizedefinition s, finishingmethod f, productlistpercustomer plpc' ||
                                         chr(10) || 'where wi.weareremployment_id = we.weareremployment_id and ' ||
                                         chr(10) || '      we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      wi.product_id = p.product_id and' || chr(10) ||
                                         '      wi.sizedefinition_id = s.sizedefinition_id and' || chr(10) ||
                                         '      wi.finishingmethod_id = f.finishingmethod_id and' || chr(10) ||
                                         '      sysdate between wi.dateactive and wi.dateinactive and' || chr(10) ||
                                         '       plpc.customer_id = c.customer_id and ' || chr(10) ||
                                         '       plpc.product_id = p.product_id and' || chr(10) ||
                                         '       plpc.sizedefinition_id = (select ss.sizedefinition_id from sizedefinition ss where ss.code = ''*'') ' ||
                                         chr(10) || '       and not exists ' || chr(10) ||
                                         ' (select productlistpercustomer_id ' || chr(10) ||
                                         ' from productlistpercustomer ' || chr(10) ||
                                         ' where customer_id = c.customer_id ' || chr(10) ||
                                         ' and product_id = p.product_id ' || chr(10) ||
                                         ' and sizedefinition_id =  s.sizedefinition_id ' || chr(10) ||
                                         ' and sysdate between dateactive and dateinactive) and' || chr(10) ||
                                         '        plpc.finishingmethod_id = f.finishingmethod_id and' || chr(10) ||
                                         '        sysdate not between plpc.dateactive and plpc.dateinactive' || chr(10) ||
                                         'union ' || chr(10) || 'select c.customernumber, w.wearernumber, we.sequencenumber, p.code productCode, s.code sizeCode, f.code finishingmethodCode,
         null, null, null ' || chr(10) ||
                                         'from wearerinventory wi, weareremployment we, wearer w, customer c, product p, sizedefinition s, finishingmethod f' ||
                                         chr(10) || 'where wi.weareremployment_id = we.weareremployment_id and ' ||
                                         chr(10) || '      we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      wi.product_id = p.product_id and' || chr(10) ||
                                         '      wi.sizedefinition_id = s.sizedefinition_id and' || chr(10) ||
                                         '      wi.finishingmethod_id = f.finishingmethod_id and' || chr(10) ||
                                         '      sysdate between wi.dateactive and wi.dateinactive and' || chr(10) ||
                                         '      not exists (select plpc.productlistpercustomer_id from productlistpercustomer plpc' ||
                                         chr(10) || '                  where plpc.customer_id = c.customer_id and ' ||
                                         chr(10) || '                        plpc.product_id = p.product_id and' ||
                                         chr(10) ||
                                         '                        (plpc.sizedefinition_id = s.sizedefinition_id or' ||
                                         chr(10) ||
                                         '                         plpc.sizedefinition_id = (select ss.sizedefinition_id from sizedefinition ss where ss.code = ''*'')) and' ||
                                         chr(10) ||
                                         '                        plpc.finishingmethod_id = f.finishingmethod_id )',
                                         'There are active wearer inventories line with no corresponding active product list per customer!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(40,
                                         'Check for overlapping product list per customer',
                                         'select c.customernumber, p.code productcode, s.code sizecode, f.code finishingmethodcode,' ||
                                         chr(10) || 'a.productlistpercustomer_id, a.dateactive, a.dateinactive, ' ||
                                         chr(10) || 'b.productlistpercustomer_id, b.dateactive, b.dateinactive, ' ||
                                         chr(10) || 'a.timestamp, b.timestamp' || chr(10) ||
                                         'from productlistpercustomer a, productlistpercustomer b, customer c, product p, sizedefinition s, finishingmethod f' ||
                                         chr(10) || 'where a.customer_id = b.customer_id and' || chr(10) ||
                                         'a.product_id = b.product_id and' || chr(10) ||
                                         'a.sizedefinition_id = b.sizedefinition_id and' || chr(10) ||
                                         'a.finishingmethod_id = b.finishingmethod_id and' || chr(10) ||
                                         'a.productlistpercustomer_id != b.productlistpercustomer_id and' || chr(10) ||
                                         '(a.dateactive between b.dateactive and b.dateinactive or' || chr(10) ||
                                         'a.dateinactive between b.dateactive and b.dateinactive) and' || chr(10) ||
                                         'a.customer_id = c.customer_id and' || chr(10) ||
                                         'a.product_id = p.product_id and' || chr(10) ||
                                         'a.sizedefinition_id = s.sizedefinition_id and' || chr(10) ||
                                         'a.finishingmethod_id = f.finishingmethod_id' || chr(10) ||
                                         'order by c.customernumber, p.code, s.code, f.code',
                                         'There are overlapping product list per customer!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(41,
                                         'Check for overlapping standard delivery lines',
                                         'select
  cust.defaultbusinessunit_id,
  sdl1.timestamp,
  cust.customernumber,
         dep.departmentnumber,
         dip.distributionpointnumber,
         p.code                       productcode,
         s.code                       sizecode,
         fm.code                      finishingmethodcode,
         sdl1.standarddeliveryline_id,
         sdl1.dateactive,
         sdl1.dateinactive,
         sdl2.standarddeliveryline_id,
         sdl2.dateactive,
         sdl2.dateinactive
    from standarddeliveryline       sdl1,
         standarddeliveryline       sdl2,
         productlistperdistribpoint plpdp,
         product                    p,
         sizedefinition             s,
         finishingmethod            fm,
         distributionpoint          dip,
         department                 dep,
         customer                   cust
   where sdl1.standarddelivery_id = sdl2.standarddelivery_id
     and sdl1.productlistperdistribpoint_id =
         sdl2.productlistperdistribpoint_id
     and sdl1.standarddeliveryline_id < sdl2.standarddeliveryline_id
     and (((sdl1.dateactive <= sdl2.dateactive) and
         (sdl2.dateactive <= sdl1.dateinactive)) or
         ((sdl2.dateactive <= sdl1.dateactive) and
         (sdl1.dateactive <= sdl2.dateinactive)))
     and sdl1.productlistperdistribpoint_id =
         plpdp.productlistperdistribpoint_id
     and plpdp.distributionpoint_id = dip.distributionpoint_id
     and dip.department_id = dep.department_id
     and dep.customer_id = cust.customer_id
     and plpdp.product_id = p.product_id
     and plpdp.sizedefinition_id = s.sizedefinition_id
     and plpdp.finishingmethod_id = fm.finishingmethod_id
     and sdl1.deliveryscheme_id=sdl2.deliveryscheme_id
     and cust.defaultbusinessunit_id = 5
     order by sdl1.timestamp desc',
                                         'There are overlapping standard delivery lines!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(42,
                                         'Check if there are wearer employments linked to a wrong distribution point (linked to another customer than customer of the wearer)',
                                         'select c.customernumber, w.wearernumber, we.sequencenumber, cc.customernumber' ||
                                         chr(10) ||
                                         'from weareremployment we, wearer w, customer c, distributionpoint dip, department dep, customer cc' ||
                                         chr(10) || 'where we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      we.distributionpoint_id = dip.distributionpoint_id and' || chr(10) ||
                                         '      dip.department_id = dep.department_id and' || chr(10) ||
                                         '      dep.customer_id = cc.customer_id and' || chr(10) ||
                                         '      c.customer_id != cc.customer_id',
                                         'There are wearer employments linked to a wrong distribution point!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(43,
                                         'Check if in wearer inventory only products with type of merchandise garments exist',
                                         'select c.customernumber, w.wearernumber, we.sequencenumber, p.code, p.typeofmerchandise' ||
                                         chr(10) ||
                                         'from wearerinventory wi, weareremployment we, wearer w, customer c, product p' ||
                                         chr(10) || 'where wi.weareremployment_id = we.weareremployment_id and' ||
                                         chr(10) || '      we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      wi.product_id = p.product_id and' || chr(10) ||
                                         '      p.typeofmerchandise != 2',
                                         'There are products in wearer inventory with another type of merchandise than garments',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(44,
                                         'Check if wearer employments have only one of the following links filled: delivery point, locker, garment dispenser',
                                         'select c.customernumber, w.wearernumber, we.sequencenumber' || chr(10) ||
                                         'from weareremployment we, wearer w, customer c' || chr(10) ||
                                         'where we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      ((we.deliverypoint_id is not null and we.locker_id is not null) or' ||
                                         chr(10) ||
                                         '       (we.deliverypoint_id is not null and we.garmentdispenser_id is not null) or ' ||
                                         chr(10) ||
                                         '       (we.locker_id is not null and we.garmentdispenser_id is not null))',
                                         'There are wearer employments having more than only one of the following links filled: delivery point, locker, garment dispenser!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(45,
                                         'Check if wearer employments have at least one of the following links filled: delivery point, locker, garment dispenser',
                                         'select c.customernumber, w.wearernumber, we.sequencenumber' || chr(10) ||
                                         'from weareremployment we, wearer w, customer c' || chr(10) ||
                                         'where we.wearer_id = w.wearer_id and' || chr(10) ||
                                         '      w.customer_id = c.customer_id and' || chr(10) ||
                                         '      we.deliverypoint_id is null and we.locker_id is null and we.garmentdispenser_id is null',
                                         'There are wearer employments having none of the following links filled: delivery point, locker, garment dispenser!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(46,
                                         'Check if every product group is linked to a packing department',
                                         'select pg.code prodgroupcode, pl.code plantcode' || chr(10) ||
                                         'from productgroup pg, plant pl' || chr(10) ||
                                         'where exists (select pd.productgroup_id' || chr(10) ||
                                         'from packingdepartmentdefinition pd' || chr(10) ||
                                         'where pd.productgroup_id = pg.productgroup_id and' || chr(10) ||
                                         'pd.plant_id = pl.plant_id and' || chr(10) ||
                                         'pd.plantdepartment_id is null) OR not exists' || chr(10) ||
                                         '(select pdd.productgroup_id' || chr(10) ||
                                         'from packingdepartmentdefinition pdd' || chr(10) ||
                                         'where pdd.productgroup_id = pg.productgroup_id and' || chr(10) ||
                                         'pdd.plant_id = pl.plant_id)',
                                         'There are product groups that are not linked to a packing department',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(47,
                                         'Check for non pool unique items the existence of UniqueItemNonPool table',
                                         'select u.primaryid' || chr(10) || 'from uniqueitem u' || chr(10) ||
                                         'where u.poolitem = 2 and' || chr(10) ||
                                         '      not exists (select uinp.uniqueitem_id from uniqueitemnonpool uinp where u.uniqueitem_id = uinp.uniqueitem_id)',
                                         'There are non pool items without a corresponding record in UniqueItemNonPoolTable!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(48,
                                         'Check correct filling of field poolitem regarding stay stock',
                                         'select u.primaryid, s.staytype, s.staynr, s.factorydescription, u.businessunit_id
          from uniqueitem u, stay s
          where u.poolitem = 0 and u.stay_id = s.stay_id and
        (s.staytype != 1 or s.staynr not in (10,26))',
                                         'There are unique items in stock where stay is not filled correctly!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(49,
                                         'Check if there are route controls with settled and not settled invoices',
                                         'select r.routenumber, r.drivingday_id, rc.drivingdate ' || chr(10) ||
                                         'from routecontrol rc, route r' || chr(10) ||
                                         'where rc.route_id = r.route_id and' || chr(10) ||
                                         '      exists (select ih.invoiceheader_id from invoiceheader ih, status s' ||
                                         chr(10) || '              where ih.status_id = s.status_id and ' || chr(10) ||
                                         '                    ih.routecontrol_id = rc.routecontrol_id and' || chr(10) ||
                                         '                    s.code = 2) and' || chr(10) ||
                                         '      exists (select ih.invoiceheader_id from invoiceheader ih, status s' ||
                                         chr(10) || '              where ih.status_id = s.status_id and ' || chr(10) ||
                                         '                    ih.routecontrol_id = rc.routecontrol_id and' || chr(10) ||
                                         '                    s.code = 1)',
                                         'There are route controls with settled and not settled invoices!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(50,
                                         'Check if there is a product list per customer record for unique items in circulation',
                                         'select b.code businessunitcode, count(ui.primaryid), ''Non pool'' as "NonPool/Inscanned/Outscanned",' ||
                                         '(select pr.code from product pr where pr.product_id = ui.product_id) productCode,  ' ||
                                         '(select cu.customernumber from customer cu where cu.customer_id = w.customer_id) customerNo,  ' ||
                                         '(select sz.code from sizedefinition sz where sz.sizedefinition_id = ui.sizedefinition_id) sizeCode  ' ||
                                         'from uniqueitem ui, uniqueitemnonpool uinp, weareremployment we, wearer w, status, businessunit b  ' ||
                                         'where ui.uniqueitem_id = uinp.uniqueitem_id and ui.poolitem = 2 and  ' ||
                                         'ui.status_id = status.status_id and status.code = ''20'' and ' ||
                                         'uinp.weareremployment_id = we.weareremployment_id and ' ||
                                         'we.wearer_id = w.wearer_id and ' ||
                                         'ui.businessunit_id = b.businessunit_id and ' ||
                                         'not exists (select plpc.productlistpercustomer_id from productlistpercustomer plpc ' ||
                                         '            where w.customer_id = plpc.customer_id and ' ||
                                         '                  ui.product_id = plpc.product_id and ' ||
                                         '                  (ui.sizedefinition_id = plpc.sizedefinition_id or  ' ||
                                         '                   plpc.sizedefinition_id = (select s.sizedefinition_id from sizedefinition s where s.code = ''*'')) and ' ||
                                         '                  ui.finishingmethod_id = plpc.finishingmethod_id ) ' ||
                                         'group by b.code , b.description, ui.product_id, w.customer_id, ui.sizedefinition_id ' ||
                                         'union all ' ||
                                         'select b.code businessunitcode, count(ui.primaryid), ''Pool inscanned'', ' ||
                                         '(select pr.code from product pr where pr.product_id = ui.product_id) productCode, ' ||
                                         '(select cu.customernumber from customer cu where cu.customer_id = dep.customer_id) customerNo, ' ||
                                         '(select sz.code from sizedefinition sz where sz.sizedefinition_id = ui.sizedefinition_id) sizeCode  ' ||
                                         'from uniqueitem ui, distributionpoint dip, department dep, status, businessunit b  ' ||
                                         'where ui.lastdistributionpoint_link_id = dip.distributionpoint_id and  ' ||
                                         'dip.department_id = dep.department_id and ui.poolitem = 1 and  ' ||
                                         'ui.status_id = status.status_id and status.code = ''20'' and  ' ||
                                         'ui.businessunit_id = b.businessunit_id and ' ||
                                         'not exists (select plpc.productlistpercustomer_id from productlistpercustomer plpc ' ||
                                         '            where dep.customer_id = plpc.customer_id and ' ||
                                         '                  ui.product_id = plpc.product_id and ' ||
                                         '                 (ui.sizedefinition_id = plpc.sizedefinition_id or  ' ||
                                         '                   plpc.sizedefinition_id = (select s.sizedefinition_id from sizedefinition s where s.code = ''*'')) and ' ||
                                         '                  ui.finishingmethod_id = plpc.finishingmethod_id ) ' ||
                                         'group by b.code , b.description, ui.product_id, dep.customer_id, ui.sizedefinition_id ' ||
                                         'union all ' ||
                                         'select b.code businessunitcode, count(ui.primaryid), ''Pool outscanned'', ' ||
                                         '(select pr.code from product pr where pr.product_id = ui.product_id) productCode, ' ||
                                         '(select cu.customernumber from customer cu where cu.customer_id = dep.customer_id) customerNo, ' ||
                                         '(select sz.code from sizedefinition sz where sz.sizedefinition_id = ui.sizedefinition_id) sizeCode ' ||
                                         'from uniqueitem ui, distributionpoint dip, department dep, status, businessunit b ' ||
                                         'where ui.distributionpoint_id = dip.distributionpoint_id and ' ||
                                         'dip.department_id = dep.department_id and ui.poolitem = 1 and  ' ||
                                         'ui.status_id = status.status_id and status.code = ''20'' and ' ||
                                         'ui.businessunit_id = b.businessunit_id and ' ||
                                         'not exists (select plpc.productlistpercustomer_id from productlistpercustomer plpc ' ||
                                         '            where dep.customer_id = plpc.customer_id and ' ||
                                         '                  ui.product_id = plpc.product_id and ' ||
                                         '                  (ui.sizedefinition_id = plpc.sizedefinition_id or  ' ||
                                         '                   plpc.sizedefinition_id = (select s.sizedefinition_id from sizedefinition s where s.code = ''*'')) and ' ||
                                         '                  ui.finishingmethod_id = plpc.finishingmethod_id ) ' ||
                                         'group by b.code , b.description, ui.product_id, dep.customer_id, ui.sizedefinition_id ' ||
                                         'order by 1, 5, 4, 6',
                                         'There is no active product list per customer record for the following unique items in circulation!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(51,
                                         'Check if there are missing customer delivery schemes (check in product list per customer, standard delivery line and standard delivery amount)',
                                         'select distinct c.customernumber, c.name, ds.code deliveryschemecode, sdlamnt.day_id' ||
                                         chr(10) ||
                                         'from productlistpercustomer plpc, standarddeliveryline sdl, standarddeliveryamount sdlamnt, deliveryscheme ds, customer c' ||
                                         chr(10) ||
                                         'where plpc.productlistpercustomer_id = sdl.productlistpercustomer_id and' ||
                                         chr(10) || 'sdl.standarddeliveryline_id = sdlamnt.standarddeliveryline_id and' ||
                                         chr(10) || 'sdlamnt.amount != 0 and' || chr(10) ||
                                         'sdl.deliveryscheme_id = ds.deliveryscheme_id and' || chr(10) ||
                                         'plpc.customer_id = c.customer_id and' || chr(10) ||
                                         'not exists (select cds.customer_id from customerdeliveryscheme cds' || chr(10) ||
                                         '            where plpc.customer_id = cds.customer_id and' || chr(10) ||
                                         '                  sdl.deliveryscheme_id = cds.deliveryscheme_id and' ||
                                         chr(10) || '                  sdlamnt.day_id = cds.day_id)',
                                         'There are misssing customer delivery schemes!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(52,
                                         'Check if there are missing customer delivery days.',
                                         'select distinct c.customernumber, c.name, cds.day_id' || chr(10) ||
                                         'from customerdeliveryscheme cds, customer c' || chr(10) ||
                                         'where cds.customer_id = c.customer_id and' || chr(10) ||
                                         'not exists (select cdd.customer_id from customerdeliveryday cdd ' || chr(10) ||
                                         '            where cds.customer_id = cdd.customer_id and cds.day_id = cdd.day_id and cdd.typeofmerchadise = 1)' ||
                                         chr(10) || 'order by 1, 3',
                                         'There are missing customer delivery days!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(53,
                                         'Check if there are missing customer delivery stops.',
                                         'select distinct c.customernumber, c.name, ds.code deliveryschemecode, r.routenumber, cds.day_id, rs.stopnumber' ||
                                         chr(10) ||
                                         'from customerdeliveryscheme cds, routestop rs, route r, customer c, deliveryscheme ds' ||
                                         chr(10) || 'where cds.customer_id = rs.customer_id and' || chr(10) ||
                                         'rs.route_id = r.route_id and' || chr(10) ||
                                         'cds.customer_id = c.customer_id and' || chr(10) ||
                                         'cds.deliveryscheme_id = ds.deliveryscheme_id and' || chr(10) ||
                                         'cds.day_id = r.drivingday_id and' || chr(10) ||
                                         'not exists (select dss.customer_id' || chr(10) ||
                                         '            from deliveryschemesperstop dss, routestop rss' || chr(10) ||
                                         '            where dss.routestop_id = rss.routestop_id and' || chr(10) ||
                                         '                  dss.customer_id = rss.customer_id and' || chr(10) ||
                                         '                  cds.deliveryscheme_id = dss.deliveryscheme_id and' ||
                                         chr(10) || '                  cds.customer_id = rss.customer_id)',
                                         'There are missing customer delivery stops.',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(54,
                                         'If there are product emblems defined check if the fabric has the flag UsedForEmblem checked',
                                         'select p.code productemblemcode, ff.code fabriccode' || chr(10) ||
                                         'from product p, fabric ff' || chr(10) ||
                                         'where p.fabric_id = ff.fabric_id and p.typeofmerchandise = 4 and ' || chr(10) ||
                                         '      ff.usedforemblem = ''N'' ' || chr(10) || 'order by 1, 2 ',
                                         'There are product emblems having UsedForEmblem flag unchecked for the fabric!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(55,
                                         'If there are product emblems defined check if the background color has the flag UsedForEmblem checked',
                                         'select p.code productemblemcode, cc.code colorcode' || chr(10) ||
                                         'from product p, color cc' || chr(10) || 'where p.color_id = cc.color_id and ' ||
                                         chr(10) || '      p.typeofmerchandise = 4 and' || chr(10) ||
                                         '      cc.usedforemblem = ''N'' ',
                                         'There are product emblems having UsedForEmblem flag unchecked for the background color!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(56,
                                         'If there are product emblems defined check if the text color has the flag UsedForEmblem checked',
                                         'select p.code productemblemcode, cc.code colorcode' || chr(10) ||
                                         'from product p, emblemproduct ep, color cc' || chr(10) ||
                                         'where p.product_id = ep.product_id and p.typeofmerchandise = 4 and ' ||
                                         chr(10) || '      ep.textcolor_id = cc.color_id and cc.usedforemblem = ''N'' ' ||
                                         chr(10) || 'order by 1, 2 ',
                                         'There are product emblems having UsedForEmblem flag unchecked for the text color!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(57,
                                         'If there are product emblems defined check if the border color has the flag UsedForEmblem checked',
                                         'select p.code productemblemcode, cc.code colorcode' || chr(10) ||
                                         'from product p, emblemproduct ep, color cc' || chr(10) ||
                                         'where p.product_id = ep.product_id and p.typeofmerchandise = 4 and ' ||
                                         chr(10) || '      ep.bordercolor_id= cc.color_id and cc.usedforemblem = ''N'' ' ||
                                         chr(10) || 'order by 1, 2 ',
                                         'There are product emblems having UsedForEmblem flag unchecked for the border color!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(58,
                                         'Check if there are wearer inventory lines (circinventory > 0) without linked unique items or non unique items',
                                         'select c.customernumber, w.wearernumber, p.code productcode, s.code sizecode, f.code finishingmethodcode,
               sum(wi.circinventory) circInv,
               (select count(n.nonuniqueitem_id)
                             from   nonuniqueitem n
                             where  n.wearerinventory_id = wi.wearerinventory_id and
                                    n.freeitem = ''N'') +
                            (select count(u.uniqueitem_id)
                             from   uniqueitemnonpool u
                             where  u.wearerinventory_id = wi.wearerinventory_id and
                                    u.freeextragarment = ''N'') currentInv
          from wearerinventory wi, weareremployment we, wearer w, customer c, product p, sizedefinition s, finishingmethod f
          where wi.weareremployment_id = we.weareremployment_id and
                we.wearer_id = w.wearer_id and
                w.customer_id = c.customer_id and
                wi.product_id = p.product_id and
                wi.sizedefinition_id = s.sizedefinition_id and
                wi.finishingmethod_id = f.finishingmethod_id
          group by c.customernumber, w.wearernumber, p.code , s.code , f.code , wi.wearerinventory_id
          having sum(wi.circinventory) <> (select count(n.nonuniqueitem_id)
                             from   nonuniqueitem n
                             where  n.wearerinventory_id = wi.wearerinventory_id and
                                    n.freeitem = ''N'') +
                            (select count(u.uniqueitem_id)
                             from   uniqueitemnonpool u
                             where  u.wearerinventory_id = wi.wearerinventory_id and
                                    u.freeextragarment = ''N'')
          order by 1, 2, 3, 4, 5',
                                         'There are wearer inventory lines (circinventory > 0) without linked unique items or non unique items!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(59,
                                         'Check if a sales journal group exists when turnover group used',
                                         'select salesjournalgroup_id, code from salesjournalgroup',
                                         'There is no sales journal group!',
                                         'Y',
                                         'OK',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(60,
                                         'Check if exists records in PLPC with Delayedevenexchange = 7 and Deedeliveryscheme_id = null',
                                         'select c.customernumber, p.code productcode
          from   productlistpercustomer l, customer c, product p
          where  l.deedeliveryscheme_id is null
          and    l.delayedevenexchange = 7
          and    l.customer_id = c.customer_id
          and    l.product_id = p.product_id
          order  by 1, 2',
                                         'Delayedevenexchange = 7 and deedeliveryscheme_id = null is not allowed, for the following customer, product combinations!',
                                         'N',
                                         null,
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(61,
                                         'Check if there are duplicate  rent prices defined in a general price list',
                                         'select g.code pricelist,
         p.code product,
         s.code sizecode,
         f.code finmethod,
         (select i.factorydescription from invoicefrequency i where i.invoicefrequencynumber = gr.invoicefrequencynumber) pricefrequency,
         gr.changesperweek,
         gr.startdate,
         gr.price,
         gr.timestamp,
         (select su.username from systemuser su where su.systemuser_id = gr.systemuser_id) systemuser,
         gr.systemuser_id,
         gr.generalrentprice_id,
         gr.generalpricelist_id,
         gr.product_id,
         gr.sizedefinition_id,
         gr.finishingmethod_id,
         gr.typeofrent,
         gr.invoicefrequencynumber
         from generalrentprice gr,
         generalpricelist g,
         product p,
         sizedefinition s,
         finishingmethod f
         where g.generalpricelist_id = gr.generalpricelist_id
         and p.product_id = gr.product_id
         and s.sizedefinition_id = gr.sizedefinition_id
         and f.finishingmethod_id = gr.finishingmethod_id
         and gr.typeofrent <> 8
         and exists (select 1
         from generalrentprice gr1
         where gr1.generalpricelist_id = gr.generalpricelist_id
         and gr1.product_id = gr.product_id
         and gr1.sizedefinition_id = gr.sizedefinition_id
         and gr1.finishingmethod_id = gr.finishingmethod_id
         and gr1.startdate = gr.startdate
         and gr1.typeofrent = gr.typeofrent
         and gr1.changesperweek = gr.changesperweek
          and gr1.invoicefrequencynumber <> gr.invoicefrequencynumber
          and gr1.generalrentprice_id <> gr.generalrentprice_id)
          order by gr.generalpricelist_id,
          gr.product_id,
          gr.sizedefinition_id,
          gr.finishingmethod_id,
          gr.typeofrent,
          gr.startdate,
          gr.generalrentprice_id',
                                         'There are duplicate rent prices defined for a general price list!',
                                         'N',
                                         'They need to be corrected manually!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(62,
                                         'Check if there are duplicate  customer rent prices defined for a customer',
                                         'select cu.customernumber customer,
         p.code product,
         s.code sizecode,
         f.code finmethod,
         (select i.factorydescription from invoicefrequency i where i.invoicefrequencynumber = cr.invoicefrequencynumber) pricefrequency,
         cr.changesperweek,
         cr.startdate,
         cr.price,
         cr.timestamp,
         (select su.username from systemuser su where su.systemuser_id = cr.systemuser_id) systemuser,
         cr.systemuser_id,
         cr.customerrentprice_id,
         cr.productlistpercustomer_id,
         plpc.customer_id,
         plpc.product_id,
         plpc.sizedefinition_id,
         plpc.finishingmethod_id,
         cr.typeofrent,
         cr.invoicefrequencynumber
         from customerrentprice cr,
         productlistpercustomer plpc,
         product p,
         sizedefinition s,
         finishingmethod f,
         customer cu
         where plpc.productlistpercustomer_id = cr.productlistpercustomer_id
         and p.product_id = plpc.product_id
         and s.sizedefinition_id = plpc.sizedefinition_id
         and f.finishingmethod_id = plpc.finishingmethod_id
         and cu.customer_id = plpc.customer_id
         and cr.typeofrent <> 8
         and exists (select 1
         from customerrentprice cr1
         where cr1.productlistpercustomer_id = cr.productlistpercustomer_id
         and cr1.startdate = cr.startdate
         and cr1.typeofrent = cr.typeofrent
         and cr1.changesperweek = cr.changesperweek
         and cr1.invoicefrequencynumber <> cr.invoicefrequencynumber
         and cr1.customerrentprice_id <> cr.customerrentprice_id)
         order by plpc.productlistpercustomer_id,
         plpc.product_id,
         plpc.sizedefinition_id,
         plpc.finishingmethod_id,
         cr.typeofrent,
         cr.startdate,
         cr.customerrentprice_id',
                                         'There are duplicate rent prices defined for a customer!',
                                         'N',
                                         'They need to be corrected manually!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(63,
                                         'Check if the customer bank accounts are valid (matching the 11-proof)',
                                         'select cu.customernumber, cu.name, cbi.bankaccount, bi.idcode, bi.description, bi.internalidcode
          from customer cu, customerbillinginfo cbi, bankinstitution bi
          where cbi.customer_id = cu.customer_id
          and bi.bankinstitution_id = cbi.bankinstitution_id
          and bi.elevenproof = ''Y''
          and IsElevenProof(cbi.bankaccount) = 0',
                                         'There are bank accounts defined for a customer that do not match the 11-Proof!',
                                         'N',
                                         'They need to be corrected manually!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(64,
                                         'Check if the client bank accounts are valid (matching the 11-proof)',
                                         'select cu.customernumber, cu.name customername, cl.clientnumber, cl.name clientname,
         cbi.bankaccountnumber, bi.idcode, bi.description, bi.internalidcode
         from client cl, clientbillinginfo cbi, customer cu, bankinstitution bi
         where cbi.client_id = cl.client_id
         and cu.customer_id = cl.customer_id
         and bi.bankinstitution_id = cbi.bankinstitution_id
         and bi.elevenproof =''Y''
         and IsElevenProof(cbi.bankaccountnumber) = 0',
                                         'There are bank accounts defined for a client that do not match the 11-Proof!',
                                         'N',
                                         'They need to be corrected manually!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(65,
                                         'Check if the laundry bank accounts are valid (matching the 11-proof)',
                                         'select bi.idcode, bi.description, bi.internalidcode, bi.laundrybankaccount
          from bankinstitution bi
          where bi.elevenproof = ''Y''
          and IsElevenProof(bi.laundrybankaccount) = 0',
                                         'There are laundry bank accounts defined for a bank institution that do not match the 11-Proof!',
                                         'N',
                                         'They need to be corrected manually!',
                                         'Y');
    insertFixedInfoForDBCONSISTENCYCHECK(66,
                                         'Check if STOCKCOUNTSCHEDULE _LINK table is correctly filled',
                                         'select a.code, a.description, a.customer_id, timestamp' || chr(10) ||
                                         'from stockcountschedule a' || chr(10) ||
                                         'where not exists (select x.stockcountschedule_id from stockcountschedule_link x ' ||
                                         chr(10) ||
                                         '                  where x.stockcountschedule_id = a.stockcountschedule_id)' ||
                                         chr(10) || 'order by 1' || chr(9) || '' || chr(9) || '' || chr(9) || '' ||
                                         chr(9) || '' || chr(9) || '' || chr(9) || '' || chr(9) || '' || chr(9) || '' ||
                                         chr(9) || '',
                                         'There are records in STOCKCOUNTSCHEDULE table with no related record in STOCKCOUNTSCHEDULE_LINK table!',
                                         'N',
                                         null,
                                         'Y');

 commit;
  exception
    when others then
      rollback;
      write_log('Error at DBCONSISTENCYCHECK: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDBCONSISTENCYCHECK;

  procedure insertFixedInfoForDBCHECKONSYSTEMSETTING(fp_dbconsistencycheck_id dbcheckonsystemsetting.dbconsistencycheck_id%type,
                                                     fp_name                  dbcheckonsystemsetting.name%type,
                                                     fp_value                 dbcheckonsystemsetting.value%type,
                                                     fp_typeofvalue           dbcheckonsystemsetting.typeofvalue%type) is
    lv_name        dbcheckonsystemsetting.name%type;
    lv_value       dbcheckonsystemsetting.value%type;
    lv_typeofvalue dbcheckonsystemsetting.typeofvalue%type;
  begin
    select d.name, d.value, d.typeofvalue
      into lv_name, lv_value, lv_typeofvalue
      from dbcheckonsystemsetting d
     where d.dbconsistencycheck_id = fp_dbconsistencycheck_id
     and d.name = fp_name;
    if (lv_name <> fp_name) then
      update dbcheckonsystemsetting d
         set d.name = fp_name
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id
       and d.name = fp_name;
    end if;
    if (fp_value <> lv_value) then
      update dbcheckonsystemsetting d
         set d.value = fp_value
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id
       and d.name = fp_name;
    end if;
    if (lv_typeofvalue <> fp_typeofvalue) then
      update dbcheckonsystemsetting d
         set d.typeofvalue = fp_typeofvalue
       where d.dbconsistencycheck_id = fp_dbconsistencycheck_id
       and d.name = fp_name;
    end if;
  exception
    when no_data_found then
      insert into dbcheckonsystemsetting
        (dbconsistencycheck_id, name, value, typeofvalue)
      values
        (fp_dbconsistencycheck_id, fp_name, fp_value, fp_typeofvalue);
  end insertFixedInfoForDBCHECKONSYSTEMSETTING;
  procedure fixedInfoForDBCHECKONSYSTEMSETTING is
  begin
    insertFixedInfoForDBCHECKONSYSTEMSETTING(21, 'TAXDEFINITION', 'EU', 'S');
    insertFixedInfoForDBCHECKONSYSTEMSETTING(21, 'USETURNOVERGROUP', 'Y', 'B');
    insertFixedInfoForDBCHECKONSYSTEMSETTING(26, 'TAXDEFINITION', 'EU', 'S');
    insertFixedInfoForDBCHECKONSYSTEMSETTING(30, 'USETURNOVERGROUP', 'Y', 'B');
    insertFixedInfoForDBCHECKONSYSTEMSETTING(33, 'TAXDEFINITION', 'EU', 'S');
    insertFixedInfoForDBCHECKONSYSTEMSETTING(33, 'USETURNOVERGROUP', 'Y', 'B');
    insertFixedInfoForDBCHECKONSYSTEMSETTING(41, 'ALLOWDUPLICATECPL', 'N', 'B');
  commit;
    exception
      when others then
       rollback;
      write_log('Error at DBCHECKONSYSTEMSETTING: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDBCHECKONSYSTEMSETTING;

  procedure insertFixedInfoForFORMLAYOUT(fp_formtype      formlayout.formtype%type,
                                         fp_code          formlayout.code%type,
                                         fp_reportname    formlayout.reportname%type,
                                         fp_defaultlayout formlayout.defaultlayout%type) is
  begin
    select f.formlayout_id
      into id
      from formlayout f
     where f.code = fp_code
       and f.formtype = fp_formtype;
  exception
    when no_data_found then
      insert into FORMLAYOUT
        (formlayout_id, formtype, code, systemuser_id, reportname, timestamp, defaultlayout)
      values
        (seq_formlayout.nextval, fp_formtype, fp_code, systemUserID, fp_reportname, sysdate, fp_defaultlayout);
  end insertFixedInfoForFORMLAYOUT;

  procedure fixedInfoForFORMLAYOUT is
  begin
    insertFixedInfoForFORMLAYOUT('DC', '1', 'Standard layout', 'Y');
    insertFixedInfoForFORMLAYOUT('IC', '1', 'Standard layout', 'Y');
    insert into formlayout_desc
      (formlayout_id, language_id, description, systemuser_id, timestamp)
      select f.formlayout_id, l.language_id, f.reportname, systemUserID, sysdate
        from formlayout f, languages l
       where l.translatedescription = 'Y'
       and f.reportname is not null
         and not exists (select 1
                from formlayout_desc fd
               where fd.formlayout_id = f.formlayout_id
                 and fd.language_id = l.language_id);
   commit;
     exception
       when others then
      rollback;
      write_log('Error at FORMLAYOUT: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForFORMLAYOUT;

  procedure insertFixedInfoForINVOICEAPPENDIXDEFINITION(fp_invoiceappendixdefinition_id
                                                                     invoiceappendixdefinition.invoiceappendixdefinition_id%type,
                                                        fp_invoiceappendixtype  invoiceappendixdefinition.invoiceappendixtype%type,
                                                        fp_description          invoiceappendixdefinition.description%type,
                                                        fp_reportname           invoiceappendixdefinition.reportname%type,
                                                        fp_manual               invoiceappendixdefinition.manual%type,
                                                        fp_directinvoice        invoiceappendixdefinition.directinvoice%type,
                                                        fp_residentialservices  invoiceappendixdefinition.residentialservices%type,
                                                        fp_otherservices        invoiceappendixdefinition.otherservices%type,
                                                        fp_customercode         invoiceappendixdefinition.customercode%type,
                                                        fp_module               invoiceappendixdefinition.module%type,
                                                        fp_reporttype           invoiceappendixdefinition.reporttype%type) is

  begin
    select i.invoiceappendixdefinition_id
      into id
      from invoiceappendixdefinition i
     where i.invoiceappendixdefinition_id = fp_invoiceappendixdefinition_id;
  exception
    when no_data_found then
      insert into invoiceappendixdefinition
        (invoiceappendixdefinition_id, invoiceappendixtype, description, reportname, customercode, module, manual,
         directinvoice, otherservices, residentialservices, systemuser_id, timestamp, reporttype)
      values
        (fp_invoiceappendixdefinition_id, fp_invoiceappendixtype, fp_description, fp_reportname, fp_customercode,
         fp_module, fp_manual, fp_directinvoice, fp_otherservices, fp_residentialservices, systemUserID, sysdate,fp_reporttype);
  end insertFixedInfoForINVOICEAPPENDIXDEFINITION;

  procedure fixedInfoForINVOICEAPPENDIXDEFINITION is
  begin
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(1, 1, 'Cost report', 'CostReport.rpt', 'Y', 'Y', 'Y', 'Y', null, null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(2,
                                                2,
                                                'Condensed cost report',
                                                'CondensedCostReport.rpt',
                                                'Y',
                                                'Y',
                                                'Y',
                                                'Y',
                                                null,
                                                null,
                                                0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(3,
                                                3,
                                                'Note numbers',
                                                'NoteNumbersAppendix.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(4,
                                                4,
                                                'Garment charges',
                                                'GarmentCharges.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(5,
                                                5,
                                                'Period report pieces',
                                                'PeriodReportDeliveredArticles.rpt',
                                                'N',
                                                'N',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(6,
                                                6,
                                                'Period report soil weights',
                                                'PeriodReportWeights.rpt',
                                                'N',
                                                'N',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(7,
                                                7,
                                                'Period report clean weights',
                                                'PeriodReportWeights.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(8,
                                                8,
                                                'Month report pieces',
                                                'MonthReportDeliveredArticles.rpt',
                                                'N',
                                                'N',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(9,
                                                9,
                                                'Month report soil weights',
                                                'MonthReportWeights.rpt',
                                                'N',
                                                'N',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(10,
                                                10,
                                                'Month report clean weights',
                                                'MonthReportWeights.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(11,
                                                11,
                                                'Delivery note (no prices)',
                                                'DeliveryNoteAppendix.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(12,
                                                12,
                                                'Delivery note (with prices)',
                                                'DeliveryNoteAppendix.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(13,
                                                13,
                                                'To be returned garments',
                                                'ToBeReturnedGarmentsAppendix.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(14,
                                                14,
                                                'Week delivered products per customer',
                                                'WeekReportDeliveredProducts.rpt',
                                                'N',
                                                'N',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(15,
                                                15,
                                                'Week delivered prod. per consumpt. point',
                                                'WeekReportDeliveredProducts.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(16,
                                                16,
                                                'Detailed stockroom transactions',
                                                'StockroomTransactions.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(17,
                                                17,
                                                'Cost report per kontonumber',
                                                'KontoNumberAppendix.rpt',
                                                'Y',
                                                'Y',
                                                'N',
                                                'Y',
                                                'BET',
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(18,
                                                18,
                                                'Acceptgiro',
                                                'AppendixAcceptgiro_CH.rpt',
                                                'Y',
                                                'Y',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(19,
                                                19,
                                                'Additional specification',
                                                'AdditionalSpecification.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(20,
                                                20,
                                                'Compressed cost report',
                                                'CompressedCostReport.rpt',
                                                'Y',
                                                'Y',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(21,
                                                21,
                                                'Unemployed wearers',
                                                '(Un)EmployedWearersAppendix.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(22,
                                                22,
                                                'Costs specifications per wearer',
                                                'CostSpecificationPerWearer.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(23,
                                                23,
                                                'Compressed delivery note with prices',
                                                'CompressedDeliveryNotesWithPrices.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'POINTOFSALE',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(24,
                                                24,
                                                'Weekly summary delivery Angelica',
                                                'WeeklySummaryReport.rpt',
                                                'Y',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'RPTWEEKLYSUMMARY',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(25,
                                                25,
                                                'Costs specification per client',
                                                'CostsSpecificationPerClient.rpt',
                                                'N',
                                                'Y',
                                                'Y',
                                                'N',
                                                null,
                                                'PWBBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(26,
                                                26,
                                                'Sales Order Discount',
                                                'SalesOrderDiscount.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(27,
                                                27,
                                                'Consignment Notes',
                                                'InvoiceAppendixConsignmentNotes.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                'WMA',
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(28,
                                                28,
                                                'Garment charges per cost center',
                                                'GarmentChargesCostCenter.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(29,
                                                29,
                                                'Weighing Details',
                                                'InvoiceAppendixWeighingDetails.rpt',
                                                'N',
                                                'Y',
                                                'Y',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(30,
                                                30,
                                                'CSV Export File',
                                                'CSV Export File',
                                                'Y',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'EXPORTTOCSV',2);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(31,
                                                31,
                                                'Cost Specification Per Cost Center',
                                                'CostSpecificationPerCostCenter.rpt',
                                                'Y',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'CUSTOMERCOSTSPEC',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(32,
                                                32,
                                                'Cost Spec Per Customer Per Cost Spec',
                                                'CostSpecificationPerCustomerPerCostSpec.rpt',
                                                'Y',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'CUSTOMERCOSTSPEC',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(33,
                                                33,
                                                'Wearer changes',
                                                'AppendixWearerChanges.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'CUSTOMERAUDITREPORTS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(34,
                                                34,
                                                'Condensed Loss charges/credit pool items',
                                                'CondensedInvoiceAppendixLossForPool.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'LOSSFORPOOL',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(35,
                                                35,
                                                'Loss charges / credits for pool items',
                                                'InvoiceAppendixLossForPool.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'LOSSFORPOOL',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(36,
                                                36,
                                                'Client.csv',
                                                'Clientcsv',
                                                'N',
                                                'N',
                                                'Y',
                                                'N',
                                                null,
                                                'EXPORTTOCSV',2);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(37,
                                                37,
                                                'CostsPerWearer.CSV',
                                                'CostsPerWearerCSV',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'WEARERINVOICECATEGORY',2);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(38,
                                                38,
                                                'POD Numbers',
                                                'InvoiceAppendixPODNumbers.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'OMDINTERFACE',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(39,
                                                39,
                                                'POD Numbers with Notes',
                                                'InvoiceAppendixPODNoteNumbers.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'OMDINTERFACE',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(40,
                                                40,
                                                'POD Numbers with Notes and Prices',
                                                'InvoiceAppendixPODNoteNumbersPrices.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'OMDINTERFACE',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(41,
                                                41,
                                                'Loss for Pool per Product',
                                                'InvoiceAppendixLossForPoolPerProduct.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'LOSSFORPOOL',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(42,
                                                42,
                                                'Loss for Pool per Product and Department',
                                                'InvoiceAppendixLossForPoolPerProductDept.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'LOSSFORPOOL',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(43,
                                                43,
                                                'Loss for Pool per Product and Cons Point',
                                                'InvoiceAppendixLossForPoolPerProductCons.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'LOSSFORPOOL',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(44,
                                                44,
                                                'Garment Charges Wearer Product',
                                                'GarmentChargesWearerProduct.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'BKLBASIS',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(45,
                                                45,
                                                'Delivered Products',
                                                'DeliveredProducts.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                null,0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(46,
                                                46,
                                                'Cost Specification per dept individual',
                                                'DPCostSpecificationIndividual.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'DPCOSTSPECIFICATION',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(47,
                                                47,
                                                'Cost Specification per dept consolidated',
                                                'DPCostSpecificationConsolidated.rpt',
                                                'N',
                                                'Y',
                                                'N',
                                                'Y',
                                                null,
                                                'DPCOSTSPECIFICATION',0);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(48,
                                                48,
                                                'WashCostsPerClient.csv',
                                                'WashCostsPerClientCSV',
                                                'N',
                                                'N',
                                                'Y',
                                                'N',
                                                null,
                                                'PWBBASIS',2);
    insertFixedInfoForINVOICEAPPENDIXDEFINITION(49,
                                                49,
                                                'Container Rent',
                                                'ContainerRentAppendix.rpt',
                                                'N',
                                                'N',
                                                'N',
                                                'Y',
                                                null,
                                                'CONTAINERBILLING',0);

commit;
  exception
    when others then
      rollback;
      write_log('Error at INVOICEAPPENDIXDEFINITION: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForINVOICEAPPENDIXDEFINITION;

  procedure insertFixedInfoForSTOCKTYPE(fp_code               stocktype.code%type,
                                        fp_factorydescription stocktype.factorydescription%type,
                                        fp_active             stocktype.active%type) is
  begin
    select count(1)
    into id
    from stocktype s
    where s.code = fp_code;
    if(id = 0) then
      insert into stocktype
        (stocktype_id, code, factorydescription, systemuser_id, timestamp, active)
      values
        (seq_stocktype.nextval, fp_code, fp_factorydescription, systemUserID, sysdate, fp_active);
     end if;
  end insertFixedInfoForSTOCKTYPE;

  procedure fixedInfoForSTOCKTYPE is
  begin
    insertFixedInfoForSTOCKTYPE('01', 'New', 'Y');
    insertFixedInfoForSTOCKTYPE('02', 'Used', 'Y');
    insertFixedInfoForSTOCKTYPE('03', 'Defect', 'Y');
    insertFixedInfoForSTOCKTYPE('04', 'Circulation', 'Y');
    insertFixedInfoForSTOCKTYPE('05', 'Service Truck', 'Y');
    insertFixedInfoForSTOCKTYPE('06', 'Ragged', 'Y');
    insertFixedInfoForSTOCKTYPE('07', 'Sample', 'Y');
    insert into stocktype_desc
      (stocktype_id, language_id, description, systemuser_id, timestamp)
      select s.stocktype_id, l.language_id, s.code, systemUserID, sysdate
        from stocktype s, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from stocktype_desc sd
               where sd.stocktype_id = s.stocktype_id
                 and sd.language_id = l.language_id);

commit;
  exception
    when others then
      rollback;
      write_log('Error at STOCKTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForSTOCKTYPE;
  procedure insertFixedInfoForLEDGERACCNTTYPE(fp_code               ledgeraccnttype.code%type,
                                              fp_factorydescription ledgeraccnttype.factorydescription%type,
                                              fp_active             ledgeraccnttype.active%type) is
    lv_factorydescription ledgeraccnttype.factorydescription%type;
    lv_active             ledgeraccnttype.active%type;
  begin
    select l.factorydescription, l.active
      into lv_factorydescription, lv_active
      from ledgeraccnttype l
     where l.code = fp_code;
  exception
    when no_data_found then
      insert into ledgeraccnttype
        (ledgeraccnttype_id, code, factorydescription, systemuser_id, timestamp, active)
      values
        (seq_ledgeraccnttype.nextval, fp_code, fp_factorydescription, systemUserID, sysdate, fp_active);
  end insertFixedInfoForLEDGERACCNTTYPE;

  procedure fixedInfoForLEDGERACCNTTYPE is
  begin
    insertFixedInfoForLEDGERACCNTTYPE('WESV', 'Cost of material goods sold', 'Y');
    insertFixedInfoForLEDGERACCNTTYPE('GWG', 'Cost of material low value goods', 'Y');
    insertFixedInfoForLEDGERACCNTTYPE('ABW', 'Devaluation Stock', 'Y');
    insertFixedInfoForLEDGERACCNTTYPE('BEST', 'General Stock', 'Y');
    insertFixedInfoForLEDGERACCNTTYPE('WESS', 'Cost of material service contracts', 'Y');
    insertFixedInfoForLEDGERACCNTTYPE('WESR', 'Cost of material spare parts', 'Y');
    insert into ledgeraccnttype_desc
      (ledgeraccnttype_id, language_id, description, systemuser_id, timestamp)
      select ledgeraccnttype_id, l.language_id, factorydescription, lt.systemuser_id, lt.timestamp
        from ledgeraccnttype lt, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from ledgeraccnttype_desc ld
               where ld.ledgeraccnttype_id = lt.ledgeraccnttype_id);
    commit;
      exception
        when others then
          rollback;
          write_log('Error at LEDGERACCNTTYPE: ' || sqlerrm, 3);
          fp_error := 1;
  end fixedInfoForLEDGERACCNTTYPE;

  procedure insertFixedInfoForWEBMENUGROUP(fp_sequencenumber     webmenugroup.sequencenumber%type,
                                           fp_factorydescription webmenugroup.factorydescription%type) is
    lv_factorydescription webmenugroup.factorydescription%type;
  begin
    select w.factorydescription
      into lv_factorydescription
      from webmenugroup w
     where w.sequencenumber = fp_sequencenumber;
    if (lv_factorydescription <> fp_factorydescription) then
      update webmenugroup w
         set w.factorydescription = fp_factorydescription, w.systemuser_id = systemUserID, w.timestamp = sysdate
       where w.sequencenumber = fp_sequencenumber;
    end if;
  exception
    when no_data_found then
      insert into webmenugroup
        (webmenugroup_id, sequencenumber, factorydescription, systemuser_id, timestamp)
      values
        (seq_webmenugroup.nextval, fp_sequencenumber, fp_factorydescription, systemUserID, sysdate);
  end insertFixedInfoForWEBMENUGROUP;

  procedure fixedInfoForWEBMENUGROUP is
  begin
    insertFixedInfoForWEBMENUGROUP(1, 'Linen');
    insertFixedInfoForWEBMENUGROUP(2, 'Linen Reports');
    insertFixedInfoForWEBMENUGROUP(3, 'Garments');
    insertFixedInfoForWEBMENUGROUP(4, 'Garment Reports');
    insertFixedInfoForWEBMENUGROUP(5, 'Cost Information');
    insertFixedInfoForWEBMENUGROUP(6, 'Cost Reports');
    insertFixedInfoForWEBMENUGROUP(7, 'Financial Information');
    insertFixedInfoForWEBMENUGROUP(8, 'Delivery Documents');
    insertFixedInfoForWEBMENUGROUP(9, 'Main');
    insertFixedInfoForWEBMENUGROUP(10, 'Contacts');
    insert into webmenugroup_desc
      (webmenugroup_id, language_id, description, systemuser_id, timestamp)
      select wmg.webmenugroup_id, l.language_id, wmg.factorydescription, 1, sysdate
        from webmenugroup wmg, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from webmenugroup_desc wd
               where wd.webmenugroup_id = wmg.webmenugroup_id
                 and wd.language_id = l.language_id);
      commit;
        exception
          when others then
            rollback;
            write_log('Error at WEBMENUGROUP: ' || sqlerrm, 3);
            fp_error := 1;
  end fixedInfoForWEBMENUGROUP;

  procedure insertFixedInfoForPOSPLITCRITERIONTYPE(fp_posplitcriteriontype_id posplitcriteriontype.posplitcriteriontype_id%type,
                                                   fp_itemtype                posplitcriteriontype.itemtype%type,
                                                   fp_code                    posplitcriteriontype.code%type,
                                                   fp_factorydescription      posplitcriteriontype.factorydescription%type,
                                                   fp_active                  posplitcriteriontype.active%type) is
    lv_itemtype           posplitcriteriontype.itemtype%type;
    lv_factorydescription posplitcriteriontype.factorydescription%type;
  begin
    select p.itemtype, p.factorydescription
      into lv_itemtype, lv_factorydescription
      from posplitcriteriontype p
     where p.posplitcriteriontype_id = fp_posplitcriteriontype_id;
    if (lv_itemtype <> fp_itemtype) then
      update posplitcriteriontype p
         set p.itemtype = fp_itemtype, p.systemuser_id = systemUserID, p.timestamp = sysdate
       where p.posplitcriteriontype_id = fp_posplitcriteriontype_id;
    end if;
    if (lv_factorydescription <> fp_factorydescription) then
      update posplitcriteriontype p
         set p.factorydescription = fp_factorydescription, p.systemuser_id = systemUserID, p.timestamp = sysdate
       where p.posplitcriteriontype_id = fp_posplitcriteriontype_id;
    end if;
  exception
    when no_data_found then
      insert into posplitcriteriontype
        (posplitcriteriontype_id, itemtype, code, factorydescription, systemuser_id, timestamp, active)
      values
        (fp_posplitcriteriontype_id, fp_itemtype, fp_code, fp_factorydescription, systemUserID, sysdate, fp_active);
  end insertFixedInfoForPOSPLITCRITERIONTYPE;

  procedure fixedInfoForPOSPLITCRITERIONTYPE is
  begin
    insertFixedInfoForPOSPLITCRITERIONTYPE(1, 2, 'WOCBU', 'Work Order Creation Business Unit', 'N');
    insertFixedInfoForPOSPLITCRITERIONTYPE(2, 2, 'WOCUSTNO', 'Work Order Customer Number', 'N');
    insertFixedInfoForPOSPLITCRITERIONTYPE(3, 2, 'WORC', 'Work Order Reason Code', 'N');
    insertFixedInfoForPOSPLITCRITERIONTYPE(4, 2, 'WOEXBY', 'Work Order Executed By', 'Y');
    insertFixedInfoForPOSPLITCRITERIONTYPE(5, 2, 'WOREQDEL', 'Work Order Requested Delivery Date', 'Y');
    insertFixedInfoForPOSPLITCRITERIONTYPE(6, 2, 'WOPHASEDDEL', 'Work Order Phased Delivery Allowed', 'Y');
    commit;
        exception
          when others then
            rollback;
            write_log('Error at POSPLITCRITERIONTYPE: ' || sqlerrm, 3);
     fp_error := 1;
  end fixedInfoForPOSPLITCRITERIONTYPE;

  procedure insertFixedInfoForUHFREADERBRAND(fp_uhfreaderbrand_id uhfreaderbrand.uhfreaderbrand_id%type,
                                             fp_brandnumber       uhfreaderbrand.brandnumber%type,
                                             fp_name              uhfreaderbrand.name%type) is
    lv_brandnumber uhfreaderbrand.brandnumber%type;
    lv_name        uhfreaderbrand.name%type;
  begin
    select u.brandnumber, u.name
      into lv_brandnumber, lv_name
      from uhfreaderbrand u
     where u.uhfreaderbrand_id = fp_uhfreaderbrand_id;
    if (lv_brandnumber <> fp_brandnumber) then
      update uhfreaderbrand u
         set u.brandnumber = fp_brandnumber, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfreaderbrand_id = fp_uhfreaderbrand_id;
    end if;
    if (lv_name <> fp_name) then
      update uhfreaderbrand u
         set u.name = fp_name, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfreaderbrand_id = fp_uhfreaderbrand_id;
    end if;
  exception
    when no_data_found then
      insert into uhfreaderbrand
        (uhfreaderbrand_id, brandnumber, name, systemuser_id, timestamp)
      values
        (fp_uhfreaderbrand_id, fp_brandnumber, fp_name, systemUserID, sysdate);
  end insertFixedInfoForUHFREADERBRAND;

  procedure fixedInfoForUHFREADERBRAND is
  begin
    insertFixedInfoForUHFREADERBRAND(1, 25882, 'Impinj');
    insertFixedInfoForUHFREADERBRAND(2, 38416, 'Nordic');
    insertFixedInfoForUHFREADERBRAND(3, 26554, 'M6');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at UHFREADERBRAND: ' || sqlerrm, 3);
    fp_error := 1;
  end fixedInfoForUHFREADERBRAND;

  procedure insertFixedInfoForUHFREADERMODEL(fp_uhfreadermodel_id uhfreadermodel.uhfreadermodel_id%type,
                                             fp_modelnumber       uhfreadermodel.modelnumber%type,
                                             fp_name              uhfreadermodel.name%type,
                                             fp_uhfreaderbrand_id uhfreadermodel.uhfreaderbrand_id%type,
                                             fp_maxsensitivity    uhfreadermodel.maxsensitivity%type) is
    lv_modelnumber       uhfreadermodel.modelnumber%type;
    lv_name              uhfreadermodel.name%type;
    lv_maxsensitivity    uhfreadermodel.maxsensitivity%type;
  begin
    select u.modelnumber, u.name, u.maxsensitivity
      into lv_modelnumber, lv_name, lv_maxsensitivity
      from uhfreadermodel u
     where u.uhfreadermodel_id = fp_uhfreadermodel_id;
    if (lv_modelnumber <> fp_modelnumber) then
      update uhfreadermodel u
         set u.modelnumber = fp_modelnumber, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfreadermodel_id = fp_uhfreadermodel_id;
    end if;
    if (lv_name <> fp_name) then
      update uhfreadermodel u
         set u.name = fp_name, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfreadermodel_id = fp_uhfreadermodel_id;
    end if;
    if (lv_maxsensitivity <> fp_maxsensitivity) then
      update uhfreadermodel u
         set u.maxsensitivity = fp_maxsensitivity, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfreadermodel_id = fp_uhfreadermodel_id;
    end if;
  exception
    when no_data_found then
      insert into uhfreadermodel
        (uhfreadermodel_id, modelnumber, name, uhfreaderbrand_id, maxsensitivity, systemuser_id, timestamp)
      values
        (fp_uhfreadermodel_id, fp_modelnumber, fp_name, fp_uhfreaderbrand_id, fp_maxsensitivity, systemUserID, sysdate);
  end insertFixedInfoForUHFREADERMODEL;

  procedure fixedInfoForUHFREADERMODEL is
  begin
    insertFixedInfoForUHFREADERMODEL(1, 1000000, 'R1000', 1, -80);
    insertFixedInfoForUHFREADERMODEL(2, 1005000, 'R1005', 1, -80);
    insertFixedInfoForUHFREADERMODEL(3, 2001001, 'R220', 1, -80);
    insertFixedInfoForUHFREADERMODEL(4, 2001002, 'R420', 1, -80);
    insertFixedInfoForUHFREADERMODEL(5, 2001003, 'R640', 1, -80);
    insertFixedInfoForUHFREADERMODEL(6, 1, '813-S1A', 2, -80);
    insertFixedInfoForUHFREADERMODEL(7, 6, 'M6', 3, -80);
    insertFixedInfoForUHFREADERMODEL(8, 2001009, 'R120', 1, -80);
    insertFixedInfoForUHFREADERMODEL(9, 2001052, 'R700', 1, -80);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at UHFREADERMODEL: ' || sqlerrm, 3);
    fp_error := 1;
  end fixedInfoForUHFREADERMODEL;

  procedure insertFixedInfoForUHFREGION(fp_uhfregion_id         uhfregion.uhfregion_id%type,
                                        fp_name                 uhfregion.name%type,
                                        fp_maxpower             uhfregion.maxpower%type,
                                        fp_disablefixedfreqmode uhfregion.disablefixedfreqmode%type,
                                        fp_maxtotalpower        uhfregion.maxtotalpower%type) is
    lv_name                 uhfregion.name%type;
    lv_maxpower             uhfregion.maxpower%type;
    lv_disablefixedfreqmode uhfregion.disablefixedfreqmode%type;
    lv_maxtotalpower        uhfregion.maxtotalpower%type;
  begin
    select u.name, u.maxpower, u.disablefixedfreqmode, u.maxtotalpower
      into lv_name, lv_maxpower, lv_disablefixedfreqmode, lv_maxtotalpower
      from uhfregion u
     where u.uhfregion_id = fp_uhfregion_id;
    if (lv_name <> fp_name) then
      update uhfregion u
         set u.name = fp_name, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfregion_id = fp_uhfregion_id;
    end if;
    if (lv_maxpower <> fp_maxpower) then
      update uhfregion u
         set u.maxpower = fp_maxpower, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfregion_id = fp_uhfregion_id;
    end if;
    if (lv_disablefixedfreqmode <> fp_disablefixedfreqmode) then
      update uhfregion u
         set u.disablefixedfreqmode = fp_disablefixedfreqmode, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfregion_id = fp_uhfregion_id;
    end if;
    if (lv_maxtotalpower <> fp_maxtotalpower) then
      update uhfregion u
         set u.maxtotalpower = fp_maxtotalpower, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfregion_id = fp_uhfregion_id;
    end if;
  exception
    when no_data_found then
     begin
      insert into uhfregion
        (uhfregion_id, name, maxpower, systemuser_id, timestamp, disablefixedfreqmode, maxtotalpower)
      values
        (fp_uhfregion_id, fp_name, fp_maxpower, systemUserID, sysdate, fp_disablefixedfreqmode, fp_maxtotalpower);
      exception
        when dup_val_on_index then
          begin
            write_log('Error at uhfregion: ' || sqlerrm, 3);
            fp_error := 1;
          end;
      end;
  end insertFixedInfoForUHFREGION;

  procedure fixedInfoForUHFREGION is
  begin
    insertFixedInfoForUHFREGION(0, ' Unspecified', 32.5, 'N', 33.0);
    insertFixedInfoForUHFREGION(1, 'US_FCC_Part_15', 32.5, 'Y', 36.0);
    insertFixedInfoForUHFREGION(2, 'ETSI_302_208', 30, 'N', 33.0);
    insertFixedInfoForUHFREGION(3, 'ETSI_300_220', 32.5, 'N', 33.0);
    insertFixedInfoForUHFREGION(4, 'Australia_LIPD_1W', 32.5, 'Y', 30.0);
    insertFixedInfoForUHFREGION(5, 'Australia_LIPD_4W', 32.5, 'Y', 36.0);
    insertFixedInfoForUHFREGION(6, 'Japan_ARIB_STD_T89', 10, 'N', 36.0);
    insertFixedInfoForUHFREGION(7, 'Hong_Kong_OFTA_1049', 32.5, 'N', 36.0);
    insertFixedInfoForUHFREGION(8, 'Taiwan_DGT_LP0002', 32.5, 'N', 30.0);
    insertFixedInfoForUHFREGION(9, 'Korea_MIC_Article_5_2', 32.5, 'N', 36.0);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at UHFREGION: ' || sqlerrm, 3);
    fp_error := 1;
  end fixedInfoForUHFREGION;

  procedure insertFixedInfoForUHFANTENNAMODEL(fp_uhfantennamodel_id uhfantennamodel.uhfantennamodel_id%type,
                                              fp_name               uhfantennamodel.name%type,
                                              fp_gain               uhfantennamodel.gain%type) is
    lv_name uhfantennamodel.name%type;
    lv_gain uhfantennamodel.gain%type;
  begin
    select u.name, u.gain
      into lv_name, lv_gain
      from uhfantennamodel u
     where u.uhfantennamodel_id = fp_uhfantennamodel_id;
    if (lv_name <> fp_name) then
      update uhfantennamodel u
         set u.name = fp_name, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfantennamodel_id = fp_uhfantennamodel_id;
    end if;
    if (fp_gain <> lv_gain) then
      update uhfantennamodel u
         set u.gain = fp_gain, u.systemuser_id = systemUserID, u.timestamp = sysdate
       where u.uhfantennamodel_id = fp_uhfantennamodel_id;
    end if;
  exception
    when no_data_found then
      insert into uhfantennamodel
        (uhfantennamodel_id, name, gain, systemuser_id, timestamp)
      values
        (fp_uhfantennamodel_id, fp_name, fp_gain, systemUserID, sysdate);
  end insertFixedInfoForUHFANTENNAMODEL;

  procedure fixedInfoForUHFANTENNAMODEL is
  begin
    insertFixedInfoForUHFANTENNAMODEL(1, 'Laird Technologies S9028PC L/R', 6);
    insertFixedInfoForUHFANTENNAMODEL(2, 'Laird Technologies S8658PC L/R ', 3.85);
    insertFixedInfoForUHFANTENNAMODEL(3, 'Impinj IPJ-A0301-USA (Mini-Guardrail)', 15);
    insertFixedInfoForUHFANTENNAMODEL(4, 'Impinj IPJ-A0310-USA (Threshold-T Antenna) ', 6);
    insertFixedInfoForUHFANTENNAMODEL(5, 'Impinj  IPJ-A0400-USA, CSL CS-777-2 (Brickyard', 2);
    insertFixedInfoForUHFANTENNAMODEL(6, 'Impinj  IPJ-A0400-EU1, CSL CS-777-1 (Brickyard) ', 0);
    insertFixedInfoForUHFANTENNAMODEL(7, 'Impinj  IPJ-A0401-USA or IPJ-A0402-USA (both Guardwall)', 6);
    insertFixedInfoForUHFANTENNAMODEL(8, 'MA/COM MAAN-000246-FL1 integrated RFID floor-mounted stand', 6);
    insertFixedInfoForUHFANTENNAMODEL(9, 'MA/COM MAAN-000246-WL1 integrated RFID wall-mounted stand', 6);
    insertFixedInfoForUHFANTENNAMODEL(10, 'MTI MT-262006/TLH  or MT-262006/TRH', 6);
    insertFixedInfoForUHFANTENNAMODEL(11, 'MTI MT-262013/NLH or MT-262013/NRH', 4.5);
    insertFixedInfoForUHFANTENNAMODEL(12, 'MTI MT-262013/TLH or MT-262013/TRH', 4.5);
    insertFixedInfoForUHFANTENNAMODEL(13, 'MTI MT-242032/NLH or MT-242032/NRH', 1.85);
    insertFixedInfoForUHFANTENNAMODEL(14, 'Sensormatic Electronics Corp.  IDANT20CNA25 with 25 ft cable', 5.5);
    insertFixedInfoForUHFANTENNAMODEL(15, 'Sensormatic Electronics Corp.  IDANT10CNA25 with 25 ft cable', 3.5);
    insertFixedInfoForUHFANTENNAMODEL(16, 'Sensormatic Electronics Corp.  IDANT10CNA25 with 6 ft cable', 5.4);
    insertFixedInfoForUHFANTENNAMODEL(17, 'Sensormatic Electronics Corp.  IDANT10CEU25 with 6 ft cable', 3.25);
    insertFixedInfoForUHFANTENNAMODEL(18, 'Datamars UHF Drop Chute', 0);
    insertFixedInfoForUHFANTENNAMODEL(19, 'Impinj IPJ-A0311-EU1 (Threshold-FS Antenna)', 5);
    insertFixedInfoForUHFANTENNAMODEL(20, 'TagSys SRU500NF Internal Antenna', 0);
    insertFixedInfoForUHFANTENNAMODEL(21, 'Times-7 SlimLine A7030C FCC', 6);
    insertFixedInfoForUHFANTENNAMODEL(22, 'Times-7 SlimLine A7030C ETSI', 5);
    insertFixedInfoForUHFANTENNAMODEL(23, 'Times-7 SlimLine A6034', 9);
    insertFixedInfoForUHFANTENNAMODEL(24, 'Times-7 SlimLine A6031', 4);
    insertFixedInfoForUHFANTENNAMODEL(25, 'MTI MT-242027/NRH or MT-242027/NLH', 8.5);
    insertFixedInfoForUHFANTENNAMODEL(26, 'Times-7 SlimLine A8060', 5);
    insertFixedInfoForUHFANTENNAMODEL(27, 'Times-7 GroundAntenna A6590C', 9);
    insertFixedInfoForUHFANTENNAMODEL(28, 'Times-7 SlimLine A6034S', 9);
    insertFixedInfoForUHFANTENNAMODEL(29, 'Times-7 SlimLine A6032', 7);
    insertFixedInfoForUHFANTENNAMODEL(30, 'Times-7 GroundMat A5530', 10);
    insertFixedInfoForUHFANTENNAMODEL(31, 'Times-7 SlimLine A5010', 8.3);
    insertFixedInfoForUHFANTENNAMODEL(32, 'Times-7 SlimLine A4030L', 7.5);
    insertFixedInfoForUHFANTENNAMODEL(33, 'Impinj xPortal.', 5.5);
    insertFixedInfoForUHFANTENNAMODEL(34, 'NORDIC ID SAMPO S Integrated standard antenna variant', 8);
    insertFixedInfoForUHFANTENNAMODEL(35, 'Kathrein WIRA-30-circular-ETSI', 11.5);
    insertFixedInfoForUHFANTENNAMODEL(36, 'Kathrein WIRA-30-circular-FCC', 11);
    insertFixedInfoForUHFANTENNAMODEL(37, 'TagItron IPRO Panel Patch IINDO', 4);
    insertFixedInfoForUHFANTENNAMODEL(38, 'Times-7 SlimLine A5060', 10.5);
    insertFixedInfoForUHFANTENNAMODEL(39, 'Kathrein WRA 7070 - ETSI or FCC', 8.5);
    insertFixedInfoForUHFANTENNAMODEL(40, 'Kathrein WRA 7070 KRAI - ETSI or FCC', 6.5);
	insertFixedInfoForUHFANTENNAMODEL(41, 'Times-7 True NearField A1115', 0);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at UHFANTENNAMODEL: ' || sqlerrm, 3);
    fp_error := 1;
  end fixedInfoForUHFANTENNAMODEL;

  procedure insertFixedInfoForORDERPRIORITY(fp_ordertype             orderpriority.ordertype%type,
                                            fp_prioritycode          orderpriority.prioritycode%type,
                                            fp_factorydescription    orderpriority.factorydescription%type,
                                            fp_sequencenumber        orderpriority.sequencenumber%type,
                                            fp_prioritycolor         orderpriority.prioritycolor%type,
                                            fp_standardpriority      orderpriority.standardpriority%type,
                                            fp_active                orderpriority.active%type,
                                            fp_defaultforreplacement orderpriority.defaultforreplacement%type,
                                            fp_purchasecategory      orderpriority.purchasecategory%type,
                                            fp_defaultforcategory    orderpriority.defaultforcategory%type) is

    lv_factorydescription    orderpriority.factorydescription%type;
    lv_sequencenumber        orderpriority.sequencenumber%type;
  begin
    select o.factorydescription, o.sequencenumber
      into lv_factorydescription, lv_sequencenumber
      from orderpriority o
     where o.ordertype = fp_ordertype and o.prioritycode = fp_prioritycode;
    if (lv_factorydescription <> fp_factorydescription) then
      update orderpriority o
         set o.factorydescription = fp_factorydescription, o.systemuser_id = systemUserID, o.timestamp = sysdate
       where o.ordertype = fp_ordertype and o.prioritycode = fp_prioritycode;
    end if;
    if (lv_sequencenumber <> fp_sequencenumber) then
      update orderpriority o
         set o.sequencenumber = fp_sequencenumber, o.systemuser_id = systemUserID, o.timestamp = sysdate
       where o.ordertype = fp_ordertype and o.prioritycode = fp_prioritycode;
    end if;
  exception
    when no_data_found then
      insert into orderpriority
        (orderpriority_id, ordertype, prioritycode, factorydescription, sequencenumber, prioritycolor,
         standardpriority, active, defaultforreplacement, systemuser_id, timestamp, purchasecategory,
         defaultforcategory)
      values
        (seq_orderpriority.nextval, fp_ordertype, fp_prioritycode, fp_factorydescription, fp_sequencenumber,
         fp_prioritycolor, fp_standardpriority, fp_active, fp_defaultforreplacement, systemUserID, sysdate,
         fp_purchasecategory, fp_defaultforcategory);
  end insertFixedInfoForORDERPRIORITY;

  procedure fixedInfoForORDERPRIORITY is
  begin
    insertFixedInfoForORDERPRIORITY(1, '-', 'Standard priority', 1, 'ffffff', 'Y', 'Y', 'Y', 0, 'N');
    insertFixedInfoForORDERPRIORITY(2, '-', 'Standard priority', 1, 'ffffff', 'Y', 'Y', 'N', 1, 'N');
    insertFixedInfoForORDERPRIORITY(3, '-', 'Standard priority', 1, 'ffffff', 'Y', 'Y', 'N', 0, 'N');
    insert into orderpriority_desc
      (orderpriority_id, language_id, description, systemuser_id, timestamp)
      select opr.orderpriority_id, l.language_id, opr.factorydescription, systemUserID, sysdate
        from orderpriority opr, languages l
       where l.translatedescription = 'Y'
       and opr.factorydescription is not null
         and not exists (select 1
                from orderpriority_desc od
               where od.orderpriority_id = opr.orderpriority_id
                 and od.language_id = l.language_id);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at ORDERPRIORITY: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForORDERPRIORITY;


  procedure fixedInfoForAPPSERVERCLUSTER is
    lv_count number;
  begin
    select count(1)
      into lv_count
      from appservercluster;
    if (lv_count = 0) then
      insert into appservercluster
        (appservercluster_id, code, description, masterappserver_id, systemuser_id, timestamp, clustertype,
         timetoshutdown)
        select seq_appservercluster.nextval, 'PHYSICAL1', 'Physical Cluster1', null, systemUserID, sysdate, 1, null
          from dual;
      insert into appserverclustercontent
        (appservercluster_id, applicationserver_id, actualstatus, systemuser_id, timestamp, clustertype)
        select appsc.appservercluster_id, apps.applicationserver_id, 0, systemUserID, sysdate, appsc.clustertype
          from appservercluster appsc, applicationserver apps
         where appsc.code = 'PHYSICAL1';
      insert into appservercluster
        (appservercluster_id, code, description, masterappserver_id, systemuser_id, timestamp, clustertype,
         timetoshutdown)
        select seq_appservercluster.nextval, 'PHYSICAL2', 'Physical Cluster2', null, systemUserID, sysdate, 1, null
          from dual;
    end if;
    commit;
      exception
         when others then
           rollback;
           write_log('Error at APPSERVERCLUSTER: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForAPPSERVERCLUSTER;

  procedure insertFixedInfoForFIELDSPERDIALOG(fp_dialog_id fieldsperdialog.dialog_id%type,
                                              fp_field     fieldsperdialog.field%type) is
    lv_dialog_id fieldsperdialog.dialog_id%type;
  begin
    select f.dialog_id
      into lv_dialog_id
      from fieldsperdialog f
     where f.field = fp_field and f.dialog_id = fp_dialog_id;
  exception
    when no_data_found then
      insert into fieldsperdialog
        (fieldsperdialog_id, dialog_id, field, timestamp)
      values
        (seq_fieldsperdialog.nextval, fp_dialog_id, fp_field, sysdate);
  end insertFixedInfoForFIELDSPERDIALOG;

  procedure fixedInfoForFIELDSPERDIALOG is
    lv_DIALOG_ID dialogs.dialog_id%type;
  begin
    select d.dialog_id
      into lv_DIALOG_ID
      from dialogs d
     where d.code = 'Customer';
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtName');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtLegalName');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtLegacyCode');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'srfAccountReceivable');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'cmbNationalAccount');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtMasterAccount');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'dfDateActive');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'dfDateInactive');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'cbActive');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtCocNumber');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'btnCommentOnStatement');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'rbPaymentMethod');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtAddress1US');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtAddress2US');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtZipCodeUS');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'rbTax');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'deliverySchemesPerStopTable');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtTaxAreaMailUS');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtTaxAreaDeliveryUS');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtTaxAreaBillingUS');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtGlobalLocationNumber');
    insertFixedInfoForFIELDSPERDIALOG(lv_DIALOG_ID, 'txtCustomerPONumber');

    commit;
      exception
         when others then
           rollback;
           write_log('Error at FIELDSPERDIALOG: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForFIELDSPERDIALOG;

  procedure insertFixedInfoForFIELDSRELATIONS(fp_field           fieldsperdialog.field%type,
                                              fp_field_successor fieldsrelations.field_successor%type) is
   lv_field_successor fieldsrelations.field_successor%type;
  begin
    select f.field_successor
      into lv_field_successor
      from fieldsrelations f
     where f.field_successor = fp_field_successor
       and f.fieldsperdialog_id = (select fpd.fieldsperdialog_id
                                     from fieldsperdialog fpd
                                    where fpd.field = fp_field);
    if(lv_field_successor <> fp_field_successor) then
    update fieldsrelations f
    set f.field_successor = fp_field_successor, f.timestamp = sysdate
    where f.field_successor = fp_field_successor
       and f.fieldsperdialog_id = (select fpd.fieldsperdialog_id
                                     from fieldsperdialog fpd
                                    where fpd.field = fp_field);
    end if;
  exception
    when no_data_found then
      insert into fieldsrelations
        (fieldsperdialog_id, field_successor, timestamp)
      values
        ((select fpd.fieldsperdialog_id
           from fieldsperdialog fpd
          where fpd.field = fp_field), fp_field_successor, sysdate);
  end insertFixedInfoForFIELDSRELATIONS;

  procedure fixedInfoForFIELDSRELATIONS is
  begin
    insertFixedInfoForFIELDSRELATIONS('txtName', 'lblName');
    insertFixedInfoForFIELDSRELATIONS('txtLegalName', 'lblLegalName');
    insertFixedInfoForFIELDSRELATIONS('txtLegacyCode', 'lblLegacyCode');
    insertFixedInfoForFIELDSRELATIONS('srfAccountReceivable', 'lblAccountReceivable');
    insertFixedInfoForFIELDSRELATIONS('cmbNationalAccount', 'lblNationalAccount');
    insertFixedInfoForFIELDSRELATIONS('txtMasterAccount', 'lblMasterAccount');
    insertFixedInfoForFIELDSRELATIONS('txtCocNumber', 'lblCocNumber');
    insertFixedInfoForFIELDSRELATIONS('txtCocNumber', 'txtPnNumber');
    insertFixedInfoForFIELDSRELATIONS('rbPaymentMethod', 'lblPaymentMethod');
    insertFixedInfoForFIELDSRELATIONS('rbPaymentMethod', 'cmbPaymentType');
    insertFixedInfoForFIELDSRELATIONS('rbPaymentMethod', 'lblPayByCustomer');
    insertFixedInfoForFIELDSRELATIONS('rbPaymentMethod', 'srfPayByCustomer');
    insertFixedInfoForFIELDSRELATIONS('txtAddress1US', 'lblStreetHouseUS');
    insertFixedInfoForFIELDSRELATIONS('txtAddress1US', 'lblAddress1US');
    insertFixedInfoForFIELDSRELATIONS('txtAddress1US', 'txtHouseNrExtUS');
    insertFixedInfoForFIELDSRELATIONS('txtAddress1US', 'txtHouseUS');
    insertFixedInfoForFIELDSRELATIONS('txtAddress2US', 'lblAddress2US');
    insertFixedInfoForFIELDSRELATIONS('txtZipCodeUS', 'txtCityUS');
    insertFixedInfoForFIELDSRELATIONS('txtZipCodeUS', 'lblCity_State_ZipCodeUS');
    insertFixedInfoForFIELDSRELATIONS('txtZipCodeUS', 'txtStateUS');
    insertFixedInfoForFIELDSRELATIONS('txtZipCodeUS', 'txtCountyUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'txtCertificateUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'btnGoUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'btnOpenUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'txtTaxExemptCodeUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'cmbCountyUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'cbCountyUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'cmbCityUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'cbCityUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'lblCertifRecDateUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'dfCertifRecDateUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'lblStateUS');
    insertFixedInfoForFIELDSRELATIONS('rbTax', 'cmbStatesUS');
    insertFixedInfoForFIELDSRELATIONS('dfDateActive', 'lblDateActive');
    insertFixedInfoForFIELDSRELATIONS('dfDateInactive', 'lblDateInactive');
    insertFixedInfoForFIELDSRELATIONS('txtTaxAreaMailUS', 'lblTaxAreaMailUS');
    insertFixedInfoForFIELDSRELATIONS('txtTaxAreaDeliveryUS', 'lblTaxAreaDeliveryUS');
    insertFixedInfoForFIELDSRELATIONS('txtTaxAreaBillingUS', 'lblTaxAreaBillingUS');
    insertFixedInfoForFIELDSRELATIONS('txtGlobalLocationNumber', 'lblGlobalLocationNumber');
    insertFixedInfoForFIELDSRELATIONS('txtCustomerPONumber', 'lblCustomerPONumber');

    insert into accessrightfieldlists a
      select f.fieldsperdialog_id, arl.accessrightslist_id, 0, systemUserID, sysdate
        from fieldsperdialog f, accessrightslist arl
       where f.field = 'deliverySchemesPerStopTable'
         and not exists (select 1
                from accessrightfieldlists a1
               where a1.fieldsperdialog_id = f.fieldsperdialog_id
                 and a1.accessrightslist_id = arl.accessrightslist_id);
   commit;
      exception
         when others then
           rollback;
           write_log('Error at FIELDSPERDIALOG: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForFIELDSRELATIONS;

  procedure insertFixedInfoForCONTRACTATTRIBUTE(fp_contractattribute_id contractattribute.contractattribute_id%type,
                                                fp_groupnumber          contractattribute.groupnumber%type,
                                                fp_sequencenumber       contractattribute.sequencenumber%type,
                                                fp_factoryname          contractattribute.factoryname%type,
                                                fp_internalname         contractattribute.internalname%type,
                                                fp_novaluerule          contractattribute.novaluerule%type) is
    lv_groupnumber    contractattribute.groupnumber%type;
    lv_sequencenumber contractattribute.sequencenumber%type;
    lv_factoryname    contractattribute.factoryname%type;
    lv_internalname   contractattribute.internalname%type;
    lv_novaluerule    contractattribute.novaluerule%type;
  begin
    select c.groupnumber, c.sequencenumber, c.factoryname, c.internalname, c.novaluerule
      into lv_groupnumber, lv_sequencenumber, lv_factoryname, lv_internalname, lv_novaluerule
      from contractattribute c
     where c.contractattribute_id = fp_contractattribute_id;
    if (lv_groupnumber <> fp_groupnumber) then
      update contractattribute c
         set c.groupnumber = fp_groupnumber, c.systemuser_id = systemUserID, c.timestamp = sysdate
       where c.contractattribute_id = fp_contractattribute_id;
    end if;
    if (lv_sequencenumber <> fp_sequencenumber) then
      update contractattribute c
         set c.sequencenumber = fp_sequencenumber, c.systemuser_id = systemUserID, c.timestamp = sysdate
       where c.contractattribute_id = fp_contractattribute_id;
    end if;
    if (lv_factoryname <> fp_factoryname) then
      update contractattribute c
         set c.factoryname = fp_factoryname, c.systemuser_id = systemUserID, c.timestamp = sysdate
       where c.contractattribute_id = fp_contractattribute_id;
    end if;
    if (lv_internalname <> fp_internalname) then
      update contractattribute c
         set c.internalname = fp_internalname, c.systemuser_id = systemUserID, c.timestamp = sysdate
       where c.contractattribute_id = fp_contractattribute_id;
    end if;
    if (lv_novaluerule <> fp_novaluerule) then
      update contractattribute c
         set c.novaluerule = fp_novaluerule, c.systemuser_id = systemUserID, c.timestamp = sysdate
       where c.contractattribute_id = fp_contractattribute_id;
    end if;
  exception
    when no_data_found then
      insert into contractattribute
        (contractattribute_id, groupnumber, sequencenumber, factoryname, internalname, systemuser_id, timestamp,
         novaluerule)
      values
        (fp_contractattribute_id, fp_groupnumber, fp_sequencenumber, fp_factoryname, fp_internalname, systemUserID,
         sysdate, fp_novaluerule);
  end insertFixedInfoForCONTRACTATTRIBUTE;

  procedure fixedInfoForCONTRACTATTRIBUTE is
  begin
    insertFixedInfoForCONTRACTATTRIBUTE(1, 1, 1, 'CustomerRelated', 'cmbCustomerRelated', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(5, 2, 1, 'AllowAutomaticSales', 'cbAllowAutomaticSales', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(7, 4, 3, 'RepairRented', 'cbChargeRepairs', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(8, 4, 4, 'RepairCOG', 'cbChargeRepairsCOG', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(9, 4, 5, 'VariableServices', 'cbVariableServices', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(10, 4, 6, 'ChargeResidualValue', 'cbChargeResidualValue', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(12, 4, 8, 'ChargeLossCharge', 'cbChargeLossCharge', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(39, 4, 1, 'ChargePrepCharge', 'txtPrepChargePrice', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(51, 7, 1, 'InvoiceFrequencyCode', 'cmbInvoiceFrequency', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(53, 7, 3, 'MinimumInvoiceAmount', 'txtMinInvoiceAmount', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(55, 7, 5, 'SplitInvoicesPerActivity', 'cbSplitInvoicesPerActivity', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(63, 7, 13, 'ChargeLossForPoolItems', 'cbChargeLossForPoolAfterXDays', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(64, 7, 14, 'ChargeLossForUniquePoolDays', 'sfChargeLossForPoolNoDays', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(73, 7, 23, 'SendStatement', 'rbSendStatement', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(74, 7, 24, 'StatementFrequencyCode', 'cmbFrequencyStatement', 1);
    insertFixedInfoForCONTRACTATTRIBUTE(75, 7, 26, 'AttachInvoiceCopies', 'cbAttachInvoice', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(76, 7, 27, 'StatementPerCustomer', 'cbStatementPerCustomer', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(77, 7, 28, 'InvoiceComments', 'btnCommentOnInvoice', 1);
    insertFixedInfoForCONTRACTATTRIBUTE(79, 7, 30, 'StatementComments', 'btnCommentOnStatement', 1);
    insertFixedInfoForCONTRACTATTRIBUTE(80, 8, 1, 'PaymentMethod', 'rbPaymentMethod', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(81, 8, 2, 'PaymentType', 'cmbPaymentType', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(83, 8, 4, 'PaymentTermsCode', 'cmbPaymentTerms', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(88, 8, 9, 'FinanceChargeDays', 'sfFinancialChargeDays', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(89, 8, 10, 'PutFinanceChargeOn', 'rbPutOn', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(96, 7, 25, 'SendStatementByE-mail', 'cbSendByEmailStat', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(98, 1, 5, 'SoilCount', 'cbSoilCount', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(99, 1, 6, 'InternetOrdering', 'cbInternetOrdering', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(100, 10, 0, 'ContractProductBilling', 'Table_CONTRACTPRODUCTBILLING', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(101, 11, 0, 'ContractProductPricing', 'ContractProductPricing', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(102, 12, 0, 'ContractProductLogistics', 'Table_CONTRACTPRODUCTORDERDELIVERY', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(103,
                                        13,
                                        0,
                                        'ContractProductMiscellaneous',
                                        'Table_CONTRACTPRODUCTMISCELLANEOUS',
                                        0);
    insertFixedInfoForCONTRACTATTRIBUTE(104, 4, 12, 'CustomGarmentCharge', 'cbCustomGarmentCharge', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(105, 4, 13, 'Budget Protection', 'customerBudgetProtectionField', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(106,
                                        14,
                                        0,
                                        'ContractProductBudgetProtection',
                                        'Table_CONTRACTPRODUCTBGPROTECTION',
                                        0);
    insertFixedInfoForCONTRACTATTRIBUTE(107, 10, 1, 'BillingMethod', 'cmbBillingMethod', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(108, 10, 2, 'ChangesPerWeek', 'rbChangesPerWeek', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(109, 10, 3, 'ChargeOverUse', 'cbChargeOveruse1', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(110, 10, 4, 'RentPricePerFrequency', 'cbDelFreqRelatedPricing', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(111, 10, 5, 'ChargeWashesOnlyForCOG', 'cbChargeWashesOnlyCOG', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(112, 10, 6, 'InventoryBillingType', 'btnGroupInvBillingType', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(113, 10, 7, 'MinimumTurnAround', 'rbMinTurnArround', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(114, 10, 8, 'MinimumFrequency', 'cmbCalcRentEvery', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(115, 10, 9, 'ChargeLossForPool_YN', 'cbChargeLossForPool', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(116, 10, 10, 'ChargeLossUniquePoolDays', 'spAfterDays', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(117, 10, 11, 'PriceUsage', 'rbPriceUsage', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(118, 10, 12, 'ChargeRentNoReturnPoolWeeksAfterWks', 'spAfterWeeks', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(119, 10, 13, 'ChargeRentNotReturned', 'cmbChargeRentNotReturned', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(120, 10, 14, 'PercentageAfterDepreciation', 'spAfterDeprecCharge', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(121, 10, 15, 'InvoiceFreqRelatedPrice', 'cbInvoiceFrequencyRelatedRentPrice', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(122, 10, 16, 'InvWashBasedOnSoilCount', 'cbInvWashBasedOnSoil', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(123, 10, 17, 'ChargeWashesPack', 'cmbChargeWashesFor4', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(124, 10, 18, 'ReturnStockAllowed', 'cbReturnStockAllowed5', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(125, 10, 19, 'SeasonType_ID', 'cmbSeasonType', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(126, 10, 20, 'SeasonalRent', 'cmbSeasonalRent', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(127, 10, 21, 'ChargeWashInactiveSeason', 'cbChargeRentInactive', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(128, 10, 22, 'ResidualValueScheme_ID', 'cmbResidualValueScheme', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(129, 10, 23, 'SRCMethod', 'cbrbSystematicReplacement', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(130, 10, 24, 'SCRPercentageSoilCount', 'dfPercOfSoilCount', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(131, 10, 25, 'SRCPercentageInventory', 'dfPercOfCircInv', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(132, 10, 26, 'SRCPercentageBilledQty', 'dfPercOfBilledQty', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(133, 10, 27, 'SRCFrequency', 'cmbCalculateEvery', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(134, 10, 28, 'SRCChargeRent', 'cbSRCChargeRent', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(135, 10, 29, 'ShowFOCRentOnInvoice', 'cbShowFOCInv', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(136, 10, 30, 'ResetRVUponReIssue', 'cbResetRvUponReissue', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(137, 10, 31, 'DeliverReplacementQty', 'cbDeliverReplaceQty', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(138, 11, 1, 'RentPrice', 'RentPrice', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(139, 11, 2, 'WashPrice', 'WashPrice', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(140, 11, 3, 'SalesPrice', 'SalesPrice', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(141, 11, 4, 'ReplacementPrice', 'ReplacementPrice', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(142, 11, 5, 'InsurancePrice', 'InsurancePrice', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(145, 12, 1, 'DelayedEvenExchange', 'rbDelayedEvenExchange', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(146, 12, 2, 'DEEDeliveryFrequency', 'cbDeeDeliveryFrequency', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(147, 12, 3, 'StraightEvenExchange', 'cbStraightEvenExchange', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(148, 12, 4, 'OrderViaWeb', 'cbOrderViaWeb', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(149, 12, 5, 'SoilCountMethod', 'cmbSoilCountMethod', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(150, 12, 6, 'CleanCount', 'cbCleanCounted', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(151, 12, 7, 'CodeUniquely', 'cbCodeUniquely', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(152, 12, 8, 'OnSiteInventoryCount', 'cbOnSiteInventoryCount', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(153, 12, 9, 'AutomaticSales', 'cbAutomaticSales', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(154, 12, 10, 'CustomerRelatedGarments', 'cbCustomerRelated', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(155, 12, 11, 'AutoReplAfterLifeTime', 'cbAutoReplAfterLifeTime', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(156, 12, 12, 'AllowReturnToStock', 'cmbAllowReturnToStock', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(157, 12, 13, 'RaggedItemAction', 'cmbRaggedItemAction', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(158, 13, 1, 'CustomCode', 'txtCode', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(159, 13, 2, 'CustomDescription', 'txtDescription', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(160, 13, 3, 'EANNumber', 'dfEANNumber', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(161, 13, 4, 'NANNumber', 'txtNANNumber', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(162, 13, 5, 'SalesEmployee_ID', 'srfSalesPerson', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(163, 13, 6, 'CommissionPayable', 'cbCommissionPayable', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(164, 13, 7, 'SalesEmployee2_ID', 'srfSalesEmployee2', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(165, 13, 8, 'ContractPurchaseOrder_ID', 'cmbPurchaseOrderNumber', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(166, 13, 9, 'ContractPurchaseOrderLine_ID', 'cmbPurchaseOrderLine', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(167, 13, 10, 'GainReason_ID', 'cmbGainReason', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(168, 13, 11, 'GainCompetitor_ID', 'cmbGainCompetitor', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(169, 13, 12, 'LostReason_ID', 'cmbLostReason', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(170, 13, 13, 'LostCompetitor_ID', 'cmbLostCompetitor', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(171, 13, 14, 'Remark', 'txtRemark', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(172, 4, 14, 'UseProdSizeSurchargePricing', 'cbUseProdSizeSurchargePricing', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(173, 14, 1, 'BudgetProtection', 'plpcBudgetProtectionField', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(174, 15, 0, 'ImageCare', 'ContractProductImageCare', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(175, 15, 1, 'PLPCImageCare', 'plpcImageCareField', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(176, 2, 16, 'AutoSoilPercentage', 'txtAutoSoil', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(177, 12, 14, 'PLPCAutoSoilPercentage', 'dfAutoSoilPercentage', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(178, 7, 32, 'PORequired', 'PORequired', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(179, 2, 19, 'NameLabelLayout', 'cmbNameLabelLayout', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(180, 16, 0, 'EmblemTemplate', 'Table_CONTRACTEMBTEMP', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(181, 17, 0, 'WearerFunction', 'Table_CONTRACTWEARERFUNCTION', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(247, 4, 15, 'GarmentRentSpecification', 'cmbGarmentRentSpecification', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(248, 4, 16, 'SpecialSizeCharge', 'cbSpecialSizeCharge', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(249, 18, 0, 'DeliveryFrequency', 'Table_CONTRACTPRODUCTDELFREQCOMPL', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(250, 4, 17, 'MerchandiseBuyoutCharge', 'cbMerchandiseBuyoutCharge', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(253, 11, 8, 'SRChargePercentage', 'SRChargePercentage', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(254, 11, 9, 'LossChargePercentage', 'LossChargePercentage', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(255, 8, 11, 'GeneratePayment', 'rbCreditCardPayment', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(256, 8, 12, 'Schedule', 'btnSchedule', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(257, 8, 13, 'CashDelayCharge', 'txtCashDelayChargePrice', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(258, 4, 18, 'ChargeExchangeCharge', 'txtExchangeChargePrice', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(259, 4, 19, 'NoEmblemCharge1stInvoice', 'cbNoEmblemCharge1stInvoice', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(260, 4, 20, 'NoPrepCharge1stInvoice', 'cbNoPrepCharge1stInvoice', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(249, 18, 0, 'DeliveryFrequency', 'Table_CONTRACTPRODUCTDELFREQCOMPL', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(261, 19, 0, 'SpecialCharge', 'Table_CONTRACTSPECIALCHARGE', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(262, 18, 1, 'CPLDeliveryScheme', 'cmbDeliveryScheme', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(263, 20, 1, 'NonGarmChargeResidualValue', 'cbNonGarmChargeResidualValue', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(264, 20, 2, 'NonGarmChargeLossCharge', 'cbNonGarmChargeLossCharge', 2);
    insertFixedInfoForCONTRACTATTRIBUTE(266, 1, 7, 'RAAccessTemplate', 'cmbRAAccessTemplate', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(267, 21, 0, 'BM6ContractProduct', 'Table_CONTRACTPRODUCTBM6', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(268, 21, 1, 'BM6BillingMultiplier', 'txtSpecificBillingMultiplier', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(269,
                                        21,
                                        2,
                                        'BM6InventoryMaintPerc',
                                        'txtSpecificInventoryMaintenancePercentage',
                                        0);
    insertFixedInfoForCONTRACTATTRIBUTE(270,
                                        21,
                                        3,
                                        'BM6OneOffPriceMultiplier',
                                        'txtSpecificOneTimeOrderingMultiplier',
                                        0);
    insertFixedInfoForCONTRACTATTRIBUTE(271, 21, 4, 'BM6DeliveryDaysPerWeek', 'delDaysPerWeekBM6Table', 0);
    insertFixedInfoForCONTRACTATTRIBUTE(272, 4, 14, 'ChargeRentForLoss', 'cbChargeRentForLoss', 2);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at CONTRACTATTRIBUTE: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForCONTRACTATTRIBUTE;

  procedure insertFixedInfoForCONTRACTATTRIBUTEDEPEND(fp_contractattribute_id contractattributedepend.contractattribute_id%type,
                                                      fp_internalname         contractattributedepend.internalname%type) is
    lv_contractattribute_id contractattributedepend.contractattribute_id%type;
  begin
    select c.contractattribute_id
      into lv_contractattribute_id
      from contractattributedepend c
     where c.internalname = fp_internalname and c.contractattribute_id = fp_contractattribute_id ;
  exception
    when no_data_found then
      insert into contractattributedepend
        (contractattribute_id, internalname, systemuser_id, timestamp)
      values
        (fp_contractattribute_id, fp_internalname, systemUserID, sysdate);
  end insertFixedInfoForCONTRACTATTRIBUTEDEPEND;

  procedure fixedInfoForCONTRACTATTRIBUTEDEPEND is
  begin
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(107, 'btnChargeWashesOnlyCOG4');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(109, 'cbChargeOveruse2');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(112, 'btnGroupInvBillingTypeBM2');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(113, 'spMinTurnArround');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(113, 'txtMinTurnAround');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(116, 'spAfterDaysCOG4');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(116, 'spAfterDaysBM2');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(125, 'cbSeasonRelated');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(129, 'cbrbSystematicReplacementBtGrp');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(145, 'cmbReturnMerchandise');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(147, 'rbFixedDeliveryScheme');
    insertFixedInfoForCONTRACTATTRIBUTEDEPEND(149, 'cbSoilCounted');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at CONTRACTATTRIBUTEDEPEND: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForCONTRACTATTRIBUTEDEPEND;

  procedure insertFixedInfoForMAATEMPLATEATTRIBUTE(fp_maatemplateattribute_id maatemplateattribute.maatemplateattribute_id%type,
                                                   fp_description             maatemplateattribute.description%type,
                                                   fp_module                  maatemplateattribute.module%type,
                                                   fp_disable                 maatemplateattribute.disable%type,
                                                   fp_hide                    maatemplateattribute.hide%type,
                                                   fp_decreaseadjustmentlimit maatemplateattribute.decreaseadjustmentlimit%type,
                                                   fp_invoicelinetye_id       maatemplateattribute.invoicelinetye_id%type,
                                                   fp_routeassistantversion   maatemplateattribute.routeassistantversion%type,
                                                   fp_internalname            maatemplateattribute.internalname%type) is
    lv_description             maatemplateattribute.description%type;
    lv_module                  maatemplateattribute.module%type;
    lv_disable                 maatemplateattribute.disable%type;
    lv_hide                    maatemplateattribute.hide%type;
    lv_decreaseadjustmentlimit maatemplateattribute.decreaseadjustmentlimit%type;
    lv_invoicelinetye_id       maatemplateattribute.invoicelinetye_id%type;
    lv_routeassistantversion   maatemplateattribute.routeassistantversion%type;
    lv_internalname            maatemplateattribute.internalname%type;
  begin
    select m.description, m.module, m.disable, m.hide, m.decreaseadjustmentlimit, m.invoicelinetye_id,
           m.routeassistantversion, m.internalname
      into lv_description, lv_module, lv_disable, lv_hide, lv_decreaseadjustmentlimit, lv_invoicelinetye_id,
           lv_routeassistantversion, lv_internalname
      from maatemplateattribute m
     where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    if (lv_description <> fp_description) then
      update maatemplateattribute m
         set m.description = fp_description, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_module <> fp_module) then
      update maatemplateattribute m
         set m.module = fp_module, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_disable <> fp_disable) then
      update maatemplateattribute m
         set m.disable = fp_disable, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_hide <> fp_hide) then
      update maatemplateattribute m
         set m.hide = fp_hide, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_decreaseadjustmentlimit <> fp_decreaseadjustmentlimit) then
      update maatemplateattribute m
         set m.decreaseadjustmentlimit = fp_decreaseadjustmentlimit, m.systemuser_id = systemUserID,
             m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_invoicelinetye_id <> fp_invoicelinetye_id) then
      update maatemplateattribute m
         set m.invoicelinetye_id = fp_invoicelinetye_id, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_routeassistantversion <> fp_routeassistantversion) then
      update maatemplateattribute m
         set m.routeassistantversion = fp_routeassistantversion, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
    if (lv_internalname <> fp_internalname) then
      update maatemplateattribute m
         set m.internalname = fp_internalname, m.systemuser_id = systemUserID, m.timestamp = sysdate
       where m.maatemplateattribute_id = fp_maatemplateattribute_id;
    end if;
  exception
    when no_data_found then
      insert into maatemplateattribute
        (maatemplateattribute_id, description, module, disable, hide, decreaseadjustmentlimit, invoicelinetye_id,
         routeassistantversion, systemuser_id, timestamp, internalname)
      values
        (fp_maatemplateattribute_id, fp_description, fp_module, fp_disable, fp_hide, fp_decreaseadjustmentlimit,
         fp_invoicelinetye_id, fp_routeassistantversion, systemUserID, sysdate, fp_internalname);
  end insertFixedInfoForMAATEMPLATEATTRIBUTE;

  procedure fixedInfoForMAATEMPLATEATTRIBUTE is
  begin
    insertFixedInfoForMAATEMPLATEATTRIBUTE(1, 'Rent', null, 'Y', 'N', 'Y', 1, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(2, 'Delivery(wash)', null, 'Y', 'N', 'Y', 2, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(3, 'Soil weight', null, 'Y', 'N', 'Y', 3, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(4, 'Clean weight', null, 'Y', 'N', 'Y', 4, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(5, 'Sales', null, 'Y', 'N', 'Y', 5, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(6, 'Repair', null, 'Y', 'N', 'Y', 6, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(7, 'Replacement charge', null, 'Y', 'N', 'Y', 7, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(8, 'Automatic replacement', null, 'Y', 'N', 'Y', 8, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(9, 'Loss charge', null, 'Y', 'N', 'Y', 9, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(10, 'Residual value charge', null, 'Y', 'N', 'Y', 10, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(11, 'Garment insurance', null, 'Y', 'N', 'Y', 11, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(12,
                                           'Stockroom handling & label/ emblem charge',
                                           null,
                                           'Y',
                                           'N',
                                           'Y',
                                           12,
                                           935,
                                           null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(13, 'Miscellaneous invoice line', null, 'Y', 'N', 'Y', 15, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(14, 'Special charge', 'UNFCUSTOM', 'Y', 'N', 'Y', 16, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(15, 'Locker rent', null, 'Y', 'N', 'Y', 20, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(16, 'Locker service', null, 'Y', 'N', 'Y', 21, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(17, 'Lease', null, 'Y', 'N', 'Y', 22, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(18, 'Stock charge', null, 'Y', 'N', 'Y', 23, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(19,
                                           'Lost Customer Residual Value Charge',
                                           'LOSTCUSTOMER',
                                           'Y',
                                           'N',
                                           'Y',
                                           24,
                                           935,
                                           null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(20, 'Lost Revenue Charge', 'LOSTCUSTOMER', 'Y', 'N', 'Y', 25, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(21, 'Residential Wash', 'PWBBASIS', 'Y', 'N', 'Y', 26, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(22, 'Residential Labels', 'PWBBASIS', 'Y', 'N', 'Y', 27, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(23, 'Service Costs', 'PWBBASIS', 'Y', 'N', 'Y', 28, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(24, 'Capped Excess Amounts', 'PWBBASIS', 'Y', 'N', 'Y', 29, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(25, 'Client Rent', 'PWBBASIS', 'Y', 'N', 'Y', 30, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(26, 'Budget', 'TEXTILECONTROLLING', 'Y', 'N', 'Y', 31, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(27, 'Down Payment', 'DOWNPAYMENTS', 'Y', 'N', 'Y', 32, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(28,
                                           'Custom Garment Charge',
                                           'CUSTOMGARMENTCHARGE',
                                           'Y',
                                           'N',
                                           'Y',
                                           34,
                                           935,
                                           null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(29, 'Service', 'UNIQUEITEMSERVICE', 'Y', 'N', 'Y', 35, 935, null);
    insertFixedInfoForMAATEMPLATEATTRIBUTE(100,
                                           'Rent Price',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editRentalAmount');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(101,
                                           'Wash Price',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editWash');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(102,
                                           'Replacement Price',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editReplacementAmount');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(103,
                                           'Sales Price',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editSale');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(104,
                                           'ImageCare Price',
                                           'ImageCare',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editImageCareIns');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(105,
                                           'SRC Percentage',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editSrc');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(106,
                                           'Minimum usage percentage',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editMinUsage');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(107,
                                           'Circulating inventory',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editCirculatingInvDel');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(108,
                                           'Billing quantity',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editBillingQtyDel');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(109,
                                           'Delivery quantity',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'layoutDeliveryDays');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(110,
                                           'Add additional products',
                                           'RouteAssistantContract',
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'btnSelect');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(111,
                                           'Quit product',
                                           'RouteAssistantContract',
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'action_deleteProduct');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(112,
                                           'Quit product at consumption point',
                                           'RouteAssistantContract',
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'action_deleteProduct_consPoint');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(113,
                                           'Change Product Delivery Day',
                                           'RouteAssistantContract',
                                           'Y',
                                           'N',
                                           'N',
                                           null,
                                           935,
                                           'layoutDeliveryDays_product');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(114,
                                           'Soil Count - Soiled',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'layoutIncreaseInvChanges');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(115,
                                           'Soil Count - Loss',
                                           'SOILCOUNTLOSS',
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'layoutIncreaseLostCounts');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(116,
                                           'Soil Count - Ruin',
                                           'SOILCOUNTLOSS',
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'layoutIncreaseRuinCounts');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(117, 'Add Wearer', null, 'Y', 'Y', 'N', null, 935, 'action_add_wearer');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(118,
                                           'Duplicate Wearer',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'action_make_a_like');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(119, 'Quit Wearer', null, 'Y', 'Y', 'N', null, 935, 'action_quit_wearer');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(120,
                                           'Increase/Decrease Wearer Inventory',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'wearerProdbtnIncreaseDec');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(121,
                                           'Size Exchange',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'btnWearerProdSizeExchange');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(122,
                                           'Style Exchange',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'btnWearerProdStyleExchange');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(123, 'Bill Loss Now', null, 'Y', 'Y', 'N', null, 935, 'btnScanReturnsRTS');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(124,
                                           'Bill Damage Now',
                                           'ROUTEASSISTANTBILLDAMAGE',
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'btnAbuseBillNow');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(125, 'Scan to replace', null, 'Y', 'Y', 'N', null, 935, 'btnReplace');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(126,
                                           'Replace All',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'btnWearerProductRecplaceCompleteInv');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(127, 'Replace Loss', null, 'Y', 'Y', 'N', null, 935, 'btnReplaceLoss');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(128,
                                           'Mark as undeliverable',
                                           null,
                                           'Y',
                                           'Y',
                                           'N',
                                           null,
                                           935,
                                           'action_undeliverable');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(129,
                                           'Weekly Usage',
                                           'BILLINGMETHOD6',
                                           'Y',
                                           'N',
                                           'Y',
                                           null,
                                           935,
                                           'editWeeklyUsage');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(130, 'Frequency', null, 'Y', 'Y', 'N', null, 935, 'layoutFrequency');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(132, 'Receipt of Payment', null, 'Y', 'N', 'N', null, 935, 'editSettleAmountCollected');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(133, 'Route Service Contract Rent Price', NULL, 'Y', 'N', 'Y', NULL, 935, 'editRentalAmountRSC');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(134, 'Route Service Contract Wash Price', NULL, 'Y', 'N', 'Y', NULL, 935, 'editWashRSC');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(135, 'Route Service Contract Sales Price', NULL, 'Y', 'N', 'Y', NULL, 935, 'editSaleRSC');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(136, 'Route Service Contract Replacement Price', NULL, 'Y', 'N', 'Y', NULL, 935, 'editReplacementAmountRSC');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(137, 'Route Service Contract Image Care Price', NULL, 'Y', 'N', 'Y', NULL, 935, 'editImageCareInsRSC');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(138, 'Route Service Contract SRC Percentage', NULL, 'Y', 'N', 'Y', NULL, 935, 'editSrcRSC');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(139, 'Invoice line adjust amount', NULL, 'Y', 'N', 'N', NULL, 935, 'adjustmentAmount');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(140, 'All Open Invoices', 'RAS', 'Y', 'Y', 'N', NULL, 935, 'btnAllOpenInvoices');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(141, 'Last Payment', 'RAS', 'N', 'Y', 'N', NULL, 935, 'layoutLastPaymentInfo');
	  insertFixedInfoForMAATEMPLATEATTRIBUTE(142,'No Signature Available','RAS','Y', 'Y', 'N',NULL, 935,'btnNoSignatureAvailable');
    insertFixedInfoForMAATEMPLATEATTRIBUTE(143, 'Delete Unique ID Service Item', 'UNIQUEITEMSERVICE', 'Y', 'Y', 'N', NULL, 935, 'action_delete');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at MAATEMPLATEATTRIBUTE: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForMAATEMPLATEATTRIBUTE;

  procedure insertFixedInfoForOOSACTION(fp_oosaction_id       oosaction.oosaction_id%type,
                                        fp_factorydescription oosaction.factorydescription%type) is
  lv_factorydescription oosaction.factorydescription%type;
  begin
    select o.factorydescription
      into lv_factorydescription
      from oosaction o
     where o.oosaction_id = fp_oosaction_id;
     if(lv_factorydescription <> fp_factorydescription) then
     update oosaction o
     set o.factorydescription = lv_factorydescription, o.systemuser_id = systemUserID, o.timestamp = sysdate
     where o.oosaction_id = fp_oosaction_id;
     end if;
  exception
    when no_data_found then
      insert into oosaction
        (oosaction_id, factorydescription, systemuser_id, timestamp)
      values
        (fp_oosaction_id, fp_factorydescription, systemUserID, sysdate);
  end insertFixedInfoForOOSACTION;

  procedure fixedInfoForOOSACTION is
  begin
    insertFixedInfoForOOSACTION(1, 'Purchasing');
    insertFixedInfoForOOSACTION(2, 'Receive items on Stock');
    insertFixedInfoForOOSACTION(4, 'Reserve items from stockroom');
    insertFixedInfoForOOSACTION(5, 'MaintainUI- Change stock location');
    insertFixedInfoForOOSACTION(6, 'MaintainUI - Change product/Size/Grade');
    insertFixedInfoForOOSACTION(10, 'Allocate items for Backorder');
    insertFixedInfoForOOSACTION(11, 'Order items for stock replenishment');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at OOSACTION: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForOOSACTION;

procedure insertFixedInfoForOOSRESTRICTION(fp_oosrestriction_id  oosrestriction.oosrestriction_id%type,
                                           fp_factorydescription oosrestriction.factorydescription%type) is
begin
  select o.oosrestriction_id
    into id
    from oosrestriction o
   where o.oosrestriction_id = fp_oosrestriction_id;
exception
  when no_data_found then
    insert into oosrestriction
      (oosrestriction_id, factorydescription, systemuser_id, timestamp)
    values
      (fp_oosrestriction_id, fp_factorydescription, systemUserID, sysdate);
end insertFixedInfoForOOSRESTRICTION;

  procedure fixedInfoForOOSRESTRICTION is
  begin
    insertFixedInfoForOOSRESTRICTION(1, 'Always allowed');
    insertFixedInfoForOOSRESTRICTION(2, 'Never allowed');
    insertFixedInfoForOOSRESTRICTION(3, 'Only allowed blocked locations');
    insertFixedInfoForOOSRESTRICTION(4, 'Only allowed blocked-and picking locations');
    insertFixedInfoForOOSRESTRICTION(5, 'Maximum available quantity');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at OOSRESTRICTION: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForOOSRESTRICTION;

  procedure insertFixedInfoForOOSACTIONRESTRICTION(fp_oosaction_id      oosactionrestriction.oosaction_id%type,
                                                   fp_oosrestriction_id oosactionrestriction.oosrestriction_id%type) is
  begin
    insert into oosactionrestriction
      (oosactionrestriction_id, oosaction_id, oosrestriction_id, systemuser_id, timestamp)
    values
      (seq_oosactionrestriction.nextval, fp_oosaction_id, fp_oosrestriction_id, systemUserID, sysdate);
  exception
    when dup_val_on_index then
      null;
  end insertFixedInfoForOOSACTIONRESTRICTION;

  procedure fixedInfoForOOSACTIONRESTRICTION is
  begin
    insertFixedInfoForOOSACTIONRESTRICTION(1, 1);
    insertFixedInfoForOOSACTIONRESTRICTION(1, 2);
    insertFixedInfoForOOSACTIONRESTRICTION(2, 1);
    insertFixedInfoForOOSACTIONRESTRICTION(2, 2);
    insertFixedInfoForOOSACTIONRESTRICTION(2, 3);
    insertFixedInfoForOOSACTIONRESTRICTION(2, 4);
    insertFixedInfoForOOSACTIONRESTRICTION(4, 1);
    insertFixedInfoForOOSACTIONRESTRICTION(4, 2);
    insertFixedInfoForOOSACTIONRESTRICTION(4, 5);
    insertFixedInfoForOOSACTIONRESTRICTION(5, 1);
    insertFixedInfoForOOSACTIONRESTRICTION(5, 2);
    insertFixedInfoForOOSACTIONRESTRICTION(5, 3);
    insertFixedInfoForOOSACTIONRESTRICTION(5, 4);
    insertFixedInfoForOOSACTIONRESTRICTION(6, 1);
    insertFixedInfoForOOSACTIONRESTRICTION(6, 2);
    insertFixedInfoForOOSACTIONRESTRICTION(10, 2);
    insertFixedInfoForOOSACTIONRESTRICTION(10, 5);
    insertFixedInfoForOOSACTIONRESTRICTION(11, 1);
    insertFixedInfoForOOSACTIONRESTRICTION(11, 2);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at OOSACTIONRESTRICTION: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForOOSACTIONRESTRICTION;

  procedure insertFixedInfoForSERVICECHARGEEVENT(fp_servicechargeevent_id servicechargeevent.servicechargeevent_id%type,
                                                 fp_factorydescription    servicechargeevent.factorydescription%type) is
  begin
    select s.servicechargeevent_id
      into id
      from servicechargeevent s
     where s.servicechargeevent_id = fp_servicechargeevent_id;
   exception
    when no_data_found then
      insert into servicechargeevent
        (servicechargeevent_id, factorydescription, systemuser_id, timestamp)
      values
        (fp_servicechargeevent_id, fp_factorydescription, systemUserID, sysdate);
  end insertFixedInfoForSERVICECHARGEEVENT;

  procedure fixedInfoForSERVICECHARGEEVENT is
  begin
    insertFixedInfoForSERVICECHARGEEVENT(1, 'Rag LOG items with RV');
    insertFixedInfoForSERVICECHARGEEVENT(2, 'Rag LOG items without RV');
    insertFixedInfoForSERVICECHARGEEVENT(3, 'Rag COG items');
    insertFixedInfoForSERVICECHARGEEVENT(4, 'Return LOG items to stock with RV');
    insertFixedInfoForSERVICECHARGEEVENT(5, 'Return LOG items to stock without RV');
    insertFixedInfoForSERVICECHARGEEVENT(6, 'Return COG items to stock');
    insertFixedInfoForSERVICECHARGEEVENT(7, 'Loss for Unique Pool Items');
    insert into servicechargeevent_desc
      (servicechargeevent_id, language_id, description, systemuser_id, timestamp)
      select servicechargeevent_id, l.language_id, factorydescription, systemUserID, sysdate
        from servicechargeevent s, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from servicechargeevent_desc sd
               where sd.servicechargeevent_id = s.servicechargeevent_id
                 and sd.language_id = l.language_id);
   commit;
      exception
         when others then
           rollback;
           write_log('Error at SERVICECHARGEEVENT: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForSERVICECHARGEEVENT;

  procedure insertFixedInfoForPREFERENCE(fp_description  preference.description%type,
                                         fp_defaultvalue preference.defaultvalue%type) is
    lv_defaultvalue preference.defaultvalue%type;
  begin
    select p.defaultvalue
      into lv_defaultvalue
      from preference p
     where p.description = fp_description;
    if (lv_defaultvalue <> fp_defaultvalue) then
      update preference p
         set p.defaultvalue = fp_defaultvalue, p.systemuser_id = systemUserID, p.timestamp = sysdate
         where p.description = fp_description;
    end if;
  exception
    when no_data_found then
      insert into preference
        (preference_id, description, defaultvalue, systemuser_id, timestamp)
      values
        (seq_preference.nextval, fp_description, fp_defaultvalue, systemUserID, sysdate);
  end insertFixedInfoForPREFERENCE;

  procedure fixedInfoForPREFERENCE is
  begin
    insertFixedInfoForPREFERENCE('FONT_SIZE', 'Compact');
    insertFixedInfoForPREFERENCE('MENU_TYPE', 'Static');
    insertFixedInfoForPREFERENCE('CURRENT_BU', null);
    insertFixedInfoForPREFERENCE('CURRENT_WORKSPOT', null);
    insertFixedInfoForPREFERENCE('CURRENT_WORKSTATION', null);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at PREFERENCE: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForPREFERENCE;

  procedure insertFixedInfoForAPPLICATIONSERVERMESSAGE(fp_applicationservermessage_id applicationservermessage.applicationservermessage_id%type,
                                                       fp_messagetype            applicationservermessage.messagetype%type,
                                                       fp_factorydescription     applicationservermessage.factorydescription%type) is
  begin
    insert into applicationservermessage
      (applicationservermessage_id, messagetype, factorydescription, systemuser_id, timestamp)
    values
      (fp_applicationservermessage_id, fp_messagetype, fp_factorydescription, systemUserID, sysdate);
  exception
    when dup_val_on_index then
      null;
  end insertFixedInfoForAPPLICATIONSERVERMESSAGE;

  procedure fixedInfoForAPPLICATIONSERVERMESSAGE is
  begin
    insertFixedInfoForAPPLICATIONSERVERMESSAGE(1,
                                               1,
                                               'The Server Application to which you are connected will be shut down at scheduled time:');
    insertFixedInfoForAPPLICATIONSERVERMESSAGE(2,
                                               2,
                                               'A new license file has been activated for the active Business Unit. Please restart your client application');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at APPLICATIONSERVERMESSAGE: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForAPPLICATIONSERVERMESSAGE;

  procedure insertFixedInfoForLICENSETRANSTYPE(fp_licensetranstype_id licensetranstype.licensetranstype_id%type,
                                               fp_description         licensetranstype.description%type) is
    lv_description licensetranstype.description%type;
  begin
    select l.description
      into lv_description
      from licensetranstype l
     where l.licensetranstype_id = fp_licensetranstype_id;
    if (lv_description <> fp_description) then
      update licensetranstype l
         set l.description = fp_description, l.systemuser_id = systemUserID, l.timestamp = sysdate
         where l.licensetranstype_id = fp_licensetranstype_id;
    end if;
  exception
    when no_data_found then
      insert into licensetranstype
        (licensetranstype_id, description, systemuser_id, timestamp)
      values
        (fp_licensetranstype_id, fp_description, systemUserID, sysdate);
  end insertFixedInfoForLICENSETRANSTYPE;

  procedure fixedInfoForLICENSETRANSTYPE is
  begin
    insertFixedInfoForLICENSETRANSTYPE(1, 'New module added');
    insertFixedInfoForLICENSETRANSTYPE(2, 'Module removed');
    insertFixedInfoForLICENSETRANSTYPE(3, 'Module parameter changed');
    insertFixedInfoForLICENSETRANSTYPE(4, 'Module demo end date changed');
    insertFixedInfoForLICENSETRANSTYPE(5, 'Number of full task users changed');
    insertFixedInfoForLICENSETRANSTYPE(6, 'Number of single task users changed');
    insertFixedInfoForLICENSETRANSTYPE(7, 'Plant added');
    insertFixedInfoForLICENSETRANSTYPE(8, 'Plant removed');
    insertFixedInfoForLICENSETRANSTYPE(9, 'License expiration date changed');
    insertFixedInfoForLICENSETRANSTYPE(10, 'New License');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at LICENSETRANSTYPE: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForLICENSETRANSTYPE;

  procedure insertFixedInfoForMULTIREADEXCEPTIONREASON(fp_multireadexceptionreason_id multireadexceptionreason.multireadexceptionreason_id%type,
                                                       fp_factorydescription          multireadexceptionreason.factorydescription%type,
                                                       fp_storelogyn                  multireadexceptionreason.storelogyn%type,
                                                       fp_priorityexceptionyn         multireadexceptionreason.priorityexceptionyn%type) is
    lv_factorydescription multireadexceptionreason.factorydescription%type;
    lv_storelogyn         multireadexceptionreason.storelogyn%type;
    lv_priorityexceptionyn multireadexceptionreason.priorityexceptionyn%type;
  begin
    select m.factorydescription, m.storelogyn, m.priorityexceptionyn
      into lv_factorydescription, lv_storelogyn, lv_priorityexceptionyn
      from multireadexceptionreason m
     where m.multireadexceptionreason_id = fp_multireadexceptionreason_id;
    if (lv_factorydescription <> fp_factorydescription) then
      update multireadexceptionreason m
         set m.factorydescription = fp_factorydescription, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.multireadexceptionreason_id = fp_multireadexceptionreason_id;
    end if;
    if (lv_storelogyn <> fp_storelogyn) then
      update multireadexceptionreason m
         set m.storelogyn = fp_storelogyn, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.multireadexceptionreason_id = fp_multireadexceptionreason_id;
    end if;
    if (lv_priorityexceptionyn <> fp_priorityexceptionyn) then
      update multireadexceptionreason m
         set m.priorityexceptionyn = fp_priorityexceptionyn, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.multireadexceptionreason_id = fp_multireadexceptionreason_id;
    end if;
  exception
    when no_data_found then
      insert into multireadexceptionreason
        (multireadexceptionreason_id, factorydescription, storelogyn, priorityexceptionyn, systemuser_id, timestamp)
      values
        (fp_multireadexceptionreason_id, fp_factorydescription, fp_storelogyn, fp_priorityexceptionyn, systemUserID, sysdate);
  end insertFixedInfoForMULTIREADEXCEPTIONREASON;

  procedure fixedInfoForMULTIREADEXCEPTIONREASON is
  begin
    insertFixedInfoForMULTIREADEXCEPTIONREASON(1, 'ID code not found in database', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(2, 'Item is not in circulation', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(3, 'Item scanned again within time interval', 'N', 'N');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(4, 'Item is ragged', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(5, 'Pool item to be scanned on delivery note', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(6, 'Not a pool item', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(7, 'OR pack not allowed', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(8, 'Item is part of a bundle, scan bundle', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(9, 'Item is for a different customer', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(10, 'Item has a flag that prohibits delivery', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(11, 'No active contract found for product', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(12, 'Already scanned at this delivery note', 'N', 'N');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(13, 'Pool item already scanned in', 'N', 'N');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(14, 'Duplicate ID Code found', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(15, 'Scanned somewhere else in the meantime', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(16, 'Item not scanned out', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(17, 'Container ID not found in database', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(18, 'Container inactive', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(19, 'Container is for a different customer', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(20, 'Container already scanned', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(21, 'Item is for a different department / cp', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(22, 'Container does not match packing note', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(23, 'Container/exchange cart has deliverystop', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(24, 'Container is put on hold.', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(25, 'Container is not exchangecart/substitute', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(26, 'Container is already scanned', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(27, 'Different container scanned', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(28, 'Container not from this businessunit', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(29, 'Item does not exist in Clean Room Batch', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(30, 'Possible Stray Read', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(31, 'Already scanned Rejected from Customer', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(32, 'Already scanned as Clean Return', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(33, 'Maximum number of rewashes', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(34, 'Too many times rewashed', 'Y', 'Y');
    insertFixedInfoForMULTIREADEXCEPTIONREASON(35, 'Client Pool', 'Y', 'Y');
    insert into multireadexceptionreason_desc
      (multireadexceptionreason_id, language_id, description, systemuser_id, timestamp)
      select m.multireadexceptionreason_id, l.language_id, m.factorydescription, systemUserID, sysdate
        from multireadexceptionreason m, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from multireadexceptionreason_desc md
               where md.multireadexceptionreason_id = m.multireadexceptionreason_id
                 and md.language_id = l.language_id);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at MULTIREADEXCEPTIONREASON: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForMULTIREADEXCEPTIONREASON;

  procedure insertFixedInfoForHELPTEXT(fp_screenid   helptext.screenid%type,
                                       fp_screenname helptext.screenname%type,
                                       fp_helptext   helptext.helptext%type) is
    lv_screenname helptext.screenname%type;
    lv_helptext   helptext.helptext%type;
  begin
    select h.screenname, h.helptext
      into lv_screenname, lv_helptext
      from helptext h
     where h.screenid = fp_screenid;
    if (lv_screenname <> fp_screenname) then
      update helptext h
         set h.screenname = fp_screenname, h.systemuser_id = systemUserID, h.timestamp = sysdate
         where h.screenid = fp_screenid;
    end if;
    if (lv_helptext <> fp_helptext) then
      update helptext h
         set h.helptext = fp_helptext, h.systemuser_id = systemUserID, h.timestamp = sysdate
         where h.screenid = fp_screenid;
    end if;
  exception
    when no_data_found then
      insert into helptext
        (helptext_id, screenid, screenname, helptext, systemuser_id, timestamp)
      values
        (seq_helptext.nextval, fp_screenid, fp_screenname, fp_helptext, systemUserID, sysdate);
  end insertFixedInfoForHELPTEXT;

  procedure fixedInfoForHELPTEXT is
  begin
    insertFixedInfoForHELPTEXT(1, 'Kiosk Login', 'Kiosk Login');
    insertFixedInfoForHELPTEXT(2, 'Phone Login', 'Phone Login');
    insertFixedInfoForHELPTEXT(3, 'My Repairs', 'My Repairs');
    insertFixedInfoForHELPTEXT(4, 'My Profile', 'My Profile');
    insertFixedInfoForHELPTEXT(5,
                               'My Profile Phone Number',
                               'This number is optional and will not be shared with any 3rd parties.
          It will only be used by the laundry to communicate with you if you log some lost items.');
    insertFixedInfoForHELPTEXT(6, 'Lost and Found', 'Lost and Found');
    insertFixedInfoForHELPTEXT(7, 'My Garments', 'My Garments');
    insertFixedInfoForHELPTEXT(8, 'My Satisfaction', 'My Satisfaction');
    insertFixedInfoForHELPTEXT(9, 'My Orders', 'My Orders');
    insertFixedInfoForHELPTEXT(10, 'My Points', 'My Points');
    insertFixedInfoForHELPTEXT(11, 'My Notifications', 'My Notifications');
    insertFixedInfoForHELPTEXT(12, 'Quick View', 'Quick View');
    insert into helptext_desc
      (helptext_id, language_id, helptext, systemuser_id, timestamp)
      select h.helptext_id, l.language_id, h.helptext, systemUserID, sysdate
        from helptext h, languages l
       where l.translatedescription = 'Y'
         and not exists (select 1
                from helptext_desc hd
               where hd.helptext_id = h.helptext_id
                 and hd.language_id = l.language_id);
     commit;
      exception
         when others then
           rollback;
           write_log('Error at HELPTEXT: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForHELPTEXT;

  procedure insertFixedInfoForMUASETTINGS(fp_name         muasettings.name%type,
                                          fp_displayname  muasettings.displayname%type,
                                          fp_type         muasettings.type%type,
                                          fp_defaultvalue muasettings.defaultvalue%type,
                                          fp_description  muasettings.description%type) is
    lv_displayname  muasettings.displayname%type;
    lv_type         muasettings.type%type;
    lv_defaultvalue muasettings.defaultvalue%type;
    lv_description  muasettings.description%type;
  begin
    select m.displayname, m.type, m.defaultvalue, m.description
      into lv_displayname, lv_type, lv_defaultvalue, lv_description
      from muasettings m
     where m.name = fp_name;
   if (lv_displayname <> fp_displayname) then
      update muasettings m
         set m.displayname = fp_displayname, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.name = fp_name;
    end if;
    if (lv_type <> fp_type) then
      update muasettings m
         set m.type = fp_type, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.name = fp_name;
    end if;
    if (lv_defaultvalue <> fp_defaultvalue) then
      update muasettings m
         set m.defaultvalue = fp_defaultvalue, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.name = fp_name;
    end if;
    if (lv_description <> fp_description) then
      update muasettings m
         set m.description = fp_description, m.systemuser_id = systemUserID, m.timestamp = sysdate
         where m.name = fp_name;
    end if;
  exception
    when no_data_found then
      insert into muasettings
        (muasettings_id, name, displayname, type, defaultvalue, description, systemuser_id, timestamp)
      values
        (seq_muasettings.nextval, fp_name, fp_displayname, fp_type, fp_defaultvalue, fp_description, systemUserID,
         sysdate);
  end insertFixedInfoForMUASETTINGS;

  procedure fixedInfoForMUASETTINGS is
  begin
    insertFixedInfoForMUASETTINGS('TWOFACTORAUTHEN',
                                  'Two Factor Login Authentication Needed',
                                  0,
                                  'Y',
                                  'Y = PIN number requested after scanning / entering garment ID');
    insertFixedInfoForMUASETTINGS('WELCOMEMETHOD',
                                  'Wearer Welcome Communication Method',
                                  1,
                                  '0',
                                  '0 = none
      1 = email
      2 = csv');
    insertFixedInfoForMUASETTINGS('PASSWORDCOMPLEXITY',
                                  'Password Complexity',
                                  1,
                                  '0',
                                  '0 = no complexity
      1 = complexity check
      >4 = minimum length, no other complexity check');
    insertFixedInfoForMUASETTINGS('SECONDARYUNIQUEIDUSED',
                                  'Secondary ID used',
                                  0,
                                  'N',
                                  'Y = check for unique id will be on primary and secondary');
    insertFixedInfoForMUASETTINGS('TIMEOUT',
                                  'System Timeout',
                                  1,
                                  '300',
                                  'Timeout in seconds that a wearer is logged out for no activity');
    insertFixedInfoForMUASETTINGS('GARMENTTILE', 'Garment Tile', 0, 'Y', 'If My Garment tile is shown');
    insertFixedInfoForMUASETTINGS('REPAIRSTILE', 'Repairs Tile', 0, 'Y', 'If My Repairs tile is shown');
    insertFixedInfoForMUASETTINGS('LOSTANDFOUNDTILE',
                                  'Lost and Found Tile',
                                  0,
                                  'Y',
                                  'If My Lost and Found tile is shown');
    insertFixedInfoForMUASETTINGS('PHONECONTACT',
                                  'Lost and Found Phone contact compulsory',
                                  0,
                                  'N',
                                  'If phone number is compulsory in Lost and Found');
    insertFixedInfoForMUASETTINGS('NUMBEROFLASTDIGITS',
                                  'Number of last digits of ID code for uniqueness',
                                  1,
                                  '5',
                                  'This is the number of least significant digits (last digits) of a garment ID code that need to be entered.  This can vary due to the spread of codes the customer has.');
    insertFixedInfoForMUASETTINGS('SYSTEMUSERNAME',
                                  'System user name used for the ABSSolute session',
                                  2,
                                  null,
                                  'Automatically generated as the customer number when the customer is switch to MUA on and is used for the ABSSolute session for all wearers.');
    insertFixedInfoForMUASETTINGS('REMOVELOSTITEMFLAGDAYS',
                                  'Number of days to automatically remove lost item flags',
                                  1,
                                  7,
                                  'When number of days is reached then via a process scheduler, all the lost item flags linked to the unique items will be deleted');
  commit;
      exception
         when others then
           rollback;
           write_log('Error at MUASETTINGS: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForMUASETTINGS;

  procedure insertFixedInfoForGLOBALSETTING(fp_name         globalsetting.name%type,
                                            fp_groupname    globalsetting.groupname%type,
                                            fp_stringvalue  globalsetting.stringvalue%type,
                                            fp_numbervalue  globalsetting.numbervalue%type,
                                            fp_booleanvalue globalsetting.booleanvalue%type,
                                            fp_typeofvalue  globalsetting.typeofvalue%type,
                                            fp_active       globalsetting.active%type,
                                            fp_description  globalsetting.description%type) is
    lv_groupname    globalsetting.groupname%type;
  begin
    select g.groupname
      into lv_groupname
      from globalsetting g
     where g.name = fp_name;
  exception
    when no_data_found then
      insert into globalsetting
        (globalsetting_id, name, groupname, stringvalue, numbervalue, booleanvalue, typeofvalue, systemuser_id,
         timestamp, active, description)
      values
        (seq_globalsetting.nextval, fp_name, fp_groupname, fp_stringvalue, fp_numbervalue, fp_booleanvalue,
         fp_typeofvalue, systemUserID, sysdate, fp_active, fp_description);
  end insertFixedInfoForGLOBALSETTING;

  procedure fixedInfoForGLOBALSETTING is
  begin
    insertFixedInfoForGLOBALSETTING('ONLINELICENSE',
                                    'Online License',
                                    null,
                                    null,
                                    'N',
                                    'B',
                                    'Y',
                                    'Use Online License mechanism.');
    insertFixedInfoForGLOBALSETTING('LICENSECHECKINTERVAL',
                                    'Online License',
                                    null,
                                    60,
                                    null,
                                    'I',
                                    'Y',
                                    'Number of seconds after the other application servers are syncronized on activation new license and clients receive notifcation. Only used with Online license.');
    insertFixedInfoForGLOBALSETTING('ENVIRONMENTCHECK',
                                    'Licensing General',
                                    null,
                                    null,
                                    'N',
                                    'B',
                                    'Y',
                                    'Use environment (Production / test) check to avoid test licenses being installed on a live environment.');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at GLOBALSETTING: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForGLOBALSETTING;

  procedure insertFixedInfoForEMAILSETTINGREPLPARAM(fp_documenttype         emailsettingreplparam.documenttype%type,
                                                    fp_replaceableparameter emailsettingreplparam.replaceableparameter%type) is
    lv_replaceableparameter emailsettingreplparam.replaceableparameter%type;
  begin
    select e.replaceableparameter
      into lv_replaceableparameter
      from emailsettingreplparam e
     where e.documenttype = fp_documenttype;
  exception
    when no_data_found then
      insert into emailsettingreplparam
        (emailsettingreplparam_id, documenttype, replaceableparameter, systemuser_id, timestamp)
      values
        (seq_emailsettingreplparam.nextval, fp_documenttype, fp_replaceableparameter, systemUserID, sysdate);
  end insertFixedInfoForEMAILSETTINGREPLPARAM;

  procedure fixedInfoForEMAILSETTINGREPLPARAM is
  begin
    insertFixedInfoForEMAILSETTINGREPLPARAM(1,
                                            q'[Parameter #B is replaced by the Customer Number of the Bill to customer
          Parameter #D is replaced by the Customer Number of the Deliver to customer
          Parameter #N is replaced by the Invoice Number]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(4, q'[Parameter # is replaced by the WebUsers password]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(16, q'[Parameter #P is replaced by the WebUsers password]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(25,
                                            q'[Parameter #C is replaced by the customer number
          Parameter #W is replaced by the department number
          Parameter #D is replaced by the consumption point number
          Parameter #P is replaced by the product code
          Parameter #S is replaced by the size code
          Parameter #F is replaced by the finishing method code
          Parameter #Q is replaced by the free-of-charge contract quantity
          Parameter #R is replaced by the total delivered quantity for the contract period
          Parameter #O is replaced by the overuse quantity
          Parameter #L is replaced by the comparison quantity
          Parameter #T is replaced by the delivery note number]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(26, q'[No change, only used in PLSQL for now]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(27,
                                            q'[Parameter #N is replaced by the URL to change the PIN number
          Parameter #W is replaced by the wearer's full name]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(28,
                                            q'[Parameter #W is replaced by the wearer's full name
          Parameter #P is replaced by the URL to change the wearer's password]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(30, q'[Parameter #W is replaced by the wearer's full name]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(31,
                                            q'[Parameter #W is replaced by the wearer's full name
          Parameter #L is replaced by the URL of the web page
          Parameter #P is replaced by the wearer's password]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(32,
                                            q'[Parameter #W is replaced by the wearer's full name
          Parameter #U is replaced by the new username]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(33,
                                            q'[Parameter #A is replaced by the payment amount
          Parameter #C is replaced by the customer number
          Parameter #D is replaced by the payment date
          Parameter #I is replaced by the invoice number
          Parameter #P is replaced by the payment method
          Parameter #R is replaced by the payment reference]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(37, q'[Parameter #A is replaced by the customer number
              Parameter #B is replaced by the department
              Parameter #C is replaced by the contact number
              Parameter #D is replaced by the follow-up date
              Parameter #E is replaced by the contact person name
              Parameter #L is replaced by the URL of the web page
              Parameter #M is replaced by the category
              Parameter #N is replaced by the cause
              Parameter #O is replaced by the priority
              Parameter #R is replaced by the resolution
              Parameter #S is replaced by the status
              Parameter #T is replaced by the activity (long) description]');
    insertFixedInfoForEMAILSETTINGREPLPARAM(38, q'[Parameter #A is replaced by the customer number
            Parameter #B is replaced by the department
            Parameter #C is replaced by the contact number
            Parameter #D is replaced by the follow-up date
            Parameter #E is replaced by the contact person name
            Parameter #M is replaced by the category
            Parameter #N is replaced by the cause
            Parameter #L is replaced by the web user login name
            Parameter #O is replaced by the priority
            Parameter #R is replaced by the resolution
            Parameter #S is replaced by the status
            Parameter #T is replaced by the activity description
            Parameter #W is replaced by the web user e-mail address]');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at EMAILSETTINGREPLPARAM: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForEMAILSETTINGREPLPARAM;


  procedure insertFixedInfoForFINANCIALYEARCONVERSION(fp_startdate     financialyearconversion.startdate%type,
                                                      fp_financialyear financialyearconversion.financialyear%type,
                                                      fp_period        financialyearconversion.period%type,
                                                      fp_financialweek financialyearconversion.financialweek%type) is
  begin
    select 1
      into id
      from financialyearconversion f
     where f.financialyear = fp_financialyear and f.financialweek = fp_financialweek;
  exception
    when no_data_found then
      insert into financialyearconversion
        (startdate, financialyear, period, financialweek, systemuser_id, timestamp)
      values
        (fp_startdate, fp_financialyear, fp_period, fp_financialweek, systemUserID, sysdate);
  end insertFixedInfoForFINANCIALYEARCONVERSION;

  procedure fixedInfoForFINANCIALYEARCONVERSION is
  begin
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('28-10-2012', 'dd-mm-yyyy'), 112, 1, 1);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('04-11-2012', 'dd-mm-yyyy'), 112, 1, 2);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('11-11-2012', 'dd-mm-yyyy'), 112, 1, 3);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('18-11-2012', 'dd-mm-yyyy'), 112, 1, 4);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('25-11-2012', 'dd-mm-yyyy'), 112, 2, 5);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('02-12-2012', 'dd-mm-yyyy'), 112, 2, 6);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('09-12-2012', 'dd-mm-yyyy'), 112, 2, 7);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('16-12-2012', 'dd-mm-yyyy'), 112, 2, 8);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('23-12-2012', 'dd-mm-yyyy'), 112, 2, 9);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('30-12-2012', 'dd-mm-yyyy'), 112, 3, 10);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('06-01-2013', 'dd-mm-yyyy'), 112, 3, 11);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('13-01-2013', 'dd-mm-yyyy'), 112, 3, 12);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('20-01-2013', 'dd-mm-yyyy'), 112, 3, 13);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('27-01-2013', 'dd-mm-yyyy'), 112, 4, 14);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('03-02-2013', 'dd-mm-yyyy'), 112, 4, 15);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('10-02-2013', 'dd-mm-yyyy'), 112, 4, 16);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('17-02-2013', 'dd-mm-yyyy'), 112, 4, 17);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('24-02-2013', 'dd-mm-yyyy'), 112, 5, 18);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('03-03-2013', 'dd-mm-yyyy'), 112, 5, 19);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('10-03-2013', 'dd-mm-yyyy'), 112, 5, 20);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('17-03-2013', 'dd-mm-yyyy'), 112, 5, 21);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('24-03-2013', 'dd-mm-yyyy'), 112, 5, 22);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('31-03-2013', 'dd-mm-yyyy'), 112, 6, 23);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('07-04-2013', 'dd-mm-yyyy'), 112, 6, 24);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('14-04-2013', 'dd-mm-yyyy'), 112, 6, 25);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('21-04-2013', 'dd-mm-yyyy'), 112, 6, 26);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('28-04-2013', 'dd-mm-yyyy'), 112, 7, 27);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('05-05-2013', 'dd-mm-yyyy'), 112, 7, 28);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('12-05-2013', 'dd-mm-yyyy'), 112, 7, 29);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('19-05-2013', 'dd-mm-yyyy'), 112, 7, 30);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('26-05-2013', 'dd-mm-yyyy'), 112, 8, 31);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('02-06-2013', 'dd-mm-yyyy'), 112, 8, 32);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('09-06-2013', 'dd-mm-yyyy'), 112, 8, 33);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('16-06-2013', 'dd-mm-yyyy'), 112, 8, 34);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('23-06-2013', 'dd-mm-yyyy'), 112, 8, 35);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('30-06-2013', 'dd-mm-yyyy'), 112, 9, 36);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('07-07-2013', 'dd-mm-yyyy'), 112, 9, 37);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('14-07-2012', 'dd-mm-yyyy'), 112, 9, 38);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('21-07-2013', 'dd-mm-yyyy'), 112, 9, 39);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('28-07-2013', 'dd-mm-yyyy'), 112, 10, 40);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('04-08-2012', 'dd-mm-yyyy'), 112, 10, 41);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('11-08-2013', 'dd-mm-yyyy'), 112, 10, 42);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('18-08-2013', 'dd-mm-yyyy'), 112, 10, 43);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('25-08-2013', 'dd-mm-yyyy'), 112, 11, 44);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('01-09-2013', 'dd-mm-yyyy'), 112, 11, 45);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('08-09-2013', 'dd-mm-yyyy'), 112, 11, 46);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('15-09-2013', 'dd-mm-yyyy'), 112, 11, 47);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('22-09-2013', 'dd-mm-yyyy'), 112, 11, 48);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('29-09-2013', 'dd-mm-yyyy'), 112, 12, 49);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('06-10-2013', 'dd-mm-yyyy'), 112, 12, 50);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('13-10-2013', 'DD-MM-YYYY'), 112, 12, 51);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('20-10-2013', 'dd-mm-yyyy'), 112, 12, 52);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('27-10-2013', 'dd-mm-yyyy'), 113, 1, 1);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('03-11-2013', 'dd-mm-yyyy'), 113, 1, 2);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('10-11-2013', 'dd-mm-yyyy'), 113, 1, 3);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('17-11-2013', 'dd-mm-yyyy'), 113, 1, 4);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('24-11-2013', 'dd-mm-yyyy'), 113, 2, 5);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('01-12-2013', 'dd-mm-yyyy'), 113, 2, 6);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('08-12-2013', 'dd-mm-yyyy'), 113, 2, 7);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('15-12-2013', 'dd-mm-yyyy'), 113, 2, 8);
    insertFixedInfoForFINANCIALYEARCONVERSION(to_date('22-12-2013', 'dd-mm-yyyy'), 113, 2, 9);
    commit;
      exception
         when others then
           rollback;
           write_log('Error at FINANCIALYEARCONVERSION: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForFINANCIALYEARCONVERSION;

  procedure insertFixedInfoForDATABASESCRIPT(fp_code             databasescript.code%type,
                                             fp_usage            databasescript.usage%type,
                                             fp_description      databasescript.description%type,
                                             fp_script           databasescript.script%type,
                                             fp_active           databasescript.active%type,
                                             fp_executionhistory databasescript.executionhistory%type) is
  begin
    begin
      insert into databasescript
        (databasescript_id, code, usage, description, script, active, executionhistory, systemuser_id, timestamp)
      values
        (seq_databasescript.nextval, fp_code, fp_usage, fp_description, fp_script, fp_active, fp_executionhistory,
         systemUserID, sysdate);
    exception
      when dup_val_on_index then
        null;
    end;
  end insertFixedInfoForDATABASESCRIPT;

  procedure fixedInfoForDATABASESCRIPT is
  begin
    insertFixedInfoForDATABASESCRIPT('ENCRYP',
                                     5,
                                     'Masks all personal and sensitive data in the database for compliancy & IT regulation. Masking is not reversible. Only use on non-production environments',
                                     'begin
                                         PACK_ABSDBENCRYPT_CUSTOMER.ENCRYPT_FULL_SCHEMA;
                                         end;',
                                     'Y',
                                     'Y');
    insert into absdbencrypt
      (absdbencrypted)
    values
      ('N');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at DATABASESCRIPT: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForDATABASESCRIPT;

  procedure fixedInfoForLOSSGRACESCHEME is
  begin
    select l.lossgracescheme_id
      into id
      from lossgracescheme l
     where l.code = '-';
  exception
    when no_data_found then
      insert into lossgracescheme
        (lossgracescheme_id, code, systemuser_id, timestamp)
        select seq_lossgracescheme.nextval, '-', systemUserID, sysdate
          from dual;
      insert into lossgracescheme_desc
        (lossgracescheme_id, language_id, description, systemuser_id, timestamp)
        select lgs.lossgracescheme_id, l.language_id, '-', systemUserID, sysdate
          from lossgracescheme lgs, languages l
         where l.translatedescription = 'Y'
           and not exists (select 1
                  from lossgracescheme_desc ld
                 where ld.lossgracescheme_id = lgs.lossgracescheme_id);
       insert into lossgraceschemedetail(lossgracescheme_id, numberofdays, percentage, systemuser_id, timestamp)
       select lgs.lossgracescheme_id, 56, 100, systemUserID, sysdate from lossgracescheme lgs;
       insert into lossgraceschemedetail(lossgracescheme_id, numberofdays, percentage, systemuser_id, timestamp)
       select lgs.lossgracescheme_id, 337, 50, systemUserID, sysdate from lossgracescheme lgs;
       commit;
       when others then
           rollback;
           write_log('Error at LOSSGRACESCHEME: ' || sqlerrm, 3);
           fp_error := 1;
  end fixedInfoForLOSSGRACESCHEME;

  procedure insertFixedInfoForEXTSTOCKTRANSTYPE(fp_code               extstocktranstype.code%type,
                                                fp_keycode            extstocktranstype.keycode%type,
                                                fp_factorydescription extstocktranstype.factorydescription%type,
                                                fp_active             extstocktranstype.active%type) is
    lv_keycode            extstocktranstype.keycode%type;
    lv_factorydescription extstocktranstype.factorydescription%type;
    lv_active             extstocktranstype.active%type;
  begin
    select keycode, factorydescription, active
      into lv_keycode, lv_factorydescription, lv_active
      from extstocktranstype e
     where e.code = fp_code;
  exception
    when no_data_found then
      insert into extstocktranstype
        (extstocktranstype_id, code, keycode, factorydescription, systemuser_id, timestamp, active)
      values
        (seq_extstocktranstype.nextval, fp_code, fp_keycode, fp_factorydescription, systemUserID, sysdate, fp_active);
  end insertFixedInfoForEXTSTOCKTRANSTYPE;

  procedure fixedInfoForEXTSTOCKTRANSTYPE is
  begin
    insertFixedInfoForEXTSTOCKTRANSTYPE('0001', 'AB', 'Issue Goods Sold', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0002', 'AG', 'Issue Rental Goods', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0003', 'AR', 'Issue Spare Parts', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0004', 'AS', 'Ragged', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0005', 'AV', 'Manual Issue', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0006', 'AW', 'Devaluation', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0007', 'AX', 'Issue MVG/FIBU', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0008', 'AY', 'Issue ABO', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0009', 'EG', 'Receive in stock', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0010', 'I+', 'Inventory +', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0011', 'I-', 'Inventory -', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0012', 'RE', 'Return Sold Goods', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0013', 'RM', 'Return Rental Goods', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0014', 'RR', 'Return Spare Parts', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0015', 'RT', 'Retour Depot/Depot', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0016', 'RV', 'Manual Return', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0017', 'RX', 'Return MVG/FIBU', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0018', 'RY', 'Return ABO', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0019', 'SV', 'Balance correction', 'N');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0020', 'UB', 'Stock Transfer', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0021', 'UD', 'Location update stockroom', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0022', 'UF', 'Location update related to truck', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0023', 'UX', 'Correction stock transfer', 'N');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0024', 'ZG', 'Receive from supplier', 'Y');
    insertFixedInfoForEXTSTOCKTRANSTYPE('0025', 'ZU', 'Issue Sample Goods', 'N');
    insert into extstocktranstype_desc
      (extstocktranstype_id, language_id, description, systemuser_id, timestamp)
      select e.extstocktranstype_id, l.language_id, e.code, systemUserID, sysdate
        from extstocktranstype e, languages l
        where l.translatedescription = 'Y' and
        not exists (select 1
                from extstocktranstype_desc ed
               where ed.extstocktranstype_id = e.extstocktranstype_id
                 and ed.language_id = l.language_id);
    commit;
      exception
        when others then
          rollback;
          write_log('Error at EXTSTOCKTRANSTYPE: ' || sqlerrm, 3);
          fp_error := 1;
  end fixedInfoForEXTSTOCKTRANSTYPE;

  procedure fixedInfoForEMPLOYEEFUNCTION is
  begin
    select ef.employeefunction_id
      into id
      from employeefunction ef
     where ef.code = '-';
  exception
    when no_data_found then
      insert into employeefunction
        (employeefunction_id, code, description, active, systemuser_id, timestamp)
      values
        (seq_employeefunction.nextval, '-', '-', 'Y', systemUserID, sysdate)
      returning employeefunction_id into id;

      insert into employeefunctionauth
        (employeefunctionauth_id, employeefunction_id, ordertype, authorizationlevel, systemuser_id, timestamp)
        select seq_employeefunctionauth.nextval, id, ot.ordertype, 2, systemUserID, sysdate
          from (select rownum ordertype
                   from user_tables
                  where rownum between 1 and 3) ot;
  commit;
  when others then
          rollback;
          write_log('Error at EMPLOYEEFUNCTION: ' || sqlerrm, 3);
          fp_error := 1;
  end fixedInfoForEMPLOYEEFUNCTION;

  procedure fixedInfoForEMPLOYEEFUNCTIONDIALOG is
    begin
      insert into employeefunctiondialog
        (employeefunction_id,
         dialog_id,
         selectable,
         systemuser_id,
         timestamp)
        select ef.employeefunction_id,
               d.dialog_id,
               'Y',
               systemUserID,
               sysdate
          from dialogs d, employeefunction ef
         where not exists (select 1
                  from employeefunctiondialog e
                 where e.dialog_id = d.dialog_id)
           and d.code in ('Route',
                          'Truck',
                          'RouteStatusControl',
                          'DeliveryNote',
                          'Customer',
                          'Contract',
                          'ProductListPerCustomer',
                          'Batch',
                          'OutscanSort',
                          'BatchDeliveryNote',
                          'StockRoom',
                          'WeighingTicket',
                          'CustomerActivities',
                          'StandardDelivery',
                          'WorkOrder',
                          'PostalCodesPerCountry',
                          'AssemblePackScan',
                          'LoadCarts',
                          'ConfirmSterilization',
                          'RewashScan',
                          'PackingNoteOverview',
                          'ContainerShippingScan');
      insert into employeefunctiondialog
        (employeefunction_id,
         dialog_id,
         selectable,
         systemuser_id,
         timestamp)
        select ef.employeefunction_id, d.dialog_id, 'N', 1, sysdate
          from dialogs d, employeefunction ef
         where not exists (select 1
                  from employeefunctiondialog e
                 where e.dialog_id = d.dialog_id)
           and d.code in ('SalesOrder');
      commit;
      exception
    when
    others then rollback;
    write_log('Error at EMPLOYEEFUNCTIONDIALOG: ' || sqlerrm, 3);
    fp_error := 1;
    end fixedInfoForEMPLOYEEFUNCTIONDIALOG;

  procedure fixedInfoForDISTRICT is
  begin
    select d.district_id
      into id
      from district d
     where d.code = '-';
  exception
    when no_data_found then
      insert into district
        (district_id, code, description, systemuser_id, timestamp)
      values
        (seq_district.nextval, '-', '-', systemUserID, sysdate)
      returning district_id into id;
      insert into districtplant
        (district_id, plant_id, employee_id, systemuser_id, timestamp)
        (select id, pl, emp, systemUserID, sysdate
           from (select e.plant_id pl, e.employee_id emp
                    from employee e, plant
                   where e.plant_id = plant.plant_id
                     and e.employeenumber = (select min(e.employeenumber)
                                               from employee e)));
    commit;
    when others then
      rollback;
      write_log('Error at DISTRICT: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDISTRICT;

  procedure fixedInfoForEMPLOYEE is
    numberOfEmployees number;
  begin
    select count(1)
      into numberOfEmployees
      from employee e;
    if (numberOfEmployees = 0) then
      insert into employee e
        (PLANT_ID, EMPLOYEE_ID, EMPLOYEENUMBER, name, SEARCHNAME, DATEACTIVE, SYSTEMUSER_ID, DATEINACTIVE, timestamp,
         PDANUMBER, MOBILEDEVICE_ID, WORKSPOT, EMPLOYEEFUNCTION_ID)
        select pl.plant_id, seq_employee.nextval, pl.plant_id, '-', '-', sysdate, systemUserID,
               to_date('31-12-2099', 'dd-mm-yyyy'), sysdate, 0, null, 0, ef.employeefunction_id
          from employeefunction ef, plant pl;
    end if;
    commit;
  exception
    when others then
      rollback;
      write_log('Error at EMPLOYEE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForEMPLOYEE;

  procedure fixedInfoForDWH_SETTINGS is
  begin
    select count(1)
      into id
      from dwh_settings;
    if (id = 0) then
      insert into dwh_settings
        (dwh_settings_id, year_start_date, number_of_years, fiscal_type, language_id, loadpimsyn, systemuser_id,
         timestamp, period_type, short_date_format, long_date_format, nls_language, nls_territory, fiscal_week_offset,
         fiscal_month_offset)
        select 1, to_date('1-1-2000', 'dd-mm-yyyy'), 30, 544,
               nvl((select min(l.language_id)
                      from languages l
                     where l.translatedescription = 'Y'),
                    (select min(l2.language_id)
                       from languages l2)), 'N', systemUserID, sysdate, 544, 'FmDD-Mon-YYYY', 'FmDD Month YYYY',
               'ENGLISH', 'AMERICA', 0, 0
          from dual;
    end if;
   commit;
  exception
    when others then
      rollback;
      write_log('Error at DWH_SETTINGS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDWH_SETTINGS;

  procedure insertFixedInfoForDWH_SETTINGSPERTABLE(fp_tablename    dwh_settingspertable.tablename%type,
                                                   fp_isfactyn     dwh_settingspertable.isfactyn%type,
                                                   fp_loadyn       dwh_settingspertable.loadyn%type,
                                                   fp_sourcesystem dwh_settingspertable.sourcesystem%type) is
  begin
    select d.sourcesystem
      into id
      from dwh_settingspertable d
     where d.tablename = fp_tablename;
  exception
    when no_data_found then
      insert into dwh_settingspertable
        (tablename, isfactyn, loadyn, systemuser_id, timestamp, sourcesystem)
      values
        (fp_tablename, fp_isfactyn, fp_loadyn, systemUserID, to_date('01-01-2009', 'dd-mm-yyyy'), fp_sourcesystem);
  end insertFixedInfoForDWH_SETTINGSPERTABLE;

  procedure fixedInfoForDWH_SETTINGSPERTABLE is
  begin
    insertFixedInfoForDWH_SETTINGSPERTABLE('PRODUCTION_QUANTITIES', 'Y', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('GARMENT_ISSUE', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CLEAN_WEIGHT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('SOIL_WEIGHT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEIGHINGCATEGORY', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('TURNOVERGROUP', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('BUSINESSUNIT', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('ROUTE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('QUALITYGRADE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('PRODUCT', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CHARGETYPE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('DELIVERIES', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CURRENCY', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('INVOICE', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('GROWTHREASON', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('REVENUE_GROWTH', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('REASONCODE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('REVENUE', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CUSTOMER', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('TIME', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('FINISHINGMETHOD', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CONTACTCATEGORY', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CLOSED_CONTACTS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('DELIVERY_NOTE', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('COSTS_PBA', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CREDITS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('STAY', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('TRANSACTION_TYPE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('STOCK_ROOM', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('SYSTEM_USER', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('SCANS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('ROUTE_HISTORY', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WORKSPOT', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('SHIFT', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('HOUR_TYPE', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('ABSENCE_REASON', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('PIMS_EMPLOYEE', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('JOB_CODE', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('PIMS_BUSINESS_UNIT', 'N', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('AR_AGING_SNAPSHOT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('AR_TRANSACTION_TYPE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('AR_TRANSACTIONS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('GARMENT_SALES', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('SOIL_COUNTS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('STOCK_TRANSACTIONS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CIRC_INV_SNAPSHOT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('SETS_IN_CIRC_SNAPSHOT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('REPAIR_TYPE', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('REPAIRS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('PRODUCTION_HOURS', 'Y', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('ABSENCE_HOURS', 'Y', 'Y', 1);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEARER_SNAPSHOT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WORKSTATION', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('STATUS', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEEKLY_BUSINESS_UNIT_TARGETS', 'Y', 'N', 2);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEEKLY_CORPORATE_TARGETS', 'Y', 'N', 2);
    insertFixedInfoForDWH_SETTINGSPERTABLE('VISIT_HISTORY', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('STOCK_QUANTITY_SNAPSHOT', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEARER_EMPLOYMENT', 'N', 'N', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEARER_INVENTORY', 'Y', 'N', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WORK_ORDERS', 'Y', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('GL_SEGMENT', 'N', 'N', 2);
    insertFixedInfoForDWH_SETTINGSPERTABLE('FINANCIAL_TRANSACTION', 'Y', 'N', 2);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WORK_ORDER_DIM', 'N', 'Y', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('WEEKLY_REVENUE', 'Y', 'N', 0);
    insertFixedInfoForDWH_SETTINGSPERTABLE('CIRC_INV_ADJUST', 'Y', 'Y', 0);
   commit;
  exception
    when others then
      rollback;
      write_log('Error at DWH_SETTINGSPERTABLE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDWH_SETTINGSPERTABLE;
  procedure insertFixedInfoForDWH_STRINGS(fp_dwh_string_id      dwh_string.dwh_string_id%type,
                                          fp_factorydescription dwh_string.factorydescription%type,
                                          fp_maxstringlength    dwh_string.maxstringlength%type,
                                          fp_dimension_table    dwh_string.dimension_table%type,
                                          fp_dimension_column   dwh_string.dimension_column%type) is
  begin
    select d.dwh_string_id
      into id
      from dwh_string d
     where d.dwh_string_id = fp_dwh_string_id;
  exception
    when no_data_found then
      insert into DWH_STRING
        (DWH_STRING_ID, FACTORYDESCRIPTION, MAXSTRINGLENGTH, DIMENSION_TABLE, DIMENSION_COLUMN, SYSTEMUSER_ID, timestamp)
      values
        (fp_dwh_string_id, fp_factorydescription, fp_maxstringlength, fp_dimension_table, fp_dimension_column,
         systemUserID, to_date('01-01-2009', 'dd-mm-yyyy'));
  end insertFixedInfoForDWH_STRINGS;

  procedure fixedInfoForDWH_STRINGS is
  begin
    insertFixedInfoForDWH_STRINGS(1, 'Yes', 10, 'General', null);
    insertFixedInfoForDWH_STRINGS(2, 'No', 10, 'General', null);
    insertFixedInfoForDWH_STRINGS(3, 'Unknown', 10, 'General', null);
    insertFixedInfoForDWH_STRINGS(4, 'Not Applicable', 30, 'General', null);
    insertFixedInfoForDWH_STRINGS(5, 'N/A', 6, 'General', null);
    insertFixedInfoForDWH_STRINGS(6, 'Not Defined', 30, 'General', null);
    insertFixedInfoForDWH_STRINGS(7, 'Obsolete', 15, 'General', null);
    insertFixedInfoForDWH_STRINGS(8, 'Active', 15, 'General', null);
    insertFixedInfoForDWH_STRINGS(9, 'Inactive', 15, 'General', null);
    insertFixedInfoForDWH_STRINGS(10, 'All', 15, 'General', null);
    insertFixedInfoForDWH_STRINGS(20, 'W', 15, 'Calendar Time', 'Week Code');
    insertFixedInfoForDWH_STRINGS(21, 'Week', 15, 'Calendar Time', 'Week Name');
    insertFixedInfoForDWH_STRINGS(22, 'P', 15, 'Calendar Time', 'Period Code');
    insertFixedInfoForDWH_STRINGS(23, 'Period', 15, 'Calendar Time', 'Period Name');
    insertFixedInfoForDWH_STRINGS(24, 'Q', 15, 'Calendar Time', 'Quarter Code');
    insertFixedInfoForDWH_STRINGS(25, 'Quarter', 15, 'Calendar Time', 'Quarter Name');
    insertFixedInfoForDWH_STRINGS(30, 'COD', 30, 'Customer', 'Payment Method');
    insertFixedInfoForDWH_STRINGS(31, 'Charge', 30, 'Customer', 'Payment Method');
    insertFixedInfoForDWH_STRINGS(32, 'Cash', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(33, 'Check', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(34, 'Credit Card', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(35, 'Electronic Fund Transfer', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(36, 'EDI', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(37, 'Accept Giro', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(38, 'Automatic Collection', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(39, 'Via pay-by Customer', 30, 'Customer', 'Payment Type');
    insertFixedInfoForDWH_STRINGS(40, 'Rent Billing Method Unknown', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(41, 'Flat Rated Rent', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(42, 'Minimum Based Rent', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(43, 'Inventory Based Rent', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(44, 'Piece Rated Rent', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(45, 'Lease', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(46, 'Unrelated Loan', 30, 'Charge Type', 'Charge Description');
    insertFixedInfoForDWH_STRINGS(50, 'From Plant', 30, 'Route', 'Depot');
    insertFixedInfoForDWH_STRINGS(51, 'Not linked to Route', 30, 'Route', 'Route Description');
    insertFixedInfoForDWH_STRINGS(60, 'Non Garments', 30, 'Product', 'Type of Merchandize');
    insertFixedInfoForDWH_STRINGS(61, 'Garments', 30, 'Product', 'Type of Merchandize');
    insertFixedInfoForDWH_STRINGS(62, 'Sales-only Items/Disposables', 30, 'Product', 'Type of Merchandize');
    insertFixedInfoForDWH_STRINGS(63, 'Emblems', 30, 'Product', 'Type of Merchandize');
    insertFixedInfoForDWH_STRINGS(64, 'Residential Garments', 30, 'Product', 'Type of Merchandize');
    insertFixedInfoForDWH_STRINGS(65, 'Not Soil Counted', 20, 'Product', 'Soil Count Method');
    insertFixedInfoForDWH_STRINGS(66, 'Manual', 20, 'Product', 'Soil Count Method');
    insertFixedInfoForDWH_STRINGS(67, 'Auto Return Assumed', 20, 'Product', 'Soil Count Method');
    insertFixedInfoForDWH_STRINGS(68, 'Weight Based', 20, 'Product', 'Soil Count Method');
    insertFixedInfoForDWH_STRINGS(69, 'Delayed Even Exchange', 40, 'Product', 'Exchange Method');
    insertFixedInfoForDWH_STRINGS(70, 'Straight Even Exchange', 40, 'Product', 'Exchange Method');
    insertFixedInfoForDWH_STRINGS(71, 'Delivery based on order/standards', 40, 'Product', 'Exchange Method');
    insertFixedInfoForDWH_STRINGS(80, 'New', 10, 'Quality Grade', 'New Used');
    insertFixedInfoForDWH_STRINGS(81, 'Used', 10, 'Quality Grade', 'New Used');
    insertFixedInfoForDWH_STRINGS(85, 'New / Increase', 30, 'Growth Reason', 'Growth Reason Type');
    insertFixedInfoForDWH_STRINGS(86, 'Quit / Decrease', 30, 'Growth Reason', 'Growth Reason Type');
    insertFixedInfoForDWH_STRINGS(91, 'New/Quit Customer', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(92, 'New/Quit Customer Product', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(93, 'Changed Customer Product', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(94, 'New/Quit Wearers', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(95, 'New/Quit Wearer Products', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(96, 'Wearer Inventory Changes', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(97, 'Price Changes', 30, 'Growth Reason', 'Net Growth Reason');
    insertFixedInfoForDWH_STRINGS(101, 'New Customer', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(102, 'Quit Customer', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(103, 'New Customer Product', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(104, 'Quit Customer Product', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(105, 'Increased Customer Product', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(106, 'Decreased Customer Product', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(107, 'New Wearer', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(108, 'Quit Wearer', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(109, 'New Wearer Product', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(110, 'Quit Wearer Product', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(111, 'Increased Wearer Inventory', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(112, 'Decreased Wearer Inventory', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(113, 'Price Increase', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(114, 'Price Decrease', 30, 'Growth Reason', 'Growth Reason');
    insertFixedInfoForDWH_STRINGS(120, 'Fscl W', 15, 'Fiscal Time', 'Week Code');
    insertFixedInfoForDWH_STRINGS(121, 'Fiscal Week', 15, 'Fiscal Time', 'Week Name');
    insertFixedInfoForDWH_STRINGS(122, 'Fscl P', 15, 'Fiscal Time', 'Period Code');
    insertFixedInfoForDWH_STRINGS(123, 'Fiscal Period', 15, 'Fiscal Time', 'Period Name');
    insertFixedInfoForDWH_STRINGS(124, 'Fscl Q', 15, 'Fiscal Time', 'Quarter Code');
    insertFixedInfoForDWH_STRINGS(125, 'Fiscal Quarter', 15, 'Fiscal Time', 'Quarter Name');
    insertFixedInfoForDWH_STRINGS(200, 'Delivery Standards', 30, 'Customer', 'Standard Quantity Definition');
    insertFixedInfoForDWH_STRINGS(201, 'Usage Standards', 30, 'Customer', 'Standard Quantity Definition');
    insertFixedInfoForDWH_STRINGS(202, 'This Customer', 30, 'Customer', 'Containers Owned By');
    insertFixedInfoForDWH_STRINGS(203, 'Bill-to Customer', 30, 'Customer', 'Containers Owned By');
    insertFixedInfoForDWH_STRINGS(204, 'Master Account', 30, 'Customer', 'Containers Owned By');
    insertFixedInfoForDWH_STRINGS(205, 'Laundry', 30, 'Customer', 'Containers Owned By');
    insertFixedInfoForDWH_STRINGS(206, 'Customer', 30, 'Customer', 'Consignment Note Level');
    insertFixedInfoForDWH_STRINGS(207, 'Department', 30, 'Customer', 'Consignment Note Level');
    insertFixedInfoForDWH_STRINGS(208, 'Delivery Point', 30, 'Customer', 'Consignment Note Level');
    insertFixedInfoForDWH_STRINGS(210, 'No Sorting Info', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(211, 'Department', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(212, 'Bank / Locker', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(213, 'Garment Dispenser', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(214, 'Delivery Point', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(215, 'Service Team', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(216, 'Finishing Method', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(217, 'Size', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(218, 'Bank / Locker + Sticker', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(219, 'Sort Address', 30, 'Customer', 'Outscan Sort By');
    insertFixedInfoForDWH_STRINGS(230, 'General Price List', 30, 'Customer', 'Insurance Price Type');
    insertFixedInfoForDWH_STRINGS(231, 'Customer Specific Price', 30, 'Customer', 'Insurance Price Type');
    insertFixedInfoForDWH_STRINGS(235, 'Charge Fixed # of Banks ', 30, 'Customer', 'Locker Rent Type');
    insertFixedInfoForDWH_STRINGS(236, 'Charge per Occupied Locker', 30, 'Customer', 'Locker Rent Type');
    insertFixedInfoForDWH_STRINGS(237, 'Charge # of Bank/Lockers ', 30, 'Customer', 'Locker Service Charge Type');
    insertFixedInfoForDWH_STRINGS(238, 'Charge # Pcs per Bank/Locker', 30, 'Customer', 'Locker Service Charge Type');
    insertFixedInfoForDWH_STRINGS(240, 'Regular Mail', 30, 'Customer', 'Send Invoice By');
    insertFixedInfoForDWH_STRINGS(241, 'Fax', 30, 'Customer', 'Send Invoice By');
    insertFixedInfoForDWH_STRINGS(242, 'E-mail', 30, 'Customer', 'Send Invoice By');
    insertFixedInfoForDWH_STRINGS(243, 'EDI', 30, 'Customer', 'Send Invoice By');
    insertFixedInfoForDWH_STRINGS(251, 'Products by Wearer', 30, 'Customer', 'Garment Rent Specification');
    insertFixedInfoForDWH_STRINGS(252, 'Products by Wearer Condensed', 30, 'Customer', 'Garment Rent Specification');
    insertFixedInfoForDWH_STRINGS(253, 'Wearer Totals Only', 30, 'Customer', 'Garment Rent Specification');
    insertFixedInfoForDWH_STRINGS(254, 'By Product', 30, 'Customer', 'Garment Rent Specification');
    insertFixedInfoForDWH_STRINGS(255, 'Number of Men per Total Price', 30, 'Customer', 'Garment Rent Specification');
    insertFixedInfoForDWH_STRINGS(256, 'Summary Pers.Billing TotalCode', 30, 'Customer', 'Garment Rent Specification');
    insertFixedInfoForDWH_STRINGS(260, 'In Arrear', 30, 'Customer', 'Rent Period');
    insertFixedInfoForDWH_STRINGS(261, 'In Advance Correct Addit. Only', 30, 'Customer', 'Rent Period');
    insertFixedInfoForDWH_STRINGS(262, 'In Advance', 30, 'Customer', 'Rent Period');
    insertFixedInfoForDWH_STRINGS(265, 'No Split', 30, 'Customer', 'Split Invoice');
    insertFixedInfoForDWH_STRINGS(266, 'Per product grouping code', 30, 'Customer', 'Split Invoice');
    insertFixedInfoForDWH_STRINGS(267, 'Per Cost Center', 30, 'Customer', 'Split Invoice');
    insertFixedInfoForDWH_STRINGS(268, 'Rent / Other services', 30, 'Customer', 'Split Invoice');
    insertFixedInfoForDWH_STRINGS(270, 'Invoice', 30, 'Customer', 'Finance Charge Put On');
    insertFixedInfoForDWH_STRINGS(271, 'Statement', 30, 'Customer', 'Finance Charge Put On');
    insertFixedInfoForDWH_STRINGS(275, 'Other', 30, 'Customer', 'Credit Card Type');
    insertFixedInfoForDWH_STRINGS(281, 'Always', 30, 'Customer', 'Send Statement');
    insertFixedInfoForDWH_STRINGS(282, 'Only When Past Due', 30, 'Customer', 'Send Statement');
    insertFixedInfoForDWH_STRINGS(283, 'Never', 30, 'Customer', 'Send Statement');
    insertFixedInfoForDWH_STRINGS(285, 'Yes, Bulk Inscan Allowed', 30, 'Customer', 'Residential Inscan');
    insertFixedInfoForDWH_STRINGS(286, 'Yes, but Not in Bulk', 30, 'Customer', 'Residential Inscan');
    insertFixedInfoForDWH_STRINGS(290, 'Sequence# Delivery Note', 30, 'Customer', 'Sort Order Residential Washes');
    insertFixedInfoForDWH_STRINGS(291, 'Client Number', 30, 'Customer', 'Sort Order Residential Washes');
    insertFixedInfoForDWH_STRINGS(292, 'Client Search Name', 30, 'Customer', 'Sort Order Residential Washes');
    insertFixedInfoForDWH_STRINGS(293, 'Department / Room#', 30, 'Customer', 'Sort Order Residential Washes');
    insertFixedInfoForDWH_STRINGS(301, 'Next Visit', 30, 'Customer', 'Return Residential Items');
    insertFixedInfoForDWH_STRINGS(302, 'Same Route Next Week', 30, 'Customer', 'Return Residential Items');
    insertFixedInfoForDWH_STRINGS(303, 'Return Route', 30, 'Customer', 'Return Residential Items');
    insertFixedInfoForDWH_STRINGS(310, 'no sorting info', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(311, 'Departement#', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(312, 'Room#', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(313, 'Box#', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(314, 'Delivery Point', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(315, 'Service Team', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(316, 'Client#', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(317, 'Box# + Department#', 30, 'Customer', 'Residential Outscan Sort by');
    insertFixedInfoForDWH_STRINGS(322, 'Automatic', 30, 'Customer', 'Anniversary Price Adjustment');
    insertFixedInfoForDWH_STRINGS(323, 'Signal Only', 30, 'Customer', 'Anniversary Price Adjustment');
    insertFixedInfoForDWH_STRINGS(331, 'Fixed (Dictated)', 30, 'Customer', 'Master Account Relation');
    insertFixedInfoForDWH_STRINGS(332, 'Free', 30, 'Customer', 'Master Account Relation');
    insertFixedInfoForDWH_STRINGS(350, 'High', 10, 'Contacts', 'Priority');
    insertFixedInfoForDWH_STRINGS(351, 'Medium', 10, 'Contacts', 'Priority');
    insertFixedInfoForDWH_STRINGS(352, 'Low', 10, 'Contacts', 'Priority');
    insertFixedInfoForDWH_STRINGS(360, 'Charge', 20, 'Repairs', 'Status');
    insertFixedInfoForDWH_STRINGS(361, 'Free of Charge', 20, 'Repairs', 'Status');
    insertFixedInfoForDWH_STRINGS(362, 'Charge Cancelled', 20, 'Repairs', 'Status');
    insertFixedInfoForDWH_STRINGS(363, 'No Repair Charge', 20, 'Repairs', 'Status');
    insertFixedInfoForDWH_STRINGS(364, 'Reason Not Charged', 20, 'Garment Issue', 'Status');
    insertFixedInfoForDWH_STRINGS(365, 'In Free Period', 20, 'Garment Issue', 'Status');
    insertFixedInfoForDWH_STRINGS(366, 'No Charge Defined', 20, 'Garment Issue', 'Status');
    insertFixedInfoForDWH_STRINGS(401, 'Flat Rated Rent', 30, 'Charge Type', 'Billing Method');
    insertFixedInfoForDWH_STRINGS(402, 'Rent Based on Minimum', 30, 'Charge Type', 'Billing Method');
    insertFixedInfoForDWH_STRINGS(403, 'Inventory Based', 30, 'Charge Type', 'Billing Method');
    insertFixedInfoForDWH_STRINGS(404, 'Piece Rate Only ', 30, 'Charge Type', 'Billing Method');
    insertFixedInfoForDWH_STRINGS(405, 'Lease', 30, 'Charge Type', 'Billing Method');
    insertFixedInfoForDWH_STRINGS(409, 'Unrelated Loan', 30, 'Charge Type', 'Billing Method');
    insertFixedInfoForDWH_STRINGS(411, 'Not Started', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(412, 'In Progress', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(413, 'Completed', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(414, 'Processed', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(421, 'No Put Up Printed', 30, 'Route History', 'Packing Status');
    insertFixedInfoForDWH_STRINGS(422, 'Put Up Printed', 30, 'Route History', 'Packing Status');
    insertFixedInfoForDWH_STRINGS(430, 'Not Exported', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(431, 'Exported', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(432, 'Imported', 30, 'Route History', 'Status Columns');
    insertFixedInfoForDWH_STRINGS(440, 'Not Ready for Transfer', 30, 'Route History', 'Sorting Status & PDA Status');
    insertFixedInfoForDWH_STRINGS(441, 'Ready for Transfer', 30, 'Route History', 'Sorting Status & PDA Status');
    insertFixedInfoForDWH_STRINGS(442, 'Transferred', 30, 'Route History', 'Sorting Status & PDA Status');
    insertFixedInfoForDWH_STRINGS(450, 'Packing Note generated based on Orders', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(451, 'Manually Added', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(452, 'Batch Delivery Note', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(453, 'Correction Ticket', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(454, 'Stock Delivery Note', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(455, 'Special Order', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(456, 'Bulk Note', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(457, 'Bin Note', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(458, 'Transfer Weights', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(459, 'Imported from external datawarehouse', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(460, 'Mounting Order', 40, 'Delivery Note', 'Origin');
    insertFixedInfoForDWH_STRINGS(461, 'Generated', 30, 'Invoice', 'Invoice Type');
    insertFixedInfoForDWH_STRINGS(462, 'Manual', 30, 'Invoice', 'Invoice Type');
    insertFixedInfoForDWH_STRINGS(463, 'Credit', 30, 'Invoice', 'Invoice Type');
    insertFixedInfoForDWH_STRINGS(464, 'Additional Generated', 30, 'Invoice', 'Invoice Type');
    insertFixedInfoForDWH_STRINGS(465, 'Lost Customer Invoice', 30, 'Invoice', 'Invoice Type');
    insertFixedInfoForDWH_STRINGS(466, 'Corrections Invoice', 30, 'Invoice', 'Invoice Type');
    insertFixedInfoForDWH_STRINGS(470, 'Pieces', 10, 'Work Spot', 'Pieces Weight');
    insertFixedInfoForDWH_STRINGS(471, 'Weight', 10, 'Work Spot', 'Pieces Weight');
    insertFixedInfoForDWH_STRINGS(480, 'Permanent', 20, 'Employee', 'Contract Type');
    insertFixedInfoForDWH_STRINGS(481, 'Temporary', 20, 'Employee', 'Contract Type');
    insertFixedInfoForDWH_STRINGS(482, 'External', 20, 'Employee', 'Contract Type');
    insertFixedInfoForDWH_STRINGS(485, 'Male', 10, 'Employee', 'Gender');
    insertFixedInfoForDWH_STRINGS(486, 'Female', 10, 'Employee', 'Gender');
    insertFixedInfoForDWH_STRINGS(490, 'Debit', 20, 'AR Transaction Type', 'Debit Credit');
    insertFixedInfoForDWH_STRINGS(491, 'Credit', 20, 'AR Transaction Type', 'Debit Credit');
    insertFixedInfoForDWH_STRINGS(501, 'Weekly', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(502, 'Every Delivery', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(503, 'Every Invoice', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(504, 'Every Direct Invoice Only', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(505, 'Per Delivered Piece', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(506, 'Every Printed Delivery Note', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(507, 'Every Normal Visit', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(508, 'Every Special Visit', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(509, 'Every Active Wearer Every Inv.', 30, 'Special Charge', 'Frequency');
    insertFixedInfoForDWH_STRINGS(511, 'Next Visit', 50, 'Product List / Customer', 'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(512, 'Next Week Same Day', 50, 'Product List / Customer', 'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(513, 'With 10 Days Delay', 50, 'Product List / Customer', 'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(514,
                                  'According to Return Route in Route Schedule',
                                  50,
                                  'Product List / Customer',
                                  'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(515, 'With 14 Days Delay', 50, 'Product List / Customer', 'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(516, 'With 28 Days Delay', 50, 'Product List / Customer', 'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(517,
                                  'According to Delivery Scheme',
                                  50,
                                  'Product List / Customer',
                                  'Delayed Even Exchange');
    insertFixedInfoForDWH_STRINGS(519,
                                  'Yes, Except Special Sizes',
                                  30,
                                  'Product List / Customer',
                                  'Allow Return to Stock');
    insertFixedInfoForDWH_STRINGS(521, 'Packingnote', 30, 'Product List / Customer', 'Specific Put up Type');
    insertFixedInfoForDWH_STRINGS(522, 'Bulk Put up', 30, 'Product List / Customer', 'Specific Put up Type');
    insertFixedInfoForDWH_STRINGS(523, 'Bundle Tag / Packer', 30, 'Product List / Customer', 'Specific Put up Type');
    insertFixedInfoForDWH_STRINGS(524,
                                  'Bulk Put up Scan per Route',
                                  30,
                                  'Product List / Customer',
                                  'Specific Put up Type');
    insertFixedInfoForDWH_STRINGS(525, 'Packer Loose Linen', 30, 'Product List / Customer', 'Specific Put up Type');
    insertFixedInfoForDWH_STRINGS(531,
                                  '% of Soil Count',
                                  30,
                                  'Product List / Customer',
                                  'Systematic Repl. Charge Method');
    insertFixedInfoForDWH_STRINGS(532,
                                  '% of Circulating Inventory',
                                  30,
                                  'Product List / Customer',
                                  'Systematic Repl. Charge Method');
    insertFixedInfoForDWH_STRINGS(533,
                                  'Fixed Quantity',
                                  30,
                                  'Product List / Customer',
                                  'Systematic Repl. Charge Method');
    insertFixedInfoForDWH_STRINGS(541, 'Every Delivery', 30, 'Product List / Customer', 'Systematic Repl. Charge Freq.');
    insertFixedInfoForDWH_STRINGS(542,
                                  'Every Week First Delivery',
                                  30,
                                  'Product List / Customer',
                                  'Systematic Repl. Charge Freq.');
    insertFixedInfoForDWH_STRINGS(543,
                                  'Every Week Last Delivery',
                                  30,
                                  'Product List / Customer',
                                  'Systematic Repl. Charge Freq.');
    insertFixedInfoForDWH_STRINGS(551,
                                  'Every Week (Accumulated)',
                                  30,
                                  'Product List / Customer',
                                  'Minimum Billing Frequency');
    insertFixedInfoForDWH_STRINGS(552,
                                  'Every Visit (When Billed)',
                                  30,
                                  'Product List / Customer',
                                  'Minimum Billing Frequency');
    insertFixedInfoForDWH_STRINGS(553, 'Every Month', 30, 'Product List / Customer', 'Minimum Billing Frequency');
    insertFixedInfoForDWH_STRINGS(554,
                                  'Every Delivery with Qty > 0',
                                  30,
                                  'Product List / Customer',
                                  'Minimum Billing Frequency');
    insertFixedInfoForDWH_STRINGS(555,
                                  'Delivery Scheme Based',
                                  30,
                                  'Product List / Customer',
                                  'Minimum Billing Frequency');
    insertFixedInfoForDWH_STRINGS(560, 'Per Week', 15, 'Product List / Customer', 'Free of Charge Frequency');
    insertFixedInfoForDWH_STRINGS(561, 'Per Invoice', 15, 'Product List / Customer', 'Free of Charge Frequency');
    insertFixedInfoForDWH_STRINGS(571, 'Split Price', 20, 'Product List / Customer', 'Price Usage');
    insertFixedInfoForDWH_STRINGS(572, 'Rent Price Only', 20, 'Product List / Customer', 'Price Usage');
    insertFixedInfoForDWH_STRINGS(573, 'Wash Price Only', 20, 'Product List / Customer', 'Price Usage');
    insertFixedInfoForDWH_STRINGS(581, 'Pack', 15, 'Product List / Customer', 'Charge Washes Pack');
    insertFixedInfoForDWH_STRINGS(582, 'Content', 15, 'Product List / Customer', 'Charge Washes Pack');
    insertFixedInfoForDWH_STRINGS(583, 'Both', 15, 'Product List / Customer', 'Charge Washes Pack');
    insertFixedInfoForDWH_STRINGS(590,
                                  'Both LOG and COG, same Wash Price',
                                  40,
                                  'Product List / Customer',
                                  'Charge Washes COG');
    insertFixedInfoForDWH_STRINGS(591,
                                  'Both LOG and COG, distinct Wash Price',
                                  40,
                                  'Product List / Customer',
                                  'Charge Washes COG');
    insertFixedInfoForDWH_STRINGS(592, 'LOG Only', 40, 'Product List / Customer', 'Charge Washes COG');
    insertFixedInfoForDWH_STRINGS(593, 'COG Only', 40, 'Product List / Customer', 'Charge Washes COG');
    insertFixedInfoForDWH_STRINGS(594, 'Sales Only', 40, 'Product List / Customer', 'Charge Washes COG');
    insert into dwh_string_desc
      (dwh_string_id, languagecode, string, systemuser_id, timestamp)
      select i.dwh_string_id, 'EN_US', i.factorydescription, 1, sysdate
        from dwh_string i
       where i.dwh_string_id not in (select dwh_string_id
                                       from dwh_string_desc dd
                                      where dd.dwh_string_id = i.dwh_string_id
                                        and dd.languagecode = 'EN_US');
   commit;
     exception
    when others then
      rollback;
      write_log('Error at DWH_STRINGS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDWH_STRINGS;

  procedure insertFixedInfoForDIALOGS(fp_code                   dialogs.code%type,
                                      fp_dialogonly             dialogs.dialogonly%type,
                                      fp_gridonly               dialogs.gridonly%type,
                                      fp_confprintpreview       dialogs.confprintpreview%type,
                                      fp_containerscan          dialogs.containerscan%type,
                                      fp_orpackscan             dialogs.orpackscan%type,
                                      fp_garmentscan            dialogs.garmentscan%type,
                                      fp_residentialitemscan    dialogs.residentialitemscan%type,
                                      fp_dialogtype             dialogs.dialogtype%type,
                                      fp_reporttype             dialogs.reporttype%type,
                                      fp_reportservercluster_id dialogs.reportservercluster_id%type,
                                      fp_defineuserinstructions dialogs.defineuserinstructions%type,
                                      fp_flexfields             dialogs.flexfields%type) is
  begin
    select d.dialog_id
      into id
      from dialogs d
     where d.code = fp_code;
  exception
    when no_data_found then
      insert into dialogs
        (dialog_id, code, systemuser_id, active, timestamp, dialogonly, gridonly, confprintpreview, containerscan,
         orpackscan, garmentscan, residentialitemscan, dialogtype, reporttype, reportservercluster_id,
         defineuserinstructions, flexfields)
      values
        (seq_dialogs.nextval, fp_code, systemUserID, 'Y', sysdate, fp_dialogonly, fp_gridonly, fp_confprintpreview,
         fp_containerscan, fp_orpackscan, fp_garmentscan, fp_residentialitemscan, fp_dialogtype, fp_reporttype,
         fp_reportservercluster_id, fp_defineuserinstructions, fp_flexfields);
  end insertFixedInfoForDIALOGS;

  procedure fixedInfoForDIALOGS is
  begin
    insertFixedInfoForDIALOGS('WebAdjPatientDaysEntry', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebAllocateDeliveries', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebBudgetEntry', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebChangeCustomer', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebChangeEmail', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebChangePassword', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebConfirmStockOrder', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebConsignmentNotes', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebCustomInformation', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebDeliveryNotes', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebFinancialDetails', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebGarment', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebGarmentOrder', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebGenericDocuments', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebInvoices', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebLocker', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebLogOff', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebMaintainDelStandards', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebMaintainNormStockLevels', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebMonthDefinition', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebPatientDaysEntry', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebPatientsEntry', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebPayments', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebStatements', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebStockCountOrder', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebWearer', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptAllocationSheet', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptBlankOrderForm', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptBudgetCosts', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptBudgetDetermination', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptBudgetReconcile', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptDeliveredProducts', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptGarmentOrders', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptGarmperWearer', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptInventoryUtilisation', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptMonthlyUsage', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptOrder', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptReceivedQuantities', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptScansperWearer', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptWearer', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebRptWearerInventory', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 4, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('DeliveryNote', 'N', 'N', 'Y', 'Y', 'Y', 'N', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('DeliveryVariations', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('GarmentDispenser', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('RagInBatch', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('RagItemsFromStock', 'N', 'N', 'N', 'N', 'N', 'Y', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('ReceiveItemsFromPO', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('ReceiveItemsInStockNoPO', 'N', 'N', 'N', 'N', 'Y', 'Y', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('ReplacementRenewal', 'N', 'Y', 'N', 'N', 'Y', 'Y', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('StockCorrectionNonUnique', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('StockCorrectionUnique', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('Wearer', 'N', 'N', 'N', 'N', 'N', 'Y', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('WorkOrderApproval', 'N', 'Y', 'N', 'N', 'N', 'Y', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WorkOrder', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('ReturnToStock', 'N', 'N', 'N', 'N', 'N', 'Y', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('ReceiveItemsFromDismountingOrder', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('MoveStock', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('MoveStockWithinStockroom', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('ConfirmSterilization', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('SterilizationRunStatusControl', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('StandardDelivery', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('ORPackStatusControl', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('IssueGarmentsDirect', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('IssueGarmentsFromStock', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('CorrectionTicket', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('TreatmentBatchControl', 'N', 'Y', 'N', 'N', 'N', 'Y', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('ReceiveItemsFromSDOPush', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('UniqueItem', 'N', 'N', 'N', 'N', 'N', 'Y', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('SalesOrder', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('Client', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('RagPoolMultiRead', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('BundleSortScan', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('CheckInItemsFromPO', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('CorrectItemsCheckedInFromPO', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 5, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('MakeUniqueItemsCheckedInFromPO', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 5, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('CleanroomBatchStatusControl', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('CleanroomBatch', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('ShipmentListStatusControl', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('DepositORPacks', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('IssueSalesItems', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('ReturnToStockOrRagInBatch', 'N', 'N', 'Y', 'N', 'N', 'Y', 'N', 0, 0, '', 1, 'N');
    insertFixedInfoForDIALOGS('RewashMultiRead', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('CorrectReceivedItemsFromSDOPush', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 5, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('Customer', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '',  1, 'N');
    insertFixedInfoForDIALOGS('WebContacts', 'Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N');
    insertFixedInfoForDIALOGS('WebAddContact','Y', 'N', 'N', 'N', 'N', 'N', 'N', 3, 0, '', 0, 'N' );
    insertFixedInfoForDIALOGS('ContainerShippingScan','Y', 'N', 'N', 'N', 'N', 'N', 'N', 0, 0, '', 0, 'N' );
    insertFixedInfoForDIALOGS('CreateCleanroomBatch', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 1, 0, '', 0, 'N');
    commit;
     exception
    when others then
      rollback;
      write_log('Error at DIALOGS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForDIALOGS;

  procedure insertFixedInfoForWEBMENUDIALOG(fp_webmenudialogdescription webmenugroup.factorydescription%type,
                                            fp_dialogcode               dialogs.code%type,
                                            fp_sequencenumber           webmenudialog.sequencenumber%type) is
  begin
    select wmd.webmenudialog_id
      into id
      from webmenudialog wmd
     where wmd.webmenugroup_id = (select wmg.webmenugroup_id
                                    from webmenugroup wmg
                                   where wmg.factorydescription = fp_webmenudialogdescription)
       and wmd.dialog_id = (select d.dialog_id
                              from dialogs d
                             where d.code = fp_dialogcode);
  exception
    when no_data_found then
      begin
      insert into webmenudialog
        (webmenudialog_id, webmenugroup_id, dialog_id, sequencenumber, systemuser_id, timestamp)
        select seq_webmenudialog.nextval,
               (select wmg.webmenugroup_id
                   from webmenugroup wmg
                  where wmg.factorydescription = fp_webmenudialogdescription) webmenugroup_id,
               (select d.dialog_id
                   from dialogs d
                  where d.code = fp_dialogcode) dialog_id, fp_sequencenumber, systemUserID, sysdate
          from dual;
      exception
        when dup_val_on_index then
          begin
            write_log('Error at webmenudialog: ' || sqlerrm, 3);
            fp_error := 1;
          end;
      end;
  end insertFixedInfoForWEBMENUDIALOG;

  procedure fixedInfoForWEBMENUDIALOG is
  begin
    insertFixedInfoForWEBMENUDIALOG('Linen', 'WebStockCountOrder', 1);
    insertFixedInfoForWEBMENUDIALOG('Linen', 'WebConfirmStockOrder', 2);
    insertFixedInfoForWEBMENUDIALOG('Linen', 'WebMaintainDelStandards', 3);
    insertFixedInfoForWEBMENUDIALOG('Linen', 'WebMaintainNormStockLevels', 4);
    insertFixedInfoForWEBMENUDIALOG('Linen Reports', 'WebRptBlankOrderForm', 1);
    insertFixedInfoForWEBMENUDIALOG('Linen Reports', 'WebRptOrder', 2);
    insertFixedInfoForWEBMENUDIALOG('Linen Reports', 'WebRptDeliveredProducts', 3);
    insertFixedInfoForWEBMENUDIALOG('Garments', 'WebWearer', 1);
    insertFixedInfoForWEBMENUDIALOG('Garments', 'WebGarmentOrder', 2);
    insertFixedInfoForWEBMENUDIALOG('Garments', 'WebGarment', 3);
    insertFixedInfoForWEBMENUDIALOG('Garments', 'WebLocker', 4);
    insertFixedInfoForWEBMENUDIALOG('Garment Reports', 'WebRptWearer', 1);
    insertFixedInfoForWEBMENUDIALOG('Garment Reports', 'WebRptWearerInventory', 2);
    insertFixedInfoForWEBMENUDIALOG('Garment Reports', 'WebRptGarmperWearer', 3);
    insertFixedInfoForWEBMENUDIALOG('Garment Reports', 'WebRptGarmentOrders', 4);
    insertFixedInfoForWEBMENUDIALOG('Garment Reports', 'WebRptScansperWearer', 5);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebAllocateDeliveries', 1);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebRptAllocationSheet', 2);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebPatientDaysEntry', 3);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebAdjPatientDaysEntry', 4);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebPatientsEntry', 5);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebBudgetEntry', 6);
    insertFixedInfoForWEBMENUDIALOG('Cost Information', 'WebMonthDefinition', 7);
    insertFixedInfoForWEBMENUDIALOG('Cost Reports', 'WebRptMonthlyUsage', 1);
    insertFixedInfoForWEBMENUDIALOG('Cost Reports', 'WebRptReceivedQuantities', 2);
    insertFixedInfoForWEBMENUDIALOG('Cost Reports', 'WebRptInventoryUtilisation', 3);
    insertFixedInfoForWEBMENUDIALOG('Cost Reports', 'WebRptBudgetCosts', 4);
    insertFixedInfoForWEBMENUDIALOG('Cost Reports', 'WebRptBudgetDetermination', 5);
    insertFixedInfoForWEBMENUDIALOG('Cost Reports', 'WebRptBudgetReconcile', 6);
    insertFixedInfoForWEBMENUDIALOG('Financial Information', 'WebFinancialDetails', 1);
    insertFixedInfoForWEBMENUDIALOG('Financial Information', 'WebInvoices', 2);
    insertFixedInfoForWEBMENUDIALOG('Financial Information', 'WebPayments', 3);
    insertFixedInfoForWEBMENUDIALOG('Financial Information', 'WebStatements', 4);
    insertFixedInfoForWEBMENUDIALOG('Delivery Documents', 'WebDeliveryNotes', 1);
    insertFixedInfoForWEBMENUDIALOG('Delivery Documents', 'WebConsignmentNotes', 2);
    insertFixedInfoForWEBMENUDIALOG('Main', 'WebGenericDocuments', 1);
    insertFixedInfoForWEBMENUDIALOG('Main', 'WebCustomInformation', 2);
    insertFixedInfoForWEBMENUDIALOG('Main', 'WebChangeEmail', 3);
    insertFixedInfoForWEBMENUDIALOG('Main', 'WebChangePassword', 4);
    insertFixedInfoForWEBMENUDIALOG('Main', 'WebChangeCustomer', 5);
    insertFixedInfoForWEBMENUDIALOG('Main', 'WebLogOff', 6);
    insertFixedInfoForWEBMENUDIALOG('Contacts','WebContacts', 1);
    insertFixedInfoForWEBMENUDIALOG('Contacts','WebAddContact', 2);
    commit;
     exception
    when others then
      rollback;
      write_log('Error at WEBMENUDIALOG: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForWEBMENUDIALOG;

  procedure fixedInfoForWEBUSERDIALOG is
  begin
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, webmenugroup wmg
       where wmg.webmenugroup_id = wmd.webmenugroup_id
         and wmg.factorydescription in ('Linen', 'Linen Reports')
         and (w.accessnongarments = 'Y' or w.accesssalesitems = 'Y');
    -- garments
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, webmenugroup wmg, dialogs d
       where wmg.webmenugroup_id = wmd.webmenugroup_id
         and d.dialog_id = wmd.dialog_id
         and wmg.factorydescription in ('Garments', 'Garment Reports')
         and w.accessgarments = 'Y'
         and (d.code <> 'WebLockers' or w.allowlockerentry = 'Y');
    -- financial info
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, webmenugroup wmg
       where wmg.webmenugroup_id = wmd.webmenugroup_id
         and wmg.factorydescription = 'Financial Information'
         and w.accessfinancialdetails = 'Y';
    -- cost information: allocate deliveries
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, dialogs d
       where d.dialog_id = wmd.dialog_id
         and d.code = 'WebAllocateDeliveries'
         and w.allowdeliveryrealloc = 'Y';
    -- cost information: patient days entry
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, dialogs d
       where d.dialog_id = wmd.dialog_id
         and d.code = 'WebPatientDaysEntry'
         and w.allowpatientdayentry = 'Y';
    -- cost information: adjusted patient days entry for customer ang and tlk only
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, dialogs d
       where d.dialog_id = wmd.dialog_id
         and d.code = 'WebAdjPatientDaysEntry'
         and w.allowpatientdayentry = 'Y'
         and (select min(code)
                from databasesettings) in ('ANG', 'TLK');
    -- cost information: budget entry
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, dialogs d
       where d.dialog_id = wmd.dialog_id
         and d.code = 'WebBudgetEntry'
         and w.allowbudgetentry = 'Y';
    -- cost reports
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, webmenugroup wmg
       where wmg.webmenugroup_id = wmd.webmenugroup_id
         and wmg.factorydescription = 'Cost Reports'
         and w.allowcostreports = 'Y';
    -- main
    insert into webuserdialog
      select seq_webuserdialog.nextval, w.webuser_id, wmd.webmenudialog_id, null, 1, sysdate
        from webuser w, webmenudialog wmd, webmenugroup wmg
       where wmg.webmenugroup_id = wmd.webmenugroup_id
         and wmg.factorydescription = 'Main';
   commit;
     exception
    when others then
      rollback;
      write_log('Error at WEBUSERDIALOG: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForWEBUSERDIALOG;

  procedure insertFixedInfoForWEBEVENTTYPE(fp_webeventtype_id webeventtype.webeventtype_id%type,
                                           fp_description     webeventtype.description%type) is
    lv_description webeventtype.description%type;
  begin
    select w.description
      into lv_description
      from webeventtype w
     where w.webeventtype_id = fp_webeventtype_id;
  exception
    when no_data_found then
      insert into webeventtype
        (webeventtype_id, description, systemuser_id, timestamp)
      values
        (fp_webeventtype_id, fp_description, systemUserID, sysdate);
  end insertFixedInfoForWEBEVENTTYPE;

  procedure fixedInfoForWEBEVENTTYPE is
  begin
    insertFixedInfoForWEBEVENTTYPE(0, 'Log On');
    insertFixedInfoForWEBEVENTTYPE(1, 'Log On after Session Time Out');
    insertFixedInfoForWEBEVENTTYPE(2, 'Log Off');
    insertFixedInfoForWEBEVENTTYPE(3, 'Session Time Out');
    insertFixedInfoForWEBEVENTTYPE(4, 'Select from Menu');
    insertFixedInfoForWEBEVENTTYPE(5, 'Submit Report');
    insertFixedInfoForWEBEVENTTYPE(6, 'Save Data');
    insertFixedInfoForWEBEVENTTYPE(7, 'Select Customer');
    insertFixedInfoForWEBEVENTTYPE(10, 'Confirm Stock Count');
    insertFixedInfoForWEBEVENTTYPE(11, 'Revoke Confirmation');
    insertFixedInfoForWEBEVENTTYPE(20, 'Add Wearer');
    insertFixedInfoForWEBEVENTTYPE(21, 'Edit Wearer');
    insertFixedInfoForWEBEVENTTYPE(22, 'Quit Wearer');
    insertFixedInfoForWEBEVENTTYPE(23, 'Add Employment');
    insertFixedInfoForWEBEVENTTYPE(24, 'Remove Employment');
    insertFixedInfoForWEBEVENTTYPE(25, 'Add Inventory');
    insertFixedInfoForWEBEVENTTYPE(26, 'Edit Inventory');
    insertFixedInfoForWEBEVENTTYPE(27, 'Quit Inventory');
    insertFixedInfoForWEBEVENTTYPE(28, 'Create Work Order');
    insertFixedInfoForWEBEVENTTYPE(29, 'Cancel Work Order');
    insertFixedInfoForWEBEVENTTYPE(30, 'Add Locker');
    insertFixedInfoForWEBEVENTTYPE(31, 'Edit Locker');
    insertFixedInfoForWEBEVENTTYPE(32, 'Delete Locker');
    insertFixedInfoForWEBEVENTTYPE(33, 'Move Employment');
    insertFixedInfoForWEBEVENTTYPE(40, 'Add Flag');
    insertFixedInfoForWEBEVENTTYPE(41, 'Edit Flag');
    insertFixedInfoForWEBEVENTTYPE(42, 'Remove Flag');
    insertFixedInfoForWEBEVENTTYPE(80, 'Add Order');
    insertFixedInfoForWEBEVENTTYPE(81, 'Edit Order');
    insertFixedInfoForWEBEVENTTYPE(82, 'Confirm Order');
    insertFixedInfoForWEBEVENTTYPE(83, 'Revoke Order Confirmation');
    insertFixedInfoForWEBEVENTTYPE(84, 'Revoke Confirmation Failed');
    insertFixedInfoForWEBEVENTTYPE(85, 'Planned Data entry');
    insertFixedInfoForWEBEVENTTYPE(100, 'Add Room');
    insertFixedInfoForWEBEVENTTYPE(101, 'Edit Room');
    insertFixedInfoForWEBEVENTTYPE(102, 'Remove Room');
    insertFixedInfoForWEBEVENTTYPE(103, 'Add Client');
    insertFixedInfoForWEBEVENTTYPE(104, 'Edit Client');
    insertFixedInfoForWEBEVENTTYPE(105, 'Quit Client');
    insertFixedInfoForWEBEVENTTYPE(106, 'Add Contact Person');
    insertFixedInfoForWEBEVENTTYPE(107, 'Edit Contact Person');
    insertFixedInfoForWEBEVENTTYPE(108, 'Remove Contact Person');
    insertFixedInfoForWEBEVENTTYPE(109, 'Print Labels');
    insertFixedInfoForWEBEVENTTYPE(110, 'Assign Labels');
    insertFixedInfoForWEBEVENTTYPE(111, 'Add Flag');
    insertFixedInfoForWEBEVENTTYPE(112, 'Edit Flag');
    insertFixedInfoForWEBEVENTTYPE(113, 'Remove Flag');
    insertFixedInfoForWEBEVENTTYPE(114, 'Take out of circulation');
    insertFixedInfoForWEBEVENTTYPE(115, 'Move item to Client');
    insertFixedInfoForWEBEVENTTYPE(116, 'Checkpoint scan');
    insertFixedInfoForWEBEVENTTYPE(118, 'Move Client');
    insertFixedInfoForWEBEVENTTYPE(150, 'Log in');
    insertFixedInfoForWEBEVENTTYPE(151, 'Log out');
    insertFixedInfoForWEBEVENTTYPE(152, 'ID code scan');
    insertFixedInfoForWEBEVENTTYPE(200, 'Log in');
    insertFixedInfoForWEBEVENTTYPE(201, 'Log out');
    insertFixedInfoForWEBEVENTTYPE(202, 'Select customer');
    insertFixedInfoForWEBEVENTTYPE(203, 'Add order');
    insertFixedInfoForWEBEVENTTYPE(204, 'Edit order');
    insertFixedInfoForWEBEVENTTYPE(205, 'Confirm order');
    insertFixedInfoForWEBEVENTTYPE(206, 'Revoke order');
    insertFixedInfoForWEBEVENTTYPE(207, 'Revoke Confirmation failed');
    insertFixedInfoForWEBEVENTTYPE(230, 'Add contact');
    insertFixedInfoForWEBEVENTTYPE(231, 'Edit contact');
    insertFixedInfoForWEBEVENTTYPE(232, 'Add attachment ');
    insertFixedInfoForWEBEVENTTYPE(233, 'Delete attachment');
    insertFixedInfoForWEBEVENTTYPE(234, 'Add follow up note');
    insertFixedInfoForWEBEVENTTYPE(235, 'Edit follow up note');
    insertFixedInfoForWEBEVENTTYPE(236, 'Close contact');
    insertFixedInfoForWEBEVENTTYPE(237, 'Email contact');
    insertFixedInfoForWEBEVENTTYPE(300, 'Login');
    insertFixedInfoForWEBEVENTTYPE(301, 'Automatic Log Out');
    insertFixedInfoForWEBEVENTTYPE(302, 'Repair Logged');
    insertFixedInfoForWEBEVENTTYPE(303, 'Lost and Found');
    insertFixedInfoForWEBEVENTTYPE(304, 'Password Reset');
    insertFixedInfoForWEBEVENTTYPE(305, 'PIN Reset');
    commit;
     exception
    when others then
      rollback;
      write_log('Error at WEBEVENTTYPE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForWEBEVENTTYPE;

  procedure fixedInfoForREASONCODE is
  begin
    begin
      select r.reasoncode_id
        into id
        from reasoncode r
       where r.code = '-';
    exception
      when no_data_found then
        insert into reasoncode
          (reasoncode_id, code, internetselectable, allowprepcharges, garmentreason, linenreason, exporttohandheld,
           cancelinvoice, affectsnextinvoice, affectscurrentinvoice, invoiceadjustment, firstissue, inventorytrigger,
           systemuser_id, timestamp, chargeresidualvalue, chargerestockingfee, reasonmakecoguniqueitem, processlostitems,
           invoicecategory, customerundelivered, sampleissue, extstocktranstype_id, regphysicalstocktrans, reasongroup,
           driversales, calculaterentonstock, servicetruck, orpackreason, defaultreasonforlabeling,
           defaultreasonundoreceivepo, defaultreceivesdopush, excludeexcesscharge, adjustcircfromfixeddelivery,
           stockinventorytransaction, residentialreason, reasonformainorder, excludescrutinycheck, chargeemblem,
           purchaseorderpriority_id)
          select seq_reasoncode.nextval, '-', 'N', 'N', 'Y', 'Y', 'N', 0, 'N', 'N', 0, 'N', 0, systemUserID, sysdate, 'N',
                 'N', 'N', 'N', 0, 'N', 'N', '', 'N', '', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N',
                 'Y', ''
            from dual;
    end;
    commit;
     exception
    when others then
      rollback;
      write_log('Error at REASONCODE: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForREASONCODE;

  procedure fixedInfoForREASONCODEDIALOGS is
  begin
      insert into reasoncodedialogs
      (reasoncode_id, dialog_id, selectable, systemuser_id, timestamp)
      select r.reasoncode_id, d.dialog_id, 'Y', systemUserID, sysdate
        from reasoncode r, dialogs d
       where not exists (select 1
                from reasoncodedialogs rcd
               where rcd.reasoncode_id = r.reasoncode_id
                 and rcd.dialog_id = d.dialog_id)
         and d.code in ('DeliveryNote',
                        'DeliveryVariations',
                        'GarmentDispenser',
                        'RagInBatch',
                        'RagItemsFromStock',
                        'ReceiveItemsFromPO',
                        'ReceiveItemsInStockNoPO',
                        'ReplacementRenewal',
                        'StockCorrectionNonUnique',
                        'StockCorrectionUnique',
                        'Wearer',
                        'WorkOrderApproval',
                        'WorkOrder',
                        'ReturnToStock',
                        'ReceiveItemsFromDismountingOrder',
                        'MoveStock',
                        'MoveStockWithinStockroom',
                        'ConfirmSterilization',
                        'SterilizationRunStatusControl',
                        'StandardDelivery',
                        'ORPackStatusControl',
                        'IssueGarmentsDirect',
                        'IssueGarmentsFromStock',
                        'CorrectionTicket',
                        'TreatmentBatchControl',
                        'ReceiveItemsFromSDOPush',
                        'UniqueItem',
                        'SalesOrder',
                        'Client',
                        'RagPoolMultiRead',
                        'BundleSortScan',
                        'CheckInItemsFromPO',
                        'CorrectItemsCheckedInFromPO',
                        'MakeUniqueItemsCheckedInFromPO',
                        'CleanroomBatchStatusControl',
                        'CleanroomBatch',
                        'ShipmentListStatusControl',
                        'DepositORPacks',
                        'ReturnToStockOrRagInBatch',
                        'RewashMultiRead',
                        'CorrectReceivedItemsFromSDOPush',
                        'MaintainGarmentCharges',
                        'CreateCleanroomBatch',
                        'MakeUniqueCustomerOwnedItems');

      -- MakeUniqueCustomerOwnedItems is selectable only for reasoncodes with reasonmakecoguniqueitem = Y
      update reasoncodedialogs rsc
      set rsc.selectable = 'N'
      where rsc.reasoncode_id in (select rc.reasoncode_id from reasoncode rc where rc.reasonmakecoguniqueitem = 'N')
      and rsc.dialog_id = (select d.dialog_id from dialogs d where d.code = 'MakeUniqueCustomerOwnedItems');

   commit;
     exception
    when others then
      rollback;
      write_log('Error at REASONCODEDIALOGS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForREASONCODEDIALOGS;

  procedure fixedInfoForRAGREASON is
  begin
    select r.ragreason_id
      into id
      from ragreason r
     where r.code = '-';
  exception
    when no_data_found then
      insert into ragreason
        (ragreason_id, code, systemuser_id, timestamp, active, chargeresidualvalue, allowreissue, processlostitems,
         defaultreasonundoreceivepo, chargeresidualinsurance, orcontentsitems)
        select seq_ragreason.nextval, '-', systemUserID, sysdate, 'Y', 'N', 'N', 'N', 'Y', 0, 'N'
          from dual;
    commit;
    when others then
      rollback;
      write_log('Error at RAGREASON: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForRAGREASON;

  procedure insertFixedInfoForRAGREASONDIALOGS(fp_code dialogs.code%type) is
  begin
    select count(r.dialog_id)
    into id
    from ragreasondialogs r join dialogs d on r.dialog_id = d.dialog_id
    where d.code= fp_code;
   if(id = 0) then
        insert into ragreasondialogs(ragreason_id, dialog_id, selectable, systemuser_id, timestamp)
        select r.ragreason_id, d.dialog_id, 'Y', systemUserID, sysdate from ragreason r, dialogs d where d.code = fp_code;
   end if;
    end insertFixedInfoForRAGREASONDIALOGS;

  procedure fixedInfoForRAGREASONDIALOGS is
  begin
    insertFixedInfoForRAGREASONDIALOGS('RagItemsFromStock');
    insertFixedInfoForRAGREASONDIALOGS('ReturnCreditItems');
    insertFixedInfoForRAGREASONDIALOGS('GarmentDispenser');
    insertFixedInfoForRAGREASONDIALOGS('ReturnToStock');
    insertFixedInfoForRAGREASONDIALOGS('StockCorrectionUnique');
    insertFixedInfoForRAGREASONDIALOGS('RagInBatch');
    insertFixedInfoForRAGREASONDIALOGS('RagPoolMultiRead');
    insertFixedInfoForRAGREASONDIALOGS('IssueSalesItems');
    insertFixedInfoForRAGREASONDIALOGS('ReturnToStockOrRagInBatch');
    insertFixedInfoForRAGREASONDIALOGS('ReasonCode');
    commit;
  exception
    when others then
      rollback;
      write_log('Error at RAGREASONDIALOGS: ' || sqlerrm, 3);
      fp_error := 1;
  end fixedInfoForRAGREASONDIALOGS;

  procedure fixedInfoForEXTRABAGS is
    begin
      select count(1)
      into id
      from extrabags;
      if(id = 0) then
         insert into extrabags
          select bu.businessunit_id, 1 numberofbags, 0 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 4 numberofbags, 1 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 12 numberofbags, 2 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 18 numberofbags, 3 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 24 numberofbags, 4 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 30 numberofbags, 5 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 36 numberofbags, 6 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 42 numberofbags, 7 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 48 numberofbags, 8 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 54 numberofbags, 9 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 60 numberofbags, 10 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 66 numberofbags, 11 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 72 numberofbags, 12 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 78 numberofbags, 13 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 84 numberofbags, 14 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 90 numberofbags, 15 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
        insert into extrabags
          select bu.businessunit_id, 96 numberofbags, 16 numberofextrabags, systemUserID, sysdate
            from businessunit bu, dual;
      end if;
  commit;
  exception
    when others then
      rollback;
      write_log('Error at EXTRABAGS: ' || sqlerrm, 3);
      fp_error := 1;
      end fixedInfoForEXTRABAGS;

  procedure insertFixedInfoForPlantPdfExport(fp_reportnumber plantpdfexport.reportnumber%type,
                                             fp_reportname plantpdfexport.reportname%type) is

    begin
    select count(p.plant_id)
    into id
    from  plantpdfexport p
    where p.reportnumber = fp_reportnumber;
    if (id=0) then
      insert into plantpdfexport(plant_id, reportnumber, reportname, exportpdf, systemuser_id, timestamp, keywordfileformat)
        select p.plant_id, fp_reportnumber, fp_reportname, 'N', 0, sysdate, 1 from plant p;
      insert into plantpdfexport(plant_id, reportnumber, reportname, exportpdf, systemuser_id, timestamp, keywordfileformat)
        select p.plant_id, fp_reportnumber, fp_reportname, 'N', 0, sysdate, 3 from plant p;
    end if;

    end insertFixedInfoForPlantPdfExport;
  procedure fixedInfoForPlantPdfExport is
    begin
        insertFixedInfoForPlantPdfExport(1,'Delivery Note');
        insertFixedInfoForPlantPdfExport(2,'Weighing Ticket');
        insertFixedInfoForPlantPdfExport(3,'Invoice');
        insertFixedInfoForPlantPdfExport(4,'Invoice Appendix');
        insertFixedInfoForPlantPdfExport(5,'Sales Note');
        insertFixedInfoForPlantPdfExport(6,'Client Delivery Note');
        insertFixedInfoForPlantPdfExport(7,'Consignment Note');
      commit;
  exception
    when others then
      rollback;
      write_log('Error at PlantPdfExport: ' || sqlerrm, 3);
      fp_error := 1;
      end fixedInfoForPlantPdfExport;

  procedure fixedInfoForGARMENTDISPENSERMESSAGE is

    begin
      select count(1)
      into id
      from garmentdispensermessage;
      if(id = 0) then
       insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'G1', 'Unknown error',
               'General Error Message, generated by Garment Dispenser (check the log files of the application for more information)',
               systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'G2', 'IO Error', 'file IO Error', systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'F1', 'Field Count Error', null, systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'F2', 'Field Format Error',
               'e.g. date format, or string when a number is expected, and so on', systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'F3', 'Field Length Error', null, systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'F4', 'Field Value Error',
               'e.g. smaller than the minimum or greater than  the maximum allowed value', systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'F5', 'Invalid Characters', null, systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'T1', 'Mandatory Field Missing', null, systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'T2', 'In use', 'In use or already defined', systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'T3', 'Not defined', 'Unknown field value (not defined)',
               systemUserID, sysdate
          from dual;
      insert into garmentdispensermessage
        select seq_garmentdispensermessage.nextval, 5, 'T4', 'Type Error',
               'e.g. attempt to assign a PG garment to a Pool Wearer', systemUserID, sysdate
          from dual;
          end if;
 commit;
  exception
    when others then
      rollback;
      write_log('Error at GARMENTDISPENSERMESSAGE: ' || sqlerrm, 3);
      fp_error := 1;
      end fixedInfoForGARMENTDISPENSERMESSAGE;

   procedure fixedInfoForREPORTSERVERCLUSTER is

    begin
      select count(1)
      into id
      from reportservercluster;
      if(id = 0) then
        insert into reportservercluster rsc(reportservercluster_id, description, reporttype, active, defaultservercluster, systemuser_id, timestamp)
        select seq_reportservercluster.nextval, 'Default', 0, 'N', 'Y', systemUserID, sysdate from dual
        where (select count(1)
              from reportservercluster rsc
             where rsc.reporttype = 0) = 0;
       end if;
    commit;
  exception
    when others then
      rollback;
      write_log('Error at REPORTSERVERCLUSTER: ' || sqlerrm, 3);
      fp_error := 1;
       end fixedInfoForREPORTSERVERCLUSTER;

   procedure insertFixedInfoForCleanRoomBatchStep(fp_step  cleanroombatchstep.step%type,
                                                  fp_description cleanroombatchstep.description%type) is
  begin
    select count(c.plant_id)
    into id
    from  cleanroombatchstep c
    where c.step = fp_step;
    if (id=0) then
      insert into cleanroombatchstep(cleanroomstep_id, plant_id, step, description, userinstructiontype_id, timestamp, systemuser_id)
      select SEQ_CLEANROOMBATCHSTEP.nextval, p.plant_id, fp_step, fp_description, null, sysdate, systemUserID from plant p;
    end if;
  end insertFixedInfoForCleanRoomBatchStep;

    procedure fixedInfoForCleanRoomBatchStep is
    begin
      insertFixedInfoForCleanRoomBatchStep(0, 'New Batch');
      insertFixedInfoForCleanRoomBatchStep(1, 'Closed');
      insertFixedInfoForCleanRoomBatchStep(2, 'Completed');
      insertFixedInfoForCleanRoomBatchStep(3, 'Rejected');
      insertFixedInfoForCleanRoomBatchStep(4, 'Washed');
      insertFixedInfoForCleanRoomBatchStep(5, 'Dried');
      insertFixedInfoForCleanRoomBatchStep(6, 'Folded');
      insertFixedInfoForCleanRoomBatchStep(7, 'Out of Cleanroom');
      insertFixedInfoForCleanRoomBatchStep(8, 'Packed');
      insertFixedInfoForCleanRoomBatchStep(9, 'Shipped');
      insertFixedInfoForCleanRoomBatchStep(10, 'Cancelled');
      commit;
      exception
        when others then
          rollback;
          write_log('Error at CleanRoomBatchStep: ' || sqlerrm, 3);
          fp_error := 1;
          end fixedInfoForCleanRoomBatchStep;

     procedure fixedInfoforcheck_digit_matrix is
     begin
       --all data is fixed and should be there, so when it was empty insert, update not needed
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 0, 0, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 1, 9, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 2, 4, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 3, 6, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 4, 8, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 5, 2, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 6, 7, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 7, 1, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 8, 3, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (0, 9, 5, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 0, 9, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 1, 4, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 2, 6, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 3, 8, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 4, 2, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 5, 7, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 6, 1, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 7, 3, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 8, 5, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (1, 9, 0, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 0, 4, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 1, 6, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 2, 8, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 3, 2, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 4, 7, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 5, 1, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 6, 3, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 7, 5, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 8, 0, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (2, 9, 9, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 0, 6, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 1, 8, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 2, 2, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 3, 7, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 4, 1, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 5, 3, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 6, 5, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 7, 0, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 8, 9, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (3, 9, 4, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 0, 8, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 1, 2, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 2, 7, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 3, 1, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 4, 3, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 5, 5, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 6, 0, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 7, 9, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 8, 4, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (4, 9, 6, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 0, 2, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 1, 7, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 2, 1, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 3, 3, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 4, 5, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 5, 0, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 6, 9, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 7, 4, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 8, 6, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (5, 9, 8, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 0, 7, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 1, 1, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 2, 3, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 3, 5, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 4, 0, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 5, 9, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 6, 4, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 7, 6, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 8, 8, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (6, 9, 2, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 0, 1, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 1, 3, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 2, 5, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 3, 0, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 4, 9, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 5, 4, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 6, 6, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 7, 8, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 8, 2, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (7, 9, 7, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 0, 3, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 1, 5, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 2, 0, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 3, 9, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 4, 4, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 5, 6, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 6, 8, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 7, 2, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 8, 7, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (8, 9, 1, 1);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 0, 5, 0);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 1, 0, 9);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 2, 9, 8);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 3, 4, 7);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 4, 6, 6);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 5, 8, 5);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 6, 2, 4);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 7, 7, 3);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 8, 1, 2);
       insert into check_digit_matrix (x, y, carryover, checkdigit) values (9, 9, 3, 1);
       commit;
     exception
       when dup_val_on_index then
         null; --ok data is already there
       when others then
         begin
           rollback;
           write_log('Error insert into check_digit_matrix ' || sqlerrm, 3);
           fp_error := 1;
         end;
     end fixedInfoforcheck_digit_matrix;

      procedure insertFixedInfoForRestResource(fp_restresource_id restresource.restresource_id%type,
                                               fp_resourcename    restresource.resourcename%type,
                                               fp_allowusage      restresource.allowusage%type) is

      lv_allowusage restresource.allowusage%type;

      begin
        select r.restresource_id, r.allowusage
          into id, lv_allowusage
          from restresource r
         where r.restresource_id = fp_restresource_id;

          if (lv_allowusage <> fp_allowusage) then
      update restresource r
         set r.allowusage = fp_allowusage
       where r.restresource_id = fp_restresource_id;
      end if;

      exception
        when no_data_found then
          insert into restresource
            (restresource_id, resourcename, allowusage, timestamp)
          values
            (fp_restresource_id, fp_resourcename, fp_allowusage, sysdate);
      end insertFixedInfoForRestResource;

      procedure fixedInfoForRestResource is
      begin
        insertFixedInfoForRestResource(1, 'customers', 0);
        insertFixedInfoForRestResource(2, 'deliveryPoints', 1);
        insertFixedInfoForRestResource(3, 'routeControls', 1);
        insertFixedInfoForRestResource(4, 'departments', 0);
        insertFixedInfoForRestResource(5, 'distributionPoints', 0);
        insertFixedInfoForRestResource(6, 'costcenters', 0);
        insertFixedInfoForRestResource(7, 'wearers', 0);
        insertFixedInfoForRestResource(8, 'lockers', 0);
        insertFixedInfoForRestResource(9, 'garments', 0);
        insertFixedInfoForRestResource(10, 'products', 0);
        insertFixedInfoForRestResource(11, 'turnoverGroups', 0);
        insertFixedInfoForRestResource(12, 'sizes', 0);
        insertFixedInfoForRestResource(13, 'finishingMethods', 0);
        insertFixedInfoForRestResource(14, 'productListsPerCustomer', 0);
        insertFixedInfoForRestResource(15, 'creditCardPortals', 0);
        insertFixedInfoForRestResource(16, 'fullPaymentsOnDelivery', 0);
        insertFixedInfoForRestResource(17, 'systemUsers', 0);
        insertFixedInfoForRestResource(18, 'userGroups', 0);
        insertFixedInfoForRestResource(19, 'employees', 0);
        insertFixedInfoForRestResource(20, 'districts', 0);
        insertFixedInfoForRestResource(21, 'plants', 0);
        insertFixedInfoForRestResource(22, 'purchaseOrders', 0);
        insertFixedInfoForRestResource(23, 'salesNotes', 0);
        insertFixedInfoForRestResource(24, 'contacts', 0);
        insertFixedInfoForRestResource(25, 'surveys', 0);
        insertFixedInfoForRestResource(26, 'nonBusinessDays', 0);
        insertFixedInfoForRestResource(27, 'generalPriceLists', 0);
        insertFixedInfoForRestResource(28, 'priceListsPerCustomer', 0);
        insertFixedInfoForRestResource(29, 'customerSpecialCharges', 0);
        insertFixedInfoForRestResource(30, 'flexFieldTemplates', 0);
        insertFixedInfoForRestResource(31, 'printReport', 0);
        insertFixedInfoForRestResource(32, 'flexFieldData', 0);
        insertFixedInfoForRestResource(33, 'inwatec', 0);
        insertFixedInfoForRestResource(34, 'scans', 1);
        insertFixedInfoForRestResource(35, 'stockrooms', 0);
        insertFixedInfoForRestResource(36, 'priceApproval', 0);
        insertFixedInfoForRestResource(37, 'startMyDay', 0);
        insertFixedInfoForRestResource(38, 'routeStops', 0);
        insertFixedInfoForRestResource(39, 'automatedRouteDocuments', 0);
        insertFixedInfoForRestResource(40, 'packingNotes', 0);
        insertFixedInfoForRestResource(41, 'deliveryVariations', 0);
        insertFixedInfoForRestResource(42, 'contractsPerCustomer', 0);


        commit;
      exception
        when dup_val_on_index then
          null;
        when others then
          rollback;
          write_log('Error at RestResource: ' || sqlerrm, 3);
          fp_error := 1;
      end fixedInfoForRestResource;

   procedure insertFixedInfoForRASTOPACTIONORDER(fp_description            rastopactionorder.description%type,
                                                 fp_ordernumber            rastopactionorder.ordernumber%type,
                                                 fp_internalref            rastopactionorder.internalref%type,
                                                 fp_remark                 rastopactionorder.remark%type) is

  begin
    select r.rastopactionorder_id
      into id
      from rastopactionorder r
     where r.ordernumber = fp_ordernumber;
  exception
    when no_data_found then
     begin
      insert into RASTOPACTIONORDER
        (rastopactionorder_id, description, ordernumber, internalref, remark, systemuser_id, timestamp)
      values
        (SEQ_RASTOPACTIONORDER.NEXTVAL, fp_description, fp_ordernumber, fp_internalref, fp_remark, systemUserID, sysdate);
      exception
        when dup_val_on_index then
          begin
            write_log('Error at rastopactionorder: ' || sqlerrm, 3);
            fp_error := 1;
          end;
      end;
  end insertFixedInfoForRASTOPACTIONORDER;

  procedure fixedInfoForRASTOPACTIONORDER is
  begin
    insertFixedInfoForRASTOPACTIONORDER('Messages', 1, 'BTN_MESG', 'Module CONTACTMANAGER');
    insertFixedInfoForRASTOPACTIONORDER('Info', 2, 'BTN_INFO', '');
    insertFixedInfoForRASTOPACTIONORDER('Open Hours', 3, 'BTN_BSN_HOURS', '');
    insertFixedInfoForRASTOPACTIONORDER('Contacts', 4, 'BTN_CONTACTS', '');
    insertFixedInfoForRASTOPACTIONORDER('Financial Details', 5, 'BTN_FINANCIAL_DETAILS', 'Module RAS & SS SettlementActive = Y');
    insertFixedInfoForRASTOPACTIONORDER('Adjust', 6, 'BTN_ADJUST', 'Module RAS & SS SettlementActive = Y');
    insertFixedInfoForRASTOPACTIONORDER('Settle', 7, 'BTN_SETTLE', 'Module RAS & SS SettlementActive = Y');
    insertFixedInfoForRASTOPACTIONORDER('Sign (EU)', 8, 'BTN_SIGN', 'Module RAS & SS SettlementActive = N');
    insertFixedInfoForRASTOPACTIONORDER('Survey', 9, 'BTN_SURVEY', 'Module CONTACTMANAGER & SS SatisfactionSurvey = Y');
    insertFixedInfoForRASTOPACTIONORDER('Proof of Visit', 10, 'BTN_PROOF_OF_VISIT', '');
    insertFixedInfoForRASTOPACTIONORDER('Unload', 11, 'BTN_UNLOAD', 'Module KNT and ROUTEASSISTANTCONTAINER');
    insertFixedInfoForRASTOPACTIONORDER('Scan Containers', 12, 'BTN_SCAN_CONTAINERS', 'Module KNT and ROUTASSISTANTCONTAINER');
    insertFixedInfoForRASTOPACTIONORDER('Wearers', 13, 'BTN_WEARERS', 'Module ROUTEASSISTANTGARMENT');
    insertFixedInfoForRASTOPACTIONORDER('Scan Garments', 14, 'BTN_SCAN_ACTIONS', 'Module ROUTEASSISTANTGARMENT');
    insertFixedInfoForRASTOPACTIONORDER('Soil Count', 15, 'BTN_SOILCOUNT_ENTRY', 'Module RAS & SS SettlementActive = Y');
    insertFixedInfoForRASTOPACTIONORDER('Deliver / Pickup', 16, 'BTN_DELIVERY_PICKUP', 'No module RAS');
    insertFixedInfoForRASTOPACTIONORDER('Capture GPS Coordinates', 17, 'BTN_CAPTURE_GPS', 'SS CAPTUREGPSLOCATION');
    insertFixedInfoForRASTOPACTIONORDER('Return Item', 18, 'BTN_RETURN_ITEMS', 'RAS');
    insertFixedInfoForRASTOPACTIONORDER('Additional Products', 19, 'BTN_ADDITIONAL_PRODUCTS', 'CONTRACTMAINTENANCE');
    insertFixedInfoForRASTOPACTIONORDER('Contract Products', 20, 'BTN_CONTRACT_PRODUCTS', 'CONTRACTMAINTENANCE');
    insertFixedInfoForRASTOPACTIONORDER('Unique Item Service', 21, 'BTN_UNIQUE_ITEM_SERVICE', 'Module UNIQUEITEMSERVICE');
    insertFixedInfoForRASTOPACTIONORDER('Location Pictures', 22, 'BTN_LOCATION_PICTURES', '');
    insertFixedInfoForRASTOPACTIONORDER('Mat Carry Units', 23, 'BTN_MATS', 'MATTRANSPORT');
    insertFixedInfoForRASTOPACTIONORDER('Ordering', 24, 'BTN_ORDERING', 'ROUTEASSISTANTONEOFFORDER');
    insertFixedInfoForRASTOPACTIONORDER('Order Delivery', 25, 'BTN_ORDER_DELIVERY', 'FACILITYSERVICE');
    commit;
      exception
         when others then
           rollback;
           write_log('Error at RASTOPACTIONORDER: ' || sqlerrm, 3);
    fp_error := 1;
  end fixedInfoForRASTOPACTIONORDER;




  procedure insertFixedInfoForImagePurpose(fp_imagepurpose_id imagepurpose.imagepurpose_id%type,
                                              fp_imagetype imagepurpose.imagetype%type,
                                              fp_purpose imagepurpose.purpose%type,
                                              fp_remarks imagepurpose.remarks%type,
                                              fp_inuse imagepurpose.inuse%type) is
  begin
    select count(i.imagepurpose_id)
    into id
    from imagepurpose i
    where i.imagepurpose_id = fp_imagepurpose_id;
    if (id=0) then
    insert into IMAGEPURPOSE (imagepurpose_id, imagetype, purpose, remarks, inuse, systemuser_id, timestamp)
    values (fp_imagepurpose_id, fp_imagetype, fp_purpose, fp_remarks, fp_inuse, 1, sysdate);
    end if;
  end insertFixedInfoForImagePurpose;

    procedure fixedInfoForImagePurpose is
    begin
      insertFixedInfoForImagePurpose(1, 1, 'Product Selection', 'Format WEBP size 816x612', 'N');
      commit;
      exception
        when others then
          rollback;
          write_log('Error at IMAGEPURPOSE: ' || sqlerrm, 3);
          fp_error := 1;
          end fixedInfoForImagePurpose;

  procedure insertFixedInfoForWebServiceProcess(fp_webserviceprocess_id webserviceprocess.webserviceprocess_id%type,
                                              fp_description webserviceprocess.description%type,
                                              fp_active webserviceprocess.active%type) is
  begin
    select count(i.webserviceprocess_id)
    into id
    from webserviceprocess i
    where i.webserviceprocess_id = fp_webserviceprocess_id;
    if (id=0) then
    insert into webserviceprocess (webserviceprocess_id, description, active, systemuser_id, timestamp)
    values (fp_webserviceprocess_id, fp_description, fp_active, 1, sysdate);
    end if;
  end insertFixedInfoForWebServiceProcess;

    procedure fixedInfoForWebServiceProcess is
    begin
      insertFixedInfoForWebServiceProcess(1, 'Generate Putup Docs', 'Y');
      insertFixedInfoForWebServiceProcess(2, 'Generate Direct Invoices', 'Y');
      insertFixedInfoForWebServiceProcess(3, 'Check Route Control Status', 'Y');
      commit;
      exception
        when others then
          rollback;
          write_log('Error at WEBSERVICEPROCESS: ' || sqlerrm, 3);
          fp_error := 1;
    end fixedInfoForWebServiceProcess;

      procedure insertFixedInfofora_tablelist_tableinfo(fp_a_tablelistinfo_tablename a_tablelist_tableinfo.tablename%type,
                                                        fp_a_tablelistinfo_dimension_table a_tablelist_tableinfo.dimension_table%type) is
  begin
    select count(1)
    into id
    from a_tablelist_tableinfo i
    where i.tablename = fp_a_tablelistinfo_tablename;
    if (id=0) then
    insert into a_tablelist_tableinfo(a_tablelist_tableinfo_id, tablename, dimension_table, systemuser_id, timestamp)
    values (SEQ_A_TABLELIST_TABLEINFO.nextval, fp_a_tablelistinfo_tablename, fp_a_tablelistinfo_dimension_table, 1, sysdate);
    end if;

  end insertFixedInfofora_tablelist_tableinfo;

    procedure fixedInfofora_tablelist_tableinfo is
    begin


      insertFixedInfofora_tablelist_tableinfo('CONTACTCAUSE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTCAUSE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTFOLLOWUPNOTE', 'N');
      insertFixedInfofora_tablelist_tableinfo('CONTACTFOLLOWUPNOTERASYNC', 'N');
      insertFixedInfofora_tablelist_tableinfo('CONTACTFOLLOWUPTELESERVICE', 'N');
      insertFixedInfofora_tablelist_tableinfo('CONTACTPERSON', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTPERSONFUNCTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTPERSONFUNCTION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTRASYNC', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTRESOLUTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo('CONTACTRESOLUTION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTACTTELESERVICES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTACTWAV', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERBILLPERCUSTOMER', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERCHARGE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERCONTENTBUNDLE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERRENT', 'N');
      insertFixedInfofora_tablelist_tableinfo('CONTAINERRENTDETAILS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERREPAIR', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERSPERPNSTOP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERSPERSTOP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINERTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTAINER_DELIVERYSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTAMENDMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTATTRIBUTE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTATTRIBUTEDEPEND', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTBILLINGCOMMENTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTBRAND', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPLIANCY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTBGPROTECTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTBILLING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTCCCHARGESCH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTGRMCHARGES', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTGRMSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTMISC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCOMPONENTNONGRMCHARGES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTCOMPONENTPAYMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTCOMPONENTQTYCTRL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCUSTOMERBRAND', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCUSTOMERGAINLOSS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTCUSTOMERQMGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTDEFWEARERPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTDEFWEARINVPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTDISCOUNTLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBROIDERYCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBTEMP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBTEMPBRAND', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTEMBTEMPCUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBTEMPLINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBTEMPLINECUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBTEMPLINEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTEMBTEMPPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPOCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPOINVOICELINETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRICELIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRIMARYTOSECLINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTADDBILLING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTBGPROTECTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTBILLING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTBM6', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTBM6DELDAYS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTBRAND', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTDELFREQ', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTDELFREQCOMPL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTIMAGECARE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTMISCELLANEOUS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTPRODUCTORDERDELIVERY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTPLPC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTPRICING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPRODUCTQMGLIMIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPURCHASEORDER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTPURCHASEORDERLINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTQMGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTSPECIALCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTSPECIALCHARGECUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTSPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTSTDINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTSTDINVENTORYCUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTUSERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTWEARERFUNCBRAND', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTRACTWEARERFUNCCUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CONTRACTWEARERFUNCTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONVERTPRODUCTTABLELIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COSTCENTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COSTCENTERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COSTCENTERHISTINVDATA', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'COSTCENTERINVOICELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'COSTCENTERSPECIALCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COSTCENTER_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COSTPRICELIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COSTPRICELISTDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COSTPRICELISTPERPLANT', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo(  'COSTREPORTEXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'COSTREPORTINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'COSTSETTINGSPERPLANT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COUNTRY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COUNTRYCOMMINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COUNTRYPOSTALINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CPLTRANSITION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CREDITCARDCHARGESCHEDULE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CREDITCARDFIXEDPAYDATES', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CREDITCARDTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CREDITCARDTRANSACTIONREFUND', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CSVEXPORT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CURRENCY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CURRENCYEXCHANGERATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERACH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERACTIVITIES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERBGPROTECTIONPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERBILLINGCOMMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERBILLINGINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERBILLINGLOG', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERBUDGETDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERBUDGETINVLINETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERBUDGETPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERBUDGETPROTECTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERBUDGETUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCASHDELAYCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCCCHARGESCHEDULE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERCLIENTDELNOTEREMARK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCLUSTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCONTAINERDELPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCONTAINERRENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERCONTAINERRETCREDIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCONTAINERTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERCOSTREPORTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERCOSTSPECIFICATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCOVERPAGEINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERCREDITCARD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERCREDITCARDHIST', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERDELIVERYDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERDELIVERYSCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERDOWNPAYMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERDOWNPAYMENTINVLINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMEREASYCAREPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMEREDIINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMEREFFICIENCYCHECK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERENVINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMEREXCHANGECHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMEREXTRAINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERGARMENTCHARGES', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERGARMENTDISPENSER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERGENERAL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERIMAGECAREPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERINSURANCEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERINTERFACE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERINTERNETOPTIONS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERINVENTORYCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERINVLINETYPETAXDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERINVLINETYPETOGDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERINVOICEBUDGET', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERLABELLAYOUTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERLOCKERMANAGEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERLOCKERPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERMINRESVALUEAMOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERMONTH', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERPREPCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERPROCESSLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERPROCESSLISTDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERPRODUCTCONVERSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERPRODUCTTAXDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERPRODUCTTOGDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERRAGREASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERRANKING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERREASONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERREISSUEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERRENTDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERRENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERREPAIRPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERREPLACEMENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERRESIDENTIALRENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERRESIDENTIALSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERRESTOCKINGFEEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERROUTEINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERROUTESTOP_POS_FILE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSALESPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSBCHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERSERVICECOSTSPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERSERVICEEVENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSORTINGDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSPECIALCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERSPECIALCHARGEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERSPECIALCHARGETOGDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSPERCLUSTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERSTMTHANDLINGPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSTOCKCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERSTOCKCHARGEINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERSURVEYTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERTRANSPORTARTICLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERUSERINSTRUCTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERUSERINSTRUCTIONEXCLPD', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERUSERINSTRUCTION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERWASHDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERWASHPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERWEIGHINGCATEGTOGDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMERWEIGHTDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMERWEIGHTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMER_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CUSTOMER_POS_FILE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CUSTOMSPREFERENCELOOKUP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CUST_SALESCOMMISSION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DATABASESCRIPT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DATABASESCRIPTCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DATABASESCRIPTEXECUTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DATABASESETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DATE_FISCALYEAR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DATE_YEARWEEKDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DAY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DBCHECKONSYSTEMSETTING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DBCONSISTENCYCHECK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DBCONSISTENCYCHECKLOG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DEFAULTWEARERINVPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DEFAULTWEARERPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DEFAULTWEBGRIDSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DEFRESIDUALVALUESCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVEREDQTYPERINVENTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYAVERAGE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYLOAD', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYLOADDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYLOADDETAILSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYNOTEREMARK', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYNOTEREMARK_DESC', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYPOINT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYPOINTIMAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYPOINTOPENINGHOUR', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYPOINT_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYSCANEXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYSCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYSCHEMESPERSTOP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYSCHEME_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYSIGNATURE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYTERM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DELIVERYTERMPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYTERM_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DELIVERYVARIATIONS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DEPARTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DEPARTMENTROOM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DEPARTMENTUSAGEDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DEPARTMENT_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DEPOT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DIALOGFLEXFIELDS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DIALOGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DIALOGS_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DIALOGUSELOG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DISCOUNTLISTPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DISPATCHADVICEHEADER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DISPATCHADVICELINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DISTRIBPOINTBGPROTECTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DISTRIBUTIONPOINT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'DISTRIBUTIONPOINT_LINK', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'DISTRICT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DISTRICTPLANT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'DIVISION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'DIVISION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EDIINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMAILDOCUMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMAILSETTING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMAILSETTINGREPLPARAM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMAILSETTING_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMBLEMFONT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMBLEMHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'EMBLEMPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMBLEMTEMPLATE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'EMBLEMTEMPLATEFUNCTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'EMBLEMTEMPLATELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'EMBLEMTEMPLATELINEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMBLEMTEMPLATEPREPCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMBLEMTEMPLATEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMBROIDERYCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMPLOYEE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'EMPLOYEEFUNCTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMPLOYEEFUNCTIONAUTH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMPLOYEEFUNCTIONAUTHDEF', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMPLOYEEFUNCTIONAUTHDEFDET', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EMPLOYEEFUNCTIONDIALOG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EMPLOYEEFUNCTION_HISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'EMPLOYEETURNOVERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXCHANGECART', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXCHANGECARTCYCLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXCHANGECARTDELIVERYSTOP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXCHANGECARTREPLACEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXCHANGECARTSCHEDULE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXPIRATIONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXTERNALGARMENTSORTDATA', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EXTERNALGARMENTTRACKDATA', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'EXTERNALSTERILIZATIONLOT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'EXTERNAL_AR_BALANCES', 'N');
     -- commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'EXTRABAGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXTSTOCKTRANSTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'EXTSTOCKTRANSTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FABRIC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FABRICCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FABRIC_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FAILOVERMASTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FAILOVERPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FIELDSPERDIALOG', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FIELDSRELATIONS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FINANCECHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FINANCIALYEARCONVERSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FINISHINGCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FINISHINGCODE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FINISHINGMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FINISHINGMETHODCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FINISHINGMETHOD_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FIRSTDELIVERYSCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FIRSTDELIVERYSCHEMESPLIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FIRSTDELIVERYSCHEME_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FLAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FLAGOPTIONS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FLAG_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FLEXIBLESTORAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FLEXIBLESTORAGELOCATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FOLDINGPROGRAMDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FORMLAYOUT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FORMLAYOUTSTATEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'FORMLAYOUT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FORMPRINTCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'FREEOFCHARGEADJUSTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GACUSTOMERPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GAINLOSTREASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GAINLOSTREASON_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GARMENTBATCH', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'GARMENTBATCHSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'GARMENTBATCHSORT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'GARMENTDISPENSER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GARMENTDISPENSERMESSAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GARMENTSALESHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'GDTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALBGPROTECTIONPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALCONTAINERDELPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALCONTAINERRENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALCONTAINERRETCREDIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALDISCOUNTLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALEMBLEMPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALINSURANCEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALPRICELIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALRENTDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALRENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALREPAIRPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALREPLACEMENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALSALESPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALSERVICEEVENTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALSPECIALCHARGEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALSPECSIZECHARGEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALSYSTEMSETTING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALUSERINSTRUCTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALUSERINSTRUCTIONEXCLPD', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALUSERINSTRUCTIONPERCUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALUSERINSTRUCTION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALWASHDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALWASHPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GENERALWEIGHTDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'GENERALWEIGHTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GLEXPORT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'GLOBALMODULES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GLOBALSETTING', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'GRIDCOLUMN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'GROWTHHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'HFREADERCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'HIVELOG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'IMAGEPURPOSE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'IMAGE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INCIDENTALINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INTERNALBUACTIVITIES', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INTERNALSUPPLYCHAIN', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INTERNALVALUEHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INTERNETORDER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INTERNETORDERLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INTRASTAT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVENTORYCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INVENTORYCATEGORYPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEAPPENDIX', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEAPPENDIXDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEAPPENDIXPERCUSTOMER', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICECORRECTIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICECORRECTIONTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEFREQUENCY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEFREQUENCYLOSSPERIOD', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEFREQUENCY_DESC', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEHEADER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEHEADERCLIENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEHEADERCURRENCY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEHEADEREDIINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEHEADEREXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEHEADERREASON', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEHEADERTAXEXPORT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEHEADERUS', 'N');
      commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEHEADERXML', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEJOB', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEJOBBUSINESSUNIT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEJOBSCHEDULE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEACTIVITY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEADDITION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEADJUST', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEADJUSTED', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINECLIENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINECLIENTRENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINECONTAINER', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINECURRENCY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEDEPTCOST', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEDP', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINEEXCESSAMOUNT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEEXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEPRODUCT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINEREBILL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINERENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINESUBTYPE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINESUBTYPETAX', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINESUBTYPE_DESC', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINETAX', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINETAXEXPORT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINETGCONTRACTPO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINETYPECHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINETYPETAX', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINETYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINEVARIOUS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICELINEVARIOUSCURRENCY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICELINEWEEK', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICEMESSAGES', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'INVOICEPRICEINCREASEMESSAGE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICESIGNATURE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'INVOICESTOBEDELETED', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ISSUEHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'LABELLAYOUT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LABELLAYOUTENGINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LABELLAYOUTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LABELPRINTENGINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LABELPRINTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LACUSTOMERPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LANGUAGES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LASTCUSTOMERPRICEUSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LASTEMBLEMPRICEUSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LASTPREPCHARGEPRICEUSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LASTPRODUCTPRICEUSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LASTREPAIRPRICEUSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LASTSPECIALCHARGEPRICEUSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LASTUSEDGRIDVIEW', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'LDAPSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LEDGERACCNTSPERPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LEDGERACCNTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LEDGERACCNTTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LEDGERACCOUNTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LEDGERACCTSPERTURNOVERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LEGALENTITY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LICENSEINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LICENSEINFOADJUSTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LICENSEINFOEVENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LICENSETRANSTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LIGHTFRAMEPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LOCALPRINTSERVER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LOCATIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOCATIONTYPEPERSTOCKROOM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOCATIONTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LOCKER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOCKERSORTGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOCKERTRACKINGIDLINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOOKUPVALUES', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOSSGRACESCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOSSGRACESCHEMEDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LOSSGRACESCHEME_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOSSPERIODS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'LOSSPERIODSPROCESSED', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'LOSTITEMSHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'LTXSORTINGSCHEMEDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MAATEMPLATEATTRIBUTE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MAATEMPLATEDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MAATEMPLATEHEADER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MACHINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MACHINECOMPARTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MACHINECOMPARTMENTLIMIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MACHINETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MACHINEWASHINGPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MARKETSEGMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MARKETSEGMENT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MASTERAGREEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MASTERAGREEMENT_HISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'MATCARRYUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MATCARRYUNITCONTENTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MATCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MATORDERINGINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'MATSORTPOSITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MATSORTPOSITIONCONTENTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MAXORDERQUANTITY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MENU', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'MENUGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MENUGROUPSPERUSERGROUP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'MENUGROUP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MENUITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MENUITEM_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MENUSPERUSERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MENU_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MISCELLANEOUSCHARGE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'MISPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MISPRODUCT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MISTURNOVERSEGMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MISTURNOVERSEGMENT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MOBILEDEVICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MODIFICATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MODIFICATIONGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MODIFICATIONGROUP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MODIFICATIONSPERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MODIFICATION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MRPCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MUACUSTOMERSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MUAPRODUCTIMAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MUASETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MUAWEARERPROFILE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MULTIREADEXCEPTIONREASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'MULTIREADEXCEPTIONREASON_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'MULTIREADSCANBATCH', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'MULTIREADSCANBATCHCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'MULTIREADSCANBATCHCONTKNT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'MUNICIPALITY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'NATIONALACCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'NOBUDGETCLIENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'NOBUDGETDEPARTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'NONBUSINESSDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'NONGARMENTMBYO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'NONUNIQUEITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'NONUNIQUEITEMMBYO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'NORMSTOCKAMOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'NOTCHARGEDINVOICELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'OBSOLETEVIEWS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'OLDITEMTONEWITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ONSITEINVENTORYADJUSTMENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'OOSACTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'OOSACTIONRESTRICTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'OOSACTION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'OOSRESTRICTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'OOSRESTRICTION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'OPTIMAHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'OPTIMANORM','Y');
      insertFixedInfofora_tablelist_tableinfo(  'ORDELIVERBUSINESSUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ORDERDEADLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ORDEREDUSEDORPACK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ORDERPRIORITY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ORDERPRIORITY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ORLABELSPERWORKSTATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'OUTOFCIRCHISTEXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'OUTOFCIRCULATIONHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'OUTOFSERVICEPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'OUTOFSTOCKHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'OVERUSEHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKCONTENTSALTERNATIVE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGDEPARTMENTDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTEBOX', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTEBOXQUANTITY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTECONTAINER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTECONTAINERCONTENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTECONTAINERQTY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTEEXCHANGECART', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTELINECONTENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTELINECPL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTELINEDELIVINV', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTELINEDETAILS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTELINEPERDELSCHEME', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTELINESPECIAL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PACKINGNOTEPOD', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTESTOCKTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PACKINGNOTETAX', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PATIENTDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PAYMENTTERMS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PAYMENTTERMS_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PAYMENTTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PAYMENTTRANSACTIONDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PERIOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PERIPHERALAGENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PHASEOUTCPL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PHASEOUTWEARERINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PHONEFAXDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PICKEDUPCONTAINERS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PICKLIST', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PICKLISTLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PICKLISTLINEAS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PICKLISTLINELOCATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PICKLISTLINEORIGIN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PICKLISTLINEORIGINAS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PICKLISTPICKINGSEQUENCE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PICKLISTSTOCKTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PLACEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLACEMENT_DESC', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo(  'PLANT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTCOMPANY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTCREDITCARDEBC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTDEPARTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTDEPARTMENTFINMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTDEPARTMENTMACHINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTDEPTPERCUSTACT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTDEPTPERCUSTACTDEPT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTFLAGOPTIONS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTINVOICEFREQUENCY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTINVOICELINETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTINVOICEREMARK_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTOPERATINGHOURS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTPAYMENTCREDENTIALS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPDFEXPORT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPGSETTINGSBM6', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTPGSETTINGSBM6DELDAYS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPREDEFINEDCONTACTNOTES', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTPROCESSHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPRODSETTINGSBM6', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPRODSETTINGSBM6DELDAYS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTPRODSETTINGSFLEXFIELD', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTPRODUCTGROUPSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPRODUCTSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPRODUCTSIZESETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPRODUCTSIZETRANSPARTICLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTPRODUCTTRANSPORTARTICLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTQUALITYGRADESETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTREPAIRTYPESETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTSPECIALCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTSPERRSCONTRACT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLANTSTMTHANDLINGPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTTAXEXPORTSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLANTTURNOVERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLPCBM6', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCBM6DELDAYS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLPCBM6HISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCBM6RECALCULATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCBUDGETPROTECTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCCHARGEPERCENTAGE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCCLEANROOMPACKINSTRCAT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PLPCDISTRIBPOINTNOBUDGET', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCEXTRAINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCFIXEDWEARERS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLPCINSURANCEPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCSERVICECOSTSPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPCTEMPRENTSTOP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PLPCTREATMENTCHECKSCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'PLPC_POS_FILE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'PNLINEPERDELSCHEMENONSEE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'POHEADERCONFIRMATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACCESSRIGHTFIELDLISTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACCESSRIGHTSLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACCESSRIGHTSPERUSERGROUP', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ACCESSRIGHTSVIOLATION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ACQUISITIONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACTIVESTOCKDELIVERY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVESTOCKDELIVERYDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACTIVESTOCKLOCATION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVESTOCKLOCATIONADJACNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACTIVESTOCKLOCATIONCONTENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVESTOCKLOCATIONDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVESTOCKLOCATIONDELSCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVESTOCKLOCATIONDIST', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVESTOCKLOCATIONRESERVE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ACTIVITY', 'Y');
      insertFixedInfofora_tablelist_tableinfo('ACTIVITYPERINVOICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ACTIVITY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ADDRESS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ADDRESSTAXAREAID', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'AGGSUPPLIERORDERINGTERMS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'AGGSUPPLIERPRICETERMS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'AGGSUPPLIERPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'AGGSUPPLIERPRODUCTSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ALLOCATIONSTATUS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ALLOCATIONTRANSACTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ALLOCATIONTRANSACTIONPDA', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ALTERNATIVESIZEDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'AMENDMENTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'APPLICATIONSERVER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'APPLICATIONSERVERMESSAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'APPLICATIONSERVERMESSAGE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'APPPERMOBILEDEVICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'APPSERVERCLUSTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'APPSERVERCLUSTERCONTENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ARBALANCE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ARTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ARTRANSACTIONCOMMISSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ARTRANSACTIONDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ARTRANSACTIONSHADOW', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ARTRANSACTIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ARTRANSACTIONTYPE_DESC', 'Y');
      commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo(  'ARTRANSLEDGERACCOUNTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'AUTOMATICFLAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'AUTOSOILQUANTITY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BACKORDERALLOCATIONWOL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BACKORDERALLOCATIONWOLE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BACKORDEREXECUTIONWOL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BACKORDEREXECUTIONWOLE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BACKORDERPURCHASEORDERWOL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BACKORDERPURCHASEORDERWOLE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BACKORDERREQUISITIONWOL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BACKORDERREQUISITIONWOLE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BACKORDERWOL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BACKORDERWOLE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BAGTAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BANKINSTITUTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BATCH', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BATCHCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BATCHFINISHINGMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BATCHJOB', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BATCHJOBCONTENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BATCHPICKUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BENCHMARKCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUDGET', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUDGETUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUDGETUNIT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUINTERNALCALCINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUNDLESORTBOX', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'BUNDLESORTBOXCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'BUORDERINGCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUPREWASHDAYSDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUSERVICECHARGEEVENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUSINESSUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BUSINESSUNITACTIVITIES', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUSINESSUNITEXTRAINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BUSINESSUNITINTERNALCALCINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BUSINESSUNITPERRAGREASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BUSINESSUNITPERWORKFLOW', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BUSINESSUNITSPECIALSCAN', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'BUSINESSUNITSPERCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'BUSINESSUNITSPERUSERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CART', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CARTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CARTTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CARTUNIQUEID', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CASHAPPLICATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CASHAPPLICATIONSHADOW', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CATALOGUE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CATALOGUETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CATALOGUETYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CATALOGUE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CHAIN', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CHANGES_CUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CHANGES_PLPD', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CHANGES_WEARER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CHARACTERISTIC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CHARACTERISTICPREDEFVALUE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CHARACTERISTICSTEMPLATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CHARACTERISTICSTEMPLATE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CHARACTERISTICSTEMPLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CHARACTERISTIC_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CHIPPINGRATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CITYCOUNTY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CITYCOUNTYTAXRATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANCOUNTDELIVERY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCH', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHCONTENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHCOUNTCONTENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHPACKINGNOTE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLEANROOMBATCHPKBOX', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHPKBOXQTY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHSTEP', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMBATCHWASHING', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLEANROOMBOXLOCATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMCUSTOMERTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMPACKINSTRCAT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANROOMPACKINSTRUCTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLEANUPSCANCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTBILLINGINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTCATEGORYINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTCONTACTPERSON', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTDELIVERYNOTE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTDELIVERYNOTELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTDELIVERYNOTELINK', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTDELIVERYNOTESPECCHARGE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTDELIVERYNOTETAX', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTDELNOTELINEDELAYED', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTDELNOTELINEPOOL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTDELNOTELINESCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTFINISHINGMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTINVOICECATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTINVOICECATEGORYCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTINVOICECATEGORYPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTPRIVATEPERSON', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CLIENTPRODFINISHINGMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTRENTADJUSTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENTRESIDENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CLIENT_LINK', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'CLIEOP03BATCH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'CODETAPEPLACEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CODETAPEPLACEMENT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COLOR_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMMISSIONAVAILABLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMMISSIONDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMMUNICATIONMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMMUNICATIONMETHOD_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMPETITOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMPLIANCYGROUPATTRIBUTES', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'COMPLIANCYTEMPLATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMPLIANCYTEMPLATELINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'COMPORTCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'COMPRESSEDIMAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONSIGNMENTNOTE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'CONTACT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'CONTACTATTACHMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTACTCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'CONTACTCATEGORY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEIGHTBASEDDELHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHTOVERRIDE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WOREFERENCECUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WOREFERENCENUMBER', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOW', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOWSTEP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKFLOWSTEPDLG', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOWSTEPINST', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOWSTEPRPT', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOWSTEPTEXT', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOWSTEPURL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKFLOWSTEP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo('WORKFLOW_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDER', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERITEMDISTRIBUTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINEEMBLEM', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINEEMBLEMNAME', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERLINEEMBLEMPOLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERLINEEMBLEMPREP', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERLINEEMBLEMRESERVATION', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERLINEEMBPURCHREQ', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINEMODIFICATION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINEPREPARATION', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERLINEPURCHORDLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERLINEPURCHREQ', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINEREPLACEMENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERLINERESERVATION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERNCPICKSEQUENCE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERPICKSEQUENCE', 'N');
      insertFixedInfofora_tablelist_tableinfo('WORKORDERSHIPPINGINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERSPLIT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKORDERSTOCKTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONBOXPOSITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONCONTAINER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONEXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONOUTCLBATCH', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONPLCCONFIG', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONPNLOCK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONPRINTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONSPECIALSCANS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WORKSTATIONUHFREADER', 'Y');
      insertFixedInfofora_tablelist_tableinfo('POLINECONFIRMATION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'POSEXPORT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'POSPLITCRITERIONSTOCKROOM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'POSPLITCRITERIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'POSPLITCRITERIONTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'POSTALCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('POSTALCODEACTIVITIES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'POSTALCODEDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PREDEFINEDCONTACTNOTES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PREDEFINEDCONTACTNOTES_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PREDEFINEDREPORT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PREDEFINEDSCREEN', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PREFERENCE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRESORTBATCH', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRICEINDEX', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRICEINDEXHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo('PRICELISTPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRICELISTPERMARKETSEGMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRICELISTUSERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRICEUPDATEHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PRINTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRINTERPERWORKSTATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRINTINGRECEPTIONSTICKERS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRINTQUEUE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PRINTQUEUERESIDENTIALITEM', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODPROCESSBUFFERSNAPSHOT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODREPLENISHADJUSTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODSIZEAGGSUPPLPRODSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTAXAPTA', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTBM6', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTBM6DELDAYS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTCATALOGUE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTCONVERSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTCONVERSIONCPL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTCONVERSIONFM', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTCONVERSIONSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTCONVWRINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTDELIVERYDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTDETAILMICROSS', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTFINISHINGMETHOD', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTFINISHINGMETHODCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTGROUPBM6', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTGROUPBM6DELDAYS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTGROUPCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTGROUPPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTGROUPTAX', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTGROUP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTIONCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTIONPROCESSBUFFER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTIONPROCESSSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTIONPROCESSSCANAGGR', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTIONQUEUE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTLISTPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTLISTPERDISTRIBPOINT', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTMODIFICATIONGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTORPACK', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTRANKING', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTSERVICECATALOGUE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTSIZEPERSUPPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTSIZETRANSPARTICLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTSORTGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTSORTGROUPPERPLANT', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTTAX', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTTRANSPORTARTICLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCTUNIQUEITEMSERVICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTVERTEXTAXONLY', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PRODUCTWASHINGPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCT_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PRODUCT_LINK_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PROOFOFVISITHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PROVISIONGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PURCHASEORDERADDRESSINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PURCHASEORDERAPPROVAL', 'N');
      insertFixedInfofora_tablelist_tableinfo('PURCHASEORDERHEADER', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PURCHASEORDERLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PURCHASEORDERLINEDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PURCHASEORDERSTOCKTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'PURCHASEREQUEST', 'N');
      insertFixedInfofora_tablelist_tableinfo('PURCHASEREQUESTALLOCATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PURCHASEREQUISITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo('PURGEPLANTCONFIG', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'PURGETABLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'QUALITYGRADE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'QUALITYGRADE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'QUALITYTESTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'QUALITYTESTTYPEPERBU', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'QUALITYTESTTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RAGGEDITEM', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'RAGGEDRESIDENTIALITEM', 'N');
      insertFixedInfofora_tablelist_tableinfo('RAGREASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RAGREASONDIALOGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RAGREASONILSUBTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('RAGREASON_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RAILIMPORTDEFINITION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'RASTOPACTIONORDER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RASTOPACTIONORDER_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REASONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo('REASONCODEDIALOGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo('REASONCODE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REASONLINKTORAGREASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RECEIVEINSTOCKHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'REFERENCEWEIGHING', 'N');
      insertFixedInfofora_tablelist_tableinfo('REFERENCEWEIGHINGDETAILS', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'REFRESHTOKEN', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REGION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REGION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo('REGISTRATIONUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REGISTRATIONUNIT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REJECTEDSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'REMITBATCH', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'REMOTEPERIPHERALAGENTUSE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'RENTALQTYADJUSTMENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'REPAIRADDRESSPERCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REPAIRHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'REPAIRPOINTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REPAIRTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'REPAIRTYPESPERBU', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REPAIRTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REPORTPARAM', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'REPORTSERVER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'REPORTSERVERCLUSTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'RESERVEBOXESINBATCH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'RESIDENTIALITEMSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'RESIDENTIALITEMSCANFLAG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'RESIDENTIALRENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RESIDENTIALREPAIR', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'RESIDUALVALUEHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'RESIDUALVALUELOSTCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RESIDUALVALUESCHEME', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RESIDUALVALUESCHEME_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RESPONSECODETRANSLATION', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo(  'RESTRESOURCE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'RESTRESOURCEUSER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'REST_VIEW_PARAMETERS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'RESVALSCHEMEDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'RESVALSCHPERPLPCREASONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTEASSISTANTSYNCREQUEST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTEASSISTANTTRANSACTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECHANGETRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECODEMASTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTECONTROL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTECONTROLAD', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECONTROLBPPACKDEPT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECONTROLBULKPACKING', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECONTROLBULKPACKSTOP', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECONTROLCONTAINER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECONTROLEXTRAINFO', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTECONTROLINTERNALBU', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTECONTROLRADOWNLOAD', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTECONTROL_COMMISSION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTEDOCUMENTGENERATIONQ', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTEEXTRAINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTESTOP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTETRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTETRANSACTIONCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTETRANSACTIONCATEGORY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTETRANSACTIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'ROUTETRANSACTIONTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'ROUTETRANSTYPEREASONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SAFETYCHECK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SAFETYCHECKHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SAFETYCHECKPERTRUCK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SALESAREA', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SALESAREA_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SALESCOMMISSION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SALESJOURNALGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SALESJOURNALGROUP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SCANFLAG', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SCRUTINYCHECK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SCRUTINYMINNOMINAL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SDORDERLINEDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SEASON', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SEASONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SEASONTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SEASONWEEK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SECONDARYCONTAINER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SECONDARYIDRESIDENTIALITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SECONDARYUNIQUEITEM', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SECRENTALQTYADJUSTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SECURITYCERTIFICATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SELECTIONCONDITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SELECTIONCRITERIA', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SERIALDEVICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SERVICECHARGEEVENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SERVICECHARGEEVENT_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SERVICEEVENTCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SERVICETEAM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SETCONTENTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SETTINGGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTLISTLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTLISTLINEOR', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SHIPMENTLISTLINEORPACK', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTLISTMAT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SHIPMENTLISTMATLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTLISTMATLINEDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTLISTOR', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SHIPMENTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SHIPMENTTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SHUTDOWNAPPSERVERCLMSG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SICCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SIGNALLIGHTSSET', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SIGNALLIGHTSSETCOMPONENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIGNALLIGHTSSETCOMPONENTFLAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZEBILLGROUPPERPRODGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZEBILLINGGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZEDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SIZEDEFINITION_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZEDEFINITION_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZEDEFINITION_LINK_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SIZEGROUPINGCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZERATIO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZESPERSIZETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZETYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SIZETYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SMALLVALUEWRITEOFFCONTROL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SOILBAGTAG', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SOILCOUNT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SOILCOUNTLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SOILHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SOILREASONABILITY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SOILTICKET', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SOILTICKETLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SOILTICKETLINEPERUSER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SORTADDRESSPERFINISHINGCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTADDRESSPERFINISHINGMETH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTADDRESSPERFLAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTADDRESSPERPRODPERCUST', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SORTADDRESSPERPRODUCT', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'SORTADDRESSPERPRODUCTSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SORTADDRESSPERREASONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTADDRESSPERSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SORTADDRESSPERWASHPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTBATCH', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SORTBATCHCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SORTBATCHDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SORTBATCHDEFINITIONDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SORTEXXDEVCOMPARTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SORTEXXDEVICECONFIG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTINGCABINETBOX', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTINGCABINETBOXCONTENTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SORTINGCOLOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTINGDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTINGDEFINITIONRS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTINGIMPORTDEFINITION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SORTINGRULE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SORTINGRULECOMPONENT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SORTTUB', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SORTTUBCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SORTTUBRELEASED', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SORTTUBRELEASEDCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SOUND', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SOUNDCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SPECIALCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SPECIALCHARGEPERINVLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SPECIALCHARGETAX', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SPECIALCHARGE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SPECIALSCANS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SPECIFICLEDGERACCOUNTLINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SQARAGING', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQCOMMISSION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SQCOSTSPBA', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQITEMINCIRCULATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQLEASE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQLEASEDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQLSCRIPT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SQLSCRIPT_LOG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQMATINCIRCULATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQMAXITEMINCIRCULATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQONSITEINVENTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQRESIDENTIALITEM', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQSETINCIRCULATION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQSTOCKCHARGE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SQSTOCKQUANTITY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'SQWEARER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQWEARERINVENTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQ_DAILY_AR_U', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SQ_WEEKLY_REVENUE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STANDARDDELIVERY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STANDARDDELIVERYAMNTDETAILS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STANDARDDELIVERYAMOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STANDARDDELIVERYHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'STANDARDDELIVERYLINE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STANDARDINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STANDARDLOCATIONPERPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STANDARDLOCATIONPERSIZE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STATEMENTLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STATES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STATESTAXRATE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STATETAXGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STATUS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STATUSQUOHEADER', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'STATUS_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STAY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STERILIZATIONRUN', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STERILIZATIONRUNPERCRB', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STERILIZER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STERILIZERPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKCOUNTDEVICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKCOUNTSCHEDULE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKCOUNTSCHEDULEDAY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKCOUNTSCHEDULEDEPT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKCOUNTSCHEDULEDIST', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKCOUNTSCHEDULE_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKDEFINITIONPERITEM', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKQUANTITY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKRESERVATIONPERGRADE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKROOM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKROOMLOCATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKROOMOOSACTIONS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKROOMPRINTINGSTICKERS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKROOMPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKROOMSHIPPINGSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKROOMSPERREASONCODE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKROOMSSERVICINGBU', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKROOMSUPPLIER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKTRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKTRANSFERHEADER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKTRANSFERLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKTRANSFERUNIQUEITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STOCKVALUEAVGPP', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'STOCKVALUEFIFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STOP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'STOPGPSDATA', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'STORENUMBERMASTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'STRAIGHTEVENRETURN', 'N');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo( 'SUBCONTRACTOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SUPPLIER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SUPPLIERDELDAY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SUPPLIERDOCUMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SUPPLIEREDISETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SUPPLIERMODEL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SUPPLIERPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SUPPLIERPRODUCTPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SUPPLIERPRODVOLUMEDISCOUNT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SUPPLYCHAINRULES', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SURVEYSCORE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SURVEYTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SURVEYTYPEQUESTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SURVEYTYPEQUESTIONCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SYSTEMSETTING', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'SYSTEMUSER', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'SYSTEMUSERAPPDEFAULTS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SYSTEMUSERPREFERENCE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'SYSTEMUSERWEBGRIDSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TARGETUSAGEPERBUDGETUNIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TAXDEFINITION', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'TAXGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TELESERVICESDATACLEAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'TELESERVICESEXPORT', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'TELESERVICESIMPORT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TEMPORARYDELIVERYSTOP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'TEMPORARYGARMENTRENTSTOP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TEMPORARYRENTSTOP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TOUCHSCREENBUTTON', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TOUCHSCREENBUTTON_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TOUCHSCREENPAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TOUCHSCREENPAGE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TRANSACTIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TRANSACTIONTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TRANSPORTARTICLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TRANSPORTARTICLE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TREATMENTCHECKSCHEME', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'TREATMENTCHECKSCHEMEDETAIL', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'TREATMENTSCAN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'TREATMENTSCANCHARACTERISTIC', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'TREATMENTSPERSUBCONTRACTOR', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TREATMENTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TREATMENTTYPEPERBU', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TREATMENTTYPE_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TRUCK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TRUCKRELOAD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TURNOVERFORECASTDETAIL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TURNOVERFORECASTHEADER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TURNOVERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'TURNOVERGROUPPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'TURNOVERGROUPSPERINVOICELINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'TURNOVERGROUP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UHFANTENNACONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UHFANTENNAMODEL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UHFBUNDLE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UHFCONCENTRATOR', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UHFREADERBRAND', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UHFREADERCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UHFREADERFREQUENCY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UHFREADERMODEL', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UHFREADERSTATUS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UHFREGION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UHFTAGFILTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEBUNDLE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEBUNDLEITEMLINK', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUECURTAIN', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEIDCONFIGURATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEITEMBUFFERINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMCLIENTPOOL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMEMBLEM', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMEXCHANGECART', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEITEMFABRICCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEITEMFIXEDINFO', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEITEMFLAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMIMAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMLOSS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMLOSTINPLANT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMMBYO', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMMODIFICATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEITEMNONPOOL', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMRETURNRENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMROUTE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMSHADOW', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEMSPERSTERILIZATIONRUN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEITEM_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEORPACK', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUEORPACKCART', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEORPACKCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEORPACKRAGCONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEORPACKSTERILE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUEORPACKUNIQUECONTENTS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUERESIDENTIALITEM', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUERESIDENTIALITEMFLAG', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUERESIDENTIALITEMPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'UNIQUERESIDENTIALITEM_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNIQUERESIDITEMIMAGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'UNRELATEDLOAN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'USERACCESSRIGHTSLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'USERDEFINEDRPT', 'Y');
      --commit;
      --section break for pack_Script
      insertFixedInfofora_tablelist_tableinfo(  'USERGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'USERGROUPACCESSRIGHTSLIST', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'USERGROUPDIALOGACCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'USERGROUPPERWORKFLOW', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'USERINSTRUCTIONPERSCREEN', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'USERINSTRUCTIONTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'USRGRPPERUSERDEFINEDRPT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'VALIDATEDBUNDLE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'VERTEXBATCHCONTROL', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'VERTEXBATCHCONTROL_ARCH', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'VERTEXBATCHCONTROL_LOAD', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'VERTEXRERUN', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'VERTEXTRANSACTIONLOG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'VIEWCOLUMN', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'VIEWFILTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'VIEWMISCFILTER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'VISITINGMONTH', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WASHINGPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WASHINGPROCESSALTERNATIVE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WASHINGPROCESS_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WASTESITE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WCPCSPECIALCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEARERACCOUNTABILITYHIST', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERBUDGETTRANSACTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEAREREMPLOYMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEAREREMPLOYMENT_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEAREREMPPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEARERFUNCTION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERFUNCTIONSUBTYPE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WEARERINVENTORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEARERINVENTORYCREDIT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERINVENTORYMODIFICATION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERINVENTORYMOVEMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERINVOICECATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERINVOICECATEGORYPRODUCT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERINVPRICE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEARERTEMPASSIGNMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEARER_POS_FILE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEBCATCUSTOMEREXP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBCATINVDECORATIONLINEIMP', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WEBCATINVOICEDECORATIONIMP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBCATINVOICEHEADERIMP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBCATINVOICEPRODUCTIMP', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBEVENTTYPE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBMENUDIALOG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBMENUDIALOGINVFREQUENCY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEBMENUDIALOG_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBMENUGROUP', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBMENUGROUP_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBORDER', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBORDERLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WEBPORTALEVENT', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEBPORTALPAYMENTSESSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBPORTALPAYMENTSESSLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WEBSERVICELOG', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEBSERVICEPROCESS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBSERVICETRANSACTION', 'N');
      insertFixedInfofora_tablelist_tableinfo( 'WEBSESSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSERDEPARTMENT', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSERDIALOG', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSERGRIDSETTINGS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSERRESETPASSWORD', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEBUSERSEARCHSETTINGS', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEBUSERSESSION', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEEKSTATISTICS', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGCATEGORY', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGCATEGORYCHARGE', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGCATEGORYTAX', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEIGHINGCATEGORY_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGCATEGORY_LINK', 'Y');
      insertFixedInfofora_tablelist_tableinfo( 'WEIGHINGCATEGORY_LINK_DESC', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGCATEGPERCUSTOMER', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGHISTORY', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGTICKET', 'Y');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGTICKETLINE', 'N');
      insertFixedInfofora_tablelist_tableinfo(  'WEIGHINGTRANSACTION', 'Y');

      INSERT INTO A_TABLELIST_TABLEINFO
      (A_TABLELIST_TABLEINFO_ID, TABLENAME, DIMENSION_TABLE, SYSTEMUSER_ID, TIMESTAMP)
      SELECT SEQ_A_TABLELIST_TABLEINFO.NEXTVAL, A.TABLENAME, 'Y', 1, SYSDATE
      FROM   A_TABLELIST A
      WHERE  NOT EXISTS (SELECT 1 FROM A_TABLELIST_TABLEINFO I WHERE I.TABLENAME = A.TABLENAME);

      commit;
      exception
        when others then
          rollback;
          write_log('Error at A_TABLELIST_TABLEINFO: ' || sqlerrm, 3);
          fp_error := 1;
    end fixedInfofora_tablelist_tableinfo;

    procedure insertFixedInfoForEmailSettingApp(fp_documenttype emailsettingapp.documenttype%type,
                                              fp_sendingapplication emailsettingapp.sendingapplication%type) is
  begin
    select count(*)
    into id
    from emailsettingapp i
    where i.documenttype = fp_documenttype
    and i.sendingapplication = fp_sendingapplication;
    if (id=0) then
          insert into emailsettingapp (documenttype, sendingapplication, systemuser_id, timestamp)
          values (fp_documenttype, fp_sendingapplication, 1, sysdate);
    end if;
  end insertFixedInfoForEmailSettingApp;

    procedure fixedInfoForEmailSettingApp is
    begin
      insertFixedInfoForEmailSettingApp(1, 0);
      insertFixedInfoForEmailSettingApp(2, 0);
      insertFixedInfoForEmailSettingApp(3, 0);
      insertFixedInfoForEmailSettingApp(4, 0);
      insertFixedInfoForEmailSettingApp(5, 0);
      insertFixedInfoForEmailSettingApp(6, 0);
      insertFixedInfoForEmailSettingApp(7, 0);
      insertFixedInfoForEmailSettingApp(8, 0);
      insertFixedInfoForEmailSettingApp(9, 0);
      insertFixedInfoForEmailSettingApp(10, 0);
      insertFixedInfoForEmailSettingApp(11, 0);
      insertFixedInfoForEmailSettingApp(12, 0);
      insertFixedInfoForEmailSettingApp(13, 0);
      insertFixedInfoForEmailSettingApp(14, 0);
      insertFixedInfoForEmailSettingApp(15, 0);
      insertFixedInfoForEmailSettingApp(16, 0);
      insertFixedInfoForEmailSettingApp(17, 0);
      insertFixedInfoForEmailSettingApp(18, 0);
      insertFixedInfoForEmailSettingApp(19, 0);
      insertFixedInfoForEmailSettingApp(20, 0);
      insertFixedInfoForEmailSettingApp(21, 0);
      insertFixedInfoForEmailSettingApp(22, 0);
      insertFixedInfoForEmailSettingApp(23, 0);
      insertFixedInfoForEmailSettingApp(24, 0);
      insertFixedInfoForEmailSettingApp(25, 0);
      insertFixedInfoForEmailSettingApp(26, 0);
      insertFixedInfoForEmailSettingApp(27, 0);
      insertFixedInfoForEmailSettingApp(28, 0);
      insertFixedInfoForEmailSettingApp(29, 0);
      insertFixedInfoForEmailSettingApp(30, 0);
      insertFixedInfoForEmailSettingApp(31, 0);
      insertFixedInfoForEmailSettingApp(32, 0);
      insertFixedInfoForEmailSettingApp(33, 0);
      insertFixedInfoForEmailSettingApp(34, 0);
      insertFixedInfoForEmailSettingApp(35, 0);
      insertFixedInfoForEmailSettingApp(36, 0);
      insertFixedInfoForEmailSettingApp(37, 0);
      insertFixedInfoForEmailSettingApp(38, 0);
      commit;
      exception
        when others then
          rollback;
          write_log('Error at EMAILSETTINGAPP: ' || sqlerrm, 3);
          fp_error := 1;
    end fixedInfoForEmailSettingApp;


  procedure fixedinfoforpeppol is
    --add data into peppol_endpoint table
    procedure ins_pp(fp_country_code          in varchar2,
                     fp_flexfield_peppol_code in varchar2,
                     fp_schemeid              in varchar2) is
    begin
      insert into peppol_endpoint
        (country_code, flexfield_peppol_code, schemeid)
      values
        (fp_country_code, fp_flexfield_peppol_code, fp_schemeid);
    exception
      when dup_val_on_index then
        null;
    end ins_pp;
  begin
    ins_pp('NL', 'VAT', '9944');
    ins_pp('NL', 'COC', '0106');
    ins_pp('NL', 'GLN', '0088');
    ins_pp('BE', 'VAT', '9925');
    ins_pp('BE', 'COC', '0208');
    ins_pp('BE', 'GLN', '0088');
    ins_pp('SE', 'VAT', '0007');
    ins_pp('SE', 'GLN', '0088');
    ins_pp('DK', 'COC', '0096');
    ins_pp('DK', 'GLN', '0088');
    ins_pp('IT', 'VAT', '0211');
    ins_pp('IT', 'GLN', '0088');
    ins_pp('FI', 'VAT', '0037');
    ins_pp('FI', 'GLN', '0088');
    ins_pp('FR', 'VAT', '0009');
    ins_pp('FR', 'GLN', '0088');
    commit;
  end fixedinfoforpeppol;



  begin
    fp_error:=0;
      if(fp_isRunForUpdate = 0) then-- executed only to create from empty
    select min(language_id)
      into languageID
      from languages;
    -- user group SYSADM
  begin
    select usergroup_id
      into userGroupID
      from usergroup
     where groupname = 'SYSADM';
  exception
    when no_data_found then
      insert into usergroup
        (USERGROUP_ID, GROUPNAME, DESCRIPTION, ACTIVE, REMARK, SYSTEMUSER_ID, timestamp, contactmanageractive,
         singletask, enableleasebuyback, ALLOWCHNGCUSTPAYMENTTERM, DASHBOARD, AUTHRIGHTSCONTRACT, AUTHRIGHTSPRICELIST,
         PASSWORDREQUIRED, MULTIPLELOGINALLOWED, PASSWORDCHANGEALLOWED, PASSWORDCOMPLEXITY, MINPASSWORDLENGTH)
      values
        (seq_usergroup.nextval, 'SYSADM', 'System administrator', 'Y', null, 1, sysdate, 'N', 'N', 'N', 'N', 0, 'N',
         'N', 0, 0, 0, 0, 0)
      returning usergroup_id into userGroupID;
  end;
  -- user group ABSADM
  begin
    select usergroup_id
      into absGroupID
      from usergroup
     where groupname = 'ABSADM';
  exception
    when no_data_found then
      insert into usergroup
        (USERGROUP_ID, GROUPNAME, DESCRIPTION, ACTIVE, REMARK, SYSTEMUSER_ID, timestamp, contactmanageractive,
         singletask, enableleasebuyback, ALLOWCHNGCUSTPAYMENTTERM, DASHBOARD, AUTHRIGHTSCONTRACT, AUTHRIGHTSPRICELIST,
         PASSWORDREQUIRED, MULTIPLELOGINALLOWED, PASSWORDCHANGEALLOWED, PASSWORDCOMPLEXITY, MINPASSWORDLENGTH)
      values
        (seq_usergroup.nextval, 'ABSADM', 'ABS administrator', 'Y', null, 1, sysdate, 'Y', 'N', 'Y', 'Y', 2, 'Y', 'Y',
         0, 0, 0, 0, 0)
      returning usergroup_id into absGroupID;
  end;
  -- user SYSADM, password CHANGE_ON_INSTALL
  begin
    select systemuser_id
      into systemUserID
      from systemuser
     where username = 'SYSADM';
  exception
    when no_data_found then
      insert into systemuser
        (SYSTEMUSER_ID, USERGROUP_ID, LANGUAGE_ID, USERNAME, PASSWORD, FULLNAME, ACTIVE, SYSADMIN,
         contactmgrfullrights, creditcardauthorised, SHOWCONTACTLOGIN, LASTLOGINTIMESTAMP, PASSWORDCHANGETIMESTAMP,
         LOCKEDOUT, LASTLOGINATWORKSTATION, LASTLOGINATAPPSERVER, LASTINCORRECTLOGINTIMESTAMP,
         INCORRECTLOGINSSINCEPWCHANGE, LOGGEDIN, PASSWORDEXPIRES, CHANGEPASSWORDNEXLOGIN)
      values
        (seq_systemuser.nextval, userGroupID, languageID, 'SYSADM', 'cUSwcnDkgmYn5Y0bsLfpM3xXeXnFTEUj',
         'Automatic conversion from legacy system', 'Y', 'Y', 'N', 'N', 'N', null, null, 'N', null, null, null, 0, 0, 0,
         'N')
      returning systemuser_id into systemUserID;
  end;
  -- user ABSADM, password CHANGE_ON_INSTALL
  begin
    select systemuser_id
      into absUserID
      from systemuser
     where username = 'ABSADM';
    update systemuser
       set usergroup_id = absGroupID
     where systemuser_id = absUserID;
  exception
    when no_data_found then
      insert into systemuser
        (SYSTEMUSER_ID, USERGROUP_ID, LANGUAGE_ID, USERNAME, PASSWORD, FULLNAME, ACTIVE, SYSADMIN,
         contactmgrfullrights, creditcardauthorised, SHOWCONTACTLOGIN, LASTLOGINTIMESTAMP, PASSWORDCHANGETIMESTAMP,
         LOCKEDOUT, LASTLOGINATWORKSTATION, LASTLOGINATAPPSERVER, LASTINCORRECTLOGINTIMESTAMP,
         INCORRECTLOGINSSINCEPWCHANGE, LOGGEDIN, PASSWORDEXPIRES, CHANGEPASSWORDNEXLOGIN)
      values
        (seq_systemuser.nextval, absGroupID, languageID, 'ABSADM', 'cUSwcnDkgmYn5Y0bsLfpM3xXeXnFTEUj', 'ABS user', 'Y',
         'Y', 'Y', 'N', 'N', null, null, 'N', null, null, null, 0, 0, 0, 'N')
      returning systemuser_id into absUserID;
  end;
  if systemUserID is null then
    select min(systemuser_id)
      into systemUserID
      from systemuser;
  end if;
  if absUserID is null then
    select min(systemuser_id)
      into absUserID
      from systemuser;
  end if;
  -- businessunitsperusergroup
  for vCursor in (select businessunit_id
                    from businessunit)
  loop
    begin
      insert into businessunitsperusergroup
        (businessunit_id, usergroup_id, systemuser_id, timestamp)
      values
        (vCursor.businessunit_id, userGroupID, systemUserID, sysdate);
      insert into businessunitsperusergroup
        (businessunit_id, usergroup_id, systemuser_id, timestamp)
      values
        (vCursor.businessunit_id, absGroupID, absUserID, sysdate);
    exception
      when dup_val_on_index then
        null;
    end;
  end loop;
  else
  begin
    select systemuser_id
      into systemUserID
      from systemuser
     where username = 'SYSADM';
  exception
    when no_data_found then
      select min(systemuser_id) into systemUserID from systemuser;
  end;
  end if;
  -- invoice frequency
  fixedInfoForINVOICEFREQUENCY;
  -- invoice line type
  fixedInfoForInvoiceLineType;
  -- invoice line type tax
  if(fp_isRunForUpdate = 0) then
    fixedInfoForINVOICELINETAX;
  end if;
  --invoicelinesubtype and  subtype description
  fixedInfoForINVOICELINESUBTYPE;
  --invoice correction type
  fixedInfoForINVOICECORRECTIONTYPE;
  -- AR transaction type
  fixedInfoForARTRANSACTIONTYPE;
  -- status
  fixedInfoForSTATUS;
  -- stay
  fixedInfoForSTAY;
  -- transaction type (scan)
  fixedInfoForTRANSACTIONTYPE;
  -- ResponseCodeTranslation
  fixedInfoForRESPONSECODETRANSLATION;
  -- special scans
  fixedInfoForSPECIALSCANS;
  -- Sound Configuration
  fixedInfoForSOUNDCONFIGURATION;
  if(fp_isRunForUpdate = 0) then
    -- size
   fixedInfoForSIZEDEFINITION;
  end if;
  -- ROUTETRANSACTIONCATEGORY
  fixedInfoForROUTETRANSACTIONCATEGORY;
  -- ROUTETRANSACTIONTYPE
  fixedInfoForROUTETRANSACTIONTYPE;
  -- automaticflag
  fixedInfoForAUTOMATICFLAG;
  -- label print engine
  fixedInfoForLABELPRINTENGINE;
  -- days
  if(fp_isRunForUpdate = 0) then -- execeuted only to create from empty
    fixedInfoForDAYS;
  end if;
  -- processes
  fixedInfoForPROCESS;
  -- residual value scheme '-'
  if(fp_isRunForUpdate = 0) then
    fixedInfoForRESIDUALVALUESCHEME;
  end if;
  -- quality grade
  if(fp_isRunForUpdate = 0) then
    fixedInfoForQUALITYGRADE;
  end if;
  -- convertproducttablelist
  fixedInfoForCONVERTPRODUCTTABLELIST;
  -- paymentterms
  if(fp_isRunForUpdate = 0) then
   -- paymentterms
   fixedInfoForPAYMENTTERMS;
   -- address
   fixedInfoForADDRESS;
   -- supplier
   fixedInfoForSUPPLIER;
     -- taxgroup
  fixedInfoForTAXGROUP;
  end if;
  -- db consistency check
  fixedInfoForDBCONSISTENCYCHECK;
  fixedInfoForDBCHECKONSYSTEMSETTING;
  -- form layout
  fixedInfoForFORMLAYOUT;
  -- invoiceappendixdefinition
  fixedInfoForINVOICEAPPENDIXDEFINITION;
  if(fp_isRunForUpdate = 0) then
    ---locationtype
    fixedInfoForLOCATIONTYPE;
    ---stocktype
    fixedInfoForSTOCKTYPE;
  end if;
  ----- ledgeraccnttype
  fixedInfoForLEDGERACCNTTYPE;
  ----extstocktranstype
  fixedInfoForEXTSTOCKTRANSTYPE;

  if(fp_isRunForUpdate = 0) then
    --employee function
    fixedInfoForEMPLOYEEFUNCTION;
    --district
    fixedInfoForDISTRICT;
  end if;
  --employee
  if(fp_isRunForUpdate = 0) then
    fixedInfoForEMPLOYEE;
  end if;
  --dwh_settings
  fixedInfoForDWH_SETTINGS;
  ---dwh_settingspertable
  fixedInfoForDWH_SETTINGSPERTABLE;
  ---DWH_STRINGS
  fixedInfoForDWH_STRINGS;
  --plantpdfexport table--
  fixedInfoForPlantPdfExport;
  if(fp_isRunForUpdate = 0) then
    --WebMenuGroup
    fixedInfoForWEBMENUGROUP;
    --Dialogs table
    fixedInfoForDIALOGS;
    --webmenudialog table
    fixedInfoForWEBMENUDIALOG;
    --WebUserDialog
    fixedInfoForWEBUSERDIALOG;
  end if;
  --webeventtype table
  fixedInfoForWEBEVENTTYPE;
  --REASONCODE tables
  fixedInfoForREASONCODE;
  fixedInfoForREASONCODEDIALOGS;
  if(fp_isRunForUpdate = 0) then
    --RAGREASON tables
    fixedInfoForRAGREASON;
  end if;
  fixedInfoForRAGREASONDIALOGS;
  if(fp_isRunForUpdate = 0) then
    --EXTRABAGS tables
    fixedInfoForEXTRABAGS;
  end if;
  --MULTIREADEXCEPTIONREASON table
  fixedInfoForMULTIREADEXCEPTIONREASON;
  if(fp_isRunForUpdate = 0) then
    --garmentdispensermessage
    fixedInfoForGARMENTDISPENSERMESSAGE;
    --POSPLITCRITERIONTYPE table
    fixedInfoForPOSPLITCRITERIONTYPE;
  end if;
  ---UHFREADERBRAND table --???
  fixedInfoForUHFREADERBRAND;
  --UHFREADERMODEL table
  fixedInfoForUHFREADERMODEL;
  if(fp_isRunForUpdate = 0) then
  --UHFREGION table
  fixedInfoForUHFREGION;
  end if;
  --UHFANTENNAMODEL table
  fixedInfoForUHFANTENNAMODEL;
  if(fp_isRunForUpdate = 0) then
  --OrderPriority table
  fixedInfoForORDERPRIORITY;
  --appservercluster table
  fixedInfoForAPPSERVERCLUSTER;
  end if;
  -- fieldsperdialog table --
  fixedInfoForFIELDSPERDIALOG;
  -- fieldsrelations table --
  fixedInfoForFIELDSRELATIONS;
  --  CONTRACTATTRIBUTE
  fixedInfoForCONTRACTATTRIBUTE;
  --  CONTRACTATTRIBUTEDEPEND
  fixedInfoForCONTRACTATTRIBUTEDEPEND;
  -- MAATEMPLATEATTRIBUTE table --
  fixedInfoForMAATEMPLATEATTRIBUTE;

  --OOSAction
  fixedInfoForOOSACTION;
  if(fp_isRunForUpdate = 0) then
    --OOSRESTRICTION
    fixedInfoForOOSRESTRICTION;
  end if;
  --OOSACTIONRESTRICTION
  fixedInfoForOOSACTIONRESTRICTION;
  --SERVICECHARGEEVENT
  fixedInfoForSERVICECHARGEEVENT;
  if(fp_isRunForUpdate = 0) then

    --- preference table ---
    fixedInfoForPREFERENCE;
  end if;
  -- applicationservermessage --
  if(fp_isRunForUpdate = 0) then
    fixedInfoForAPPLICATIONSERVERMESSAGE;
    -- licensetranstype --
    fixedInfoForLICENSETRANSTYPE;
    -- helptext table --
    fixedInfoForHELPTEXT;
  end if;
  -- muasettings table --
  fixedInfoForMUASETTINGS;
  -- globalsetting table --
  if(fp_isRunForUpdate = 0) then
    fixedInfoForGLOBALSETTING;
  end if;
  -- emailsettingreplparam table --
  fixedInfoForEMAILSETTINGREPLPARAM;
  if(fp_isRunForUpdate = 0) then
    -- FINANCIALYEARCONVERSION table --
    fixedInfoForFINANCIALYEARCONVERSION;
  end if;
  if(fp_isRunForUpdate = 0) then
    -- databasescript table --
    fixedInfoForDATABASESCRIPT;
  end if;
  if(fp_isRunForUpdate = 0) then
    -- lossgracescheme table --
    fixedInfoForLOSSGRACESCHEME;
  end if;
  -- lossgraceschemedetail table added in fixedInfoForLOSSGRACESCHEME
  -- reportservercluster table --
  if(fp_isRunForUpdate = 0) then
    fixedInfoForREPORTSERVERCLUSTER;
  end if;
  fixedInfoForEMPLOYEEFUNCTIONDIALOG;
  fixedInfoForCleanRoomBatchStep;
  fixedInfoforcheck_digit_matrix;
  -- RestResource
  fixedInfoForRestResource;
  fixedInfoForRASTOPACTIONORDER;
  --WebServiceProcess
  fixedInfoForWebServiceProcess;
  --a_tablelist_tableinfo
  fixedInfofora_tablelist_tableinfo;
  --EmailSettingApp
  fixedInfoForEmailSettingApp;
  if (FPsLastScriptOfCurrentVersion is not null) then
    begin
      select substr(FPsLastScriptOfCurrentVersion, instr(FPsLastScriptOfCurrentVersion, '.', -1) - 2, 2),
             substr(FPsLastScriptOfCurrentVersion, 1, instr(FPsLastScriptOfCurrentVersion, '.', -1) - 3)
        into lastScriptNo, prefixScript
        from dual;
      for i in 1 .. lastScriptNo
      loop
        insert into sqlscript
          (scriptname, issuccessful, createddate)
        values
          (prefixScript || lpad(i, 2, '0') || '.sql', 'Y', sysdate);
      end loop;
    exception
      when others then
        null;
    end;
  end if;

  -- ImagePurpose
  fixedInfoForImagePurpose;
  --add data into peppol_endpoint table
  fixedinfoforpeppol;

end;

  procedure createNoteSequence(FPsSequenceName           in varchar2,
                               FPsExtraCode              in varchar2,
                               FPsTableName              in varchar2,
                               FPsNoteColumnName         in varchar2,
                               FPsBusinessUnitCode       in businessunit.code%type,
                               FPnMinValue               in integer,
                               FPnMaxValue               in integer,
                               FPsBusinessUnitColumnName in varchar2,
                               FPsFilter                 in varchar2) is
    --noterowsfetched   integer;
    sequenceName     varchar2(150);
    selectStatement  varchar2(500);
    numberNotesFound integer;
    errorMessage     varchar2(500);
  begin
    sequenceName := FPsSequenceName || '_' || trim(FPsBusinessUnitCode);
    if FPsExtraCode is not null then
      sequenceName := sequenceName || '_' || FPsExtraCode;
    end if;
    -- get maximum note number  current BU
    numberNotesFound := 0;
    begin
      selectStatement := 'select COUNT(a.' || FPsNoteColumnName || ') ' ||
                         'from ' || FPsTableName || ' a, businessunit b ' ||
                         'where a.' || FPsBusinessUnitColumnName ||
                         '(+) = b.businessunit_id ' || ' and b.code = ''' ||
                         FPsBusinessUnitCode || ''' ' || ' and a.' ||
                         FPsNoteColumnName || '>=' || FPnMinValue ||
                         ' and a.' || FPsNoteColumnName || '<=' ||
                         FPnMaxValue || FPsFilter;

      --dbms_output.put_line(selectStatement);
      begin
        execute immediate selectStatement
          into numberNotesFound;
      exception
        when others then
          dbms_output.put_line('Select failed.' || sqlerrm);
          RAISE_APPLICATION_ERROR(-20070, sqlerrm);
          return;
      end;

    exception
      when others then
        dbms_output.put_line('select failed.' || sqlerrm);
        RAISE_APPLICATION_ERROR(-20070, sqlerrm);
        return;
    end;

    -- sequence is not created if maxNoteNumber >= FPnNoteNumber
    if numberNotesFound > 0 then
      errorMessage := 'Cannot create ' || sequenceName ||
                      ' sequence inside range(' || FPnMinValue || ', ' ||
                      FPnMaxValue || ')!  ' || numberNotesFound || ' ' ||
                      FPsTableName || 's exist in this range !';
      dbms_output.put_line(errorMessage);
      RAISE_APPLICATION_ERROR(-20070, errorMessage);
      --raise no_data_found;
    end if;

    -- drop sequence
    begin
      execute immediate 'drop sequence ' || sequenceName;
    exception
      when others then
        errorMessage := 'Sequence ' || sequenceName || FPsBusinessUnitCode ||
                        ' cannot be droped.' || sqlerrm;
        --    dbms_output.put_line(errorMessage);
      --   RAISE_APPLICATION_ERROR(-20070, errorMessage);
    end;

    begin
      execute immediate 'create sequence ' || sequenceName || ' minvalue ' ||
                        FPnMinValue || ' maxvalue ' || FPnMaxValue ||
                        ' start with ' || FPnMinValue ||
                        ' increment by 1 nocache';
      dbms_output.put_line('Sequence ' || sequenceName || ' created.');
    exception
      when others then
        errorMessage := 'Sequence ' || sequenceName || ' failed.' ||
                        sqlerrm;
        dbms_output.put_line(errorMessage);
        RAISE_APPLICATION_ERROR(-20070, errorMessage);
    end;

  exception
    when others then
      RAISE_APPLICATION_ERROR(-20070, errorMessage);
  end;
  procedure createIdCodeSequence(FPsSequenceName           in varchar2,
                                 FPsExtraCode              in varchar2,
                                 FPsTableName              in varchar2,
                                 FPsNoteColumnName         in varchar2,
                                 FPsBusinessUnitCode       in businessunit.code%type,
                                 FPsMinValue               in varchar2,
                                 FPsMaxValue               in varchar2,
                                 FPsBusinessUnitColumnName in varchar2,
                                 FPsFilter                 in varchar2) is
    --noterowsfetched   integer;
    sequenceName     varchar2(150);
    selectStatement  varchar2(500);
    numberNotesFound integer;
    errorMessage     varchar2(500);
  begin
    sequenceName := FPsSequenceName || '_' || FPsBusinessUnitCode;
    if FPsExtraCode is not null then
      sequenceName := sequenceName || '_' || FPsExtraCode;
    end if;
    -- get maximum note number for current BU
    numberNotesFound := 0;
    begin
      selectStatement := 'select COUNT(a.' || FPsNoteColumnName || ') ' ||
                         'from ' || FPsTableName || ' a, businessunit b ' ||
                         'where a.' || FPsBusinessUnitColumnName ||
                         '(+) = b.businessunit_id ' || ' and b.code = ''' ||
                         FPsBusinessUnitCode || ''' ' || ' and a.' ||
                         FPsNoteColumnName || '>= ''' || FPsMinValue || '''' ||
                         ' and a.' || FPsNoteColumnName || '<=''' ||
                         FPsMaxValue || '''' || ' and length(' ||
                         FPsNoteColumnName || ')= length(''' || FPsMinValue ||
                         ''')' || FPsFilter;

      dbms_output.put_line(selectStatement);
      begin
        execute immediate selectStatement
          into numberNotesFound;
      exception
        when others then
          dbms_output.put_line('Select failed.' || sqlerrm);
          RAISE_APPLICATION_ERROR(-20070, sqlerrm);
          return;
      end;

    exception
      when others then
        dbms_output.put_line('select failed.' || sqlerrm);
        RAISE_APPLICATION_ERROR(-20070, sqlerrm);
        return;
    end;

    -- sequence is not created if maxNoteNumber >= FPnNoteNumber
    if numberNotesFound > 0 then
      errorMessage := 'Cannot create ' || sequenceName ||
                      ' sequence inside range(' || FPsMinValue || ', ' ||
                      FPsMaxValue || ')!  ' || numberNotesFound || ' ' ||
                      FPsTableName || 's exist in this range !';
      dbms_output.put_line(errorMessage);
      RAISE_APPLICATION_ERROR(-20070, errorMessage);
      --raise no_data_found;
    end if;

    -- drop sequence
    begin
      execute immediate 'drop sequence ' || sequenceName;
    exception
      when others then
        errorMessage := 'Sequence ' || sequenceName || FPsBusinessUnitCode ||
                        ' cannot be droped.' || sqlerrm;
        -- dbms_output.put_line(errorMessage);
    end;

    begin
      execute immediate 'create sequence ' || sequenceName || ' minvalue ' ||
                        FPsMinValue || ' maxvalue ' || FPsMaxValue ||
                        ' start with ' || FPsMinValue ||
                        ' increment by 1 nocache';
      dbms_output.put_line('Sequence ' || sequenceName || ' created.');
    exception
      when others then
        errorMessage := 'Sequence ' || sequenceName || ' failed.' ||
                        sqlerrm;
        dbms_output.put_line(errorMessage);
    end;

  exception
    when others then
      RAISE_APPLICATION_ERROR(-20070, errorMessage);
  end;

  function GetDayNumber(FPdtDate date) return int is
    sunday date := to_date('16/02/2003', 'dd/mm/yyyy');
    monday date := to_date('17/02/2003', 'dd/mm/yyyy');
    diff   int;
  begin
    if to_char(sunday, 'd') = 1 then
      diff := 1;
    end if;
    if to_char(monday, 'd') = 1 then
      diff := 0;
    end if;
    return to_char(FPdtDate, 'd') - diff;
  end;

  procedure InsertReasonCodeDialogs(p_reasoncode_id      in reasoncode.reasoncode_id%type,
                                    rc_garmentreason     in reasoncode.garmentreason%type,
                                    rc_linenreason       in reasoncode.linenreason%type,
                                    rc_orpackreason      in reasoncode.orpackreason%type,
                                    rc_residentialreason in reasoncode.residentialreason%type,
                                    systemUserID         in systemuser.systemuser_id%type) is

  begin

    if (rc_garmentreason = 'Y') then
      insert into reasoncodedialogs
        (reasoncode_id, dialog_id, selectable, systemuser_id, timestamp)
        select p_reasoncode_id, d.dialog_id, 'Y', systemUserID, sysdate
          from dialogs d
         where d.code in ('DeliveryVariations',
                          'GarmentDispenser',
                          'RagInBatch',
                          'RagItemsFromStock',
                          'ReceiveItemsFromPO',
                          'ReceiveItemsInStockNoPO',
                          'ReplacementRenewal',
                          'StockCorrectionNonUnique',
                          'StockCorrectionUnique',
                          'Wearer',
                          'WorkOrderApproval',
                          'WorkOrder',
                          'ReturnToStock',
                          'MoveStock',
                          'MoveStockWithinStockroom',
                          'IssueGarmentsDirect',
                          'IssueGarmentsFromStock',
                          'CorrectionTicket',
                          'TreatmentBatchControl',
                          'ReceiveItemsFromSDOPush',
                          'UniqueItem',
                          'SalesOrder',
                          'RagPoolMultiRead',
                          'BundleSortScan',
                          'CheckInItemsFromPO',
                          'CorrectItemsCheckedInFromPO',
                          'MakeUniqueItemsCheckedInFromPO',
                          'DeliveryNote',
                          'ReturnToStockOrRagInBatch',
                          'MaintainGarmentCharges',
                          'CreateCleanroomBatch',
                          'MakeUniqueCustomerOwnedItems')
           and not exists (select 1
                  from reasoncodedialogs rcd
                 where rcd.reasoncode_id = p_reasoncode_id
                   and rcd.dialog_id = d.dialog_id);
    end if;

    if (rc_linenreason = 'Y') then
      insert into reasoncodedialogs
        (reasoncode_id, dialog_id, selectable, systemuser_id, timestamp)
        select p_reasoncode_id, d.dialog_id, 'Y', systemUserID, sysdate
          from dialogs d
         where d.code in ('DeliveryVariations',
                          'RagInBatch',
                          'RagItemsFromStock',
                          'ReceiveItemsFromPO',
                          'ReceiveItemsInStockNoPO',
                          'ReplacementRenewal',
                          'StockCorrectionNonUnique',
                          'StockCorrectionUnique',
                          'WorkOrderApproval',
                          'WorkOrder',
                          'ReturnToStock',
                          'ReceiveItemsFromDismountingOrder',
                          'MoveStock',
                          'MoveStockWithinStockroom',
                          'StandardDelivery',
                          'CorrectionTicket',
                          'TreatmentBatchControl',
                          'ReceiveItemsFromSDOPush',
                          'UniqueItem',
                          'SalesOrder',
                          'RagPoolMultiRead',
                          'BundleSortScan',
                          'CheckInItemsFromPO',
                          'CorrectItemsCheckedInFromPO',
                          'MakeUniqueItemsCheckedInFromPO',
                          'DeliveryNote',
                          'ReturnToStockOrRagInBatch')
           and not exists (select 1
                  from reasoncodedialogs rcd
                 where rcd.reasoncode_id = p_reasoncode_id
                   and rcd.dialog_id = d.dialog_id);

    end if;

    if (rc_orpackreason = 'Y') then
      insert into reasoncodedialogs
        (reasoncode_id, dialog_id, selectable, systemuser_id, timestamp)
        select p_reasoncode_id, d.dialog_id, 'Y', systemUserID, sysdate
          from dialogs d
         where d.code in ('DeliveryVariations',
                          'RagInBatch',
                          'RagItemsFromStock',
                          'ReceiveItemsInStockNoPO',
                          'StockCorrectionUnique',
                          'WorkOrderApproval',
                          'WorkOrder',
                          'ReturnToStock',
                          'MoveStock',
                          'MoveStockWithinStockroom',
                          'ConfirmSterilization',
                          'SterilizationRunStatusControl',
                          'ORPackStatusControl',
                          'CorrectionTicket',
                          'UniqueItem',
                          'CleanroomBatchStatusControl',
                          'CleanroomBatch',
                          'DeliveryNote',
                          'ReturnToStockOrRagInBatch')
           and not exists (select 1
                  from reasoncodedialogs rcd
                 where rcd.reasoncode_id = p_reasoncode_id
                   and rcd.dialog_id = d.dialog_id);

    end if;

    if (rc_residentialreason = 'Y') then
      insert into reasoncodedialogs
        (reasoncode_id, dialog_id, selectable, systemuser_id, timestamp)
        select p_reasoncode_id, d.dialog_id, 'Y', systemUserID, sysdate
          from dialogs d
         where d.code in ('Client')
           and not exists (select 1
                  from reasoncodedialogs rcd
                 where rcd.reasoncode_id = p_reasoncode_id
                   and rcd.dialog_id = d.dialog_id);

    end if;

  end;

  procedure InsertRagReasonCodeDialogs(p_ragreason_id in ragreason.ragreason_id%type,
                                       systemUserID   in systemuser.systemuser_id%type) is
  begin

    insert into ragreasondialogs
      (ragreason_id, dialog_id, selectable, systemuser_id, timestamp)
      select p_ragreason_id, d.dialog_id, 'Y', systemUserID, sysdate
        from dialogs d
       where d.code in ('RagItemsFromStock',
                        'ReturnCreditItems',
                        'GarmentDispenser',
                        'ReturnToStock',
                        'StockCorrectionUnique',
                        'RagInBatch',
                        'RagPoolMultiRead',
                        'IssueSalesItems',
                        'RagPoolMultiRead',
                        'ReturnToStockOrRagInBatch',
                        'ReasonCode')
         and not exists (select 1
                from ragreasondialogs rcd
               where rcd.ragreason_id = p_ragreason_id
                 and rcd.dialog_id = d.dialog_id);
  end;

end PACK_UTILITIES;
/
create or replace package pack_virtuallaundry is

  /*******************************************************************************\
  *  -- Author  : PVD                                                             *
  *  -- Created : 30-09-2013                                                      *
  *  -- Purpose : Export the data from ABSsolute to Virtual Laundry               *
  *  -- Version : 6-11-2013 Export Sales Area instead of Marketsegment for VREL   *
  \*******************************************************************************/

  ---Internal function!
  function f_getvlturnovercolumn(fp_customerid in customer.customer_id%type,
                                 fp_startdate  in invoiceheader.startdate%type,
                                 fp_enddate    in invoiceheader.enddate%type,
                                 fp_legacycode in turnovergroup.legacycode%type) return number;

  ---External procedures that can be called for export to VL
  procedure exportvlmarketsegment(fp_plantcode in plant.code%type);
  procedure exportvlproduct(fp_plantcode in plant.code%type);
  procedure exportvlweight(fp_plantcode        in plant.code%type,
                           fp_firstdayofperiod in date,
                           fp_lastdayofperiod  in date);
  procedure exportvldelivered(fp_plantcode        in plant.code%type,
                              fp_firstdayofperiod in date,
                              fp_lastdayofperiod  in date);
  procedure exportvlcustomer(fp_plantcode        in plant.code%type,
                             fp_firstdayofperiod in date,
                             fp_lastdayofperiod  in date);
  procedure exportvlweightprocessedweek(fp_plantcode        in plant.code%type,
                                        fp_firstdayofperiod in date,
                                        fp_lastdayofperiod  in date);
  procedure exportvlpiecesdeliveredweek(fp_plantcode        in plant.code%type,
                                        fp_firstdayofperiod in date,
                                        fp_lastdayofperiod  in date);
  procedure exportvlall(fp_plantcode        in plant.code%type,
                        fp_firstdayofperiod in date,
                        fp_lastdayofperiod  in date);
end pack_virtuallaundry;

/
create or replace package body pack_virtuallaundry is
  ----------------------------------------------------------------------------
  --internal variables:
  gv_user_exception exception;
  gv_currentdate        date;
  gv_message            abslog.message%type := null;
  gv_dir                systemsetting.value%type;
  gv_vlexpuselegacycode systemsetting.value%type;
  gv_separator          varchar2(1) := ';';
  gv_systemuserid       systemuser.systemuser_id%type := 1;
  gv_plantid            plant.plant_id%type;
  gv_languageid         languages.language_id%type;
  gv_counter            number := 0;
  ----------------------------------------------------------------------------
  --internal functions/procedures;
  procedure write_log(fp_text     in abslog.message%type,
                      fp_priority in abslog.priority%type default 1) is
  begin
    --write_log
    abslogwrite.abslog_write(5, 'PACK_VIRTUALLAUNDRY', gv_plantid, fp_priority, fp_text,
                             gv_systemuserid);
  end write_log;

  function open_file(fp_filename in varchar2) return utl_file.file_type is
    lp_filehandle utl_file.file_type;
  begin
    --open file
    gv_message    := 'Open file; Directory: ' || gv_dir || '  Filename: ' || fp_filename;
    lp_filehandle := utl_file.fopen(gv_dir, fp_filename, 'a', 32767);
    return lp_filehandle;
  exception
    when utl_file.invalid_path then
      gv_message := gv_message || ' Invalid Path';
      raise;
    when utl_file.invalid_mode then
      gv_message := gv_message || ' Invalid Mode';
      raise;
    when utl_file.invalid_operation then
      gv_message := gv_message || ' Invalid Operation, check if directory exists';
      raise;
    when utl_file.invalid_filehandle then
      gv_message := gv_message || ' Invalid FileHandle';
      raise;
    when utl_file.write_error then
      gv_message := gv_message || ' Write Error';
      raise;
    when utl_file.read_error then
      gv_message := gv_message || ' Read Error';
      raise;
    when utl_file.internal_error then
      gv_message := gv_message || ' Internal Error';
      raise;
    when others then
      raise;
  end open_file;

  procedure close_file(fp_filehandle in out utl_file.file_type) is
  begin
    --close file
    gv_message := 'close file';
    if utl_file.is_open(fp_filehandle) = true then
      utl_file.fclose(fp_filehandle);
    end if;
  end close_file;

  function initialize(fp_plantcode in plant.code%type, fp_ss_partoffilename in varchar2)
    return varchar2 is
    lv_filenamepart systemsetting.value%type;
  begin
    --Initialization
    gv_message     := 'initialize current date ';
    gv_currentdate := trunc(sysdate);
    --get plant id
    gv_message := 'Get plant id for code ' || nvl(fp_plantcode, 'NULL');
    select pt.plant_id, pt.language_id
    into   gv_plantid, gv_languageid
    from   plant pt
    where  pt.code = fp_plantcode;
    --Get systemsetting EXPDIRVL
    gv_message := 'Get systemsetting EXPDIRVL for plant code ' || fp_plantcode;
    select coalesce(min(ss.value), min(ss.factorydefault))
    into   gv_dir
    from   systemsetting ss
    where  ss.name = 'EXPDIRVL'
    and    ss.plant_id = gv_plantid;
    if gv_dir is null then
      begin
        gv_message := 'Systemsetting EXPDIRVL for plant code ' || fp_plantcode || ' not found!';
        raise gv_user_exception;
      end;
    end if;
    --Get system setting VLEXPUSELEGACYCODE
    gv_message := 'Get systemsetting VLEXPUSELEGACYCODE for plant code ' || fp_plantcode;
    select coalesce(min(ss.value), min(ss.factorydefault), 'N')
    into   gv_vlexpuselegacycode
    from   systemsetting ss
    where  ss.name = 'VLEXPUSELEGACYCODE'
    and    ss.plant_id = gv_plantid;
    --Get systemsetting EXPDIRVL
    gv_message := 'Get systemsetting ' || fp_ss_partoffilename || ' for plant code ' ||
                  fp_plantcode;
    select coalesce(min(ss.value), min(ss.factorydefault), replace(fp_ss_partoffilename, 'FILENAME'))
    into   lv_filenamepart
    from   systemsetting ss
    where  ss.name = fp_ss_partoffilename
    and    ss.plant_id = gv_plantid;
    return fp_plantcode || '_' || lv_filenamepart || '_' || to_char(gv_currentdate, 'YYYYMMDD') || '.csv';
  end initialize;

  procedure write_line(fp_filehandle in utl_file.file_type, fp_text in varchar2) is
  begin
    --write_line
    utl_file.put_line(fp_filehandle, fp_text);
  end write_line;

  function f_getvlturnovercolumn(fp_customerid in customer.customer_id%type,
                                 fp_startdate  in invoiceheader.startdate%type,
                                 fp_enddate    in invoiceheader.enddate%type,
                                 fp_legacycode in turnovergroup.legacycode%type) return number is
    lv_turnoveramount number;
  begin
    --get turnoveramount from artransactions
    gv_message := 'pack_virtuallaundry.f_getvlturnovercolumn';
    select nvl(sum(ard.amount), 0)
    into   lv_turnoveramount
    from   artransactiondetail ard
    join   artransaction ar
    on     ar.artransaction_id = ard.artransaction_id
    join   invoiceheader ih
    on     ih.invoiceheader_id = ar.invoiceheader_id
    join   turnovergroup tg
    on     tg.turnovergroup_id = ard.turnovergroup_id
    where  tg.legacycode = fp_legacycode
    and    ih.startdate >= fp_startdate
    and    ih.enddate <= fp_enddate
    and    ih.deltocustomer_link_id = fp_customerid;
    return lv_turnoveramount;
  exception
    when no_data_found then
      return 0;
  end f_getvlturnovercolumn;

  ----------------------------------------------------------------------------
  --External procedures;
  procedure exportvlmarketsegment(fp_plantcode in plant.code%type) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select ms.code, msd.description
                from   marketsegment ms
                join   marketsegment_desc msd
                on     (msd.marketsegment_id = ms.marketsegment_id and
                       msd.language_id = gv_languageid)
                order  by ms.code) loop
        begin
          write_line(lv_filehandle, x.code || gv_separator || x.description);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlmarketsegment
    write_log('EXPORTVLMARKETSEGMENT; Processing started ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLMARKETSEGMENT for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMEMARKETSEGMNT');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLMARKETSEGMENT; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLMARKETSEGMENT; Number recors exported ' || gv_counter);
    write_log('EXPORTVLMARKETSEGMENT; Processing ended ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLMARKETSEGMENT; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLMARKETSEGMENT; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLMARKETSEGMENT; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLMARKETSEGMENT; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLMARKETSEGMENT; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLMARKETSEGMENT; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvlmarketsegment;

  procedure exportvlproduct(fp_plantcode in plant.code%type) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(p.legacyproductcode), p.code) || f.code
                          else
                           p.code || f.code
                        end code, '0' customernumber,
                       max(pd.description) || ' ' || f.code description,
                       max(p.theoreticalweight) weight
                from   productfinishingmethod pf
                join   product p
                on     p.product_id = pf.product_id
                join   product_desc pd
                on     (pd.product_id = p.product_id and pd.language_id = gv_languageid)
                join   finishingmethod f
                on     f.finishingmethod_id = pf.finishingmethod_id
                group  by p.code, f.code
                union all
                select case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(p.legacyproductcode), p.code) || f.code
                          else
                           p.code || f.code
                        end code,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(c.legacycustomernumber), to_char(c.customernumber))
                          else
                           to_char(c.customernumber)
                        end customernumber, max(pd.description) || ' ' || f.code description,
                       max(p.theoreticalweight) weight
                from   productlistpercustomer l
                join   customer c
                on     c.customer_id = l.customer_id
                join   product p
                on     p.product_id = l.product_id
                join   finishingmethod f
                on     f.finishingmethod_id = l.finishingmethod_id
                join   product_desc pd
                on     (pd.product_id = p.product_id and pd.language_id = gv_languageid)
                where  exists (select 1
                        from   productgroup g, customeractivities ca
                        join   businessunit bu
                        on     bu.businessunit_id = ca.processbusinessunit_id
                        where  g.productgroup_id = p.productgroup_id
                        and    ca.customer_id = l.customer_id
                        and    ca.activity_id = g.activity_id
                        and    bu.plant_id = gv_plantid)
                group  by c.customernumber, p.code, f.code
                order  by 1, 2) loop
        begin
          write_line(lv_filehandle,
                     x.code || gv_separator || x.customernumber || gv_separator || x.description ||
                      gv_separator || x.weight);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlproduct
    write_log('EXPORTVLPRODUCT; Processing started ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLPRODUCT for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMEPRODUCT');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLPRODUCT; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLPRODUCT; Number recors exported ' || gv_counter);
    write_log('EXPORTVLPRODUCT; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLPRODUCT; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLPRODUCT; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLPRODUCT; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLPRODUCT; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLPRODUCT; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLPRODUCT; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvlproduct;

  procedure exportvlweight(fp_plantcode        in plant.code%type,
                           fp_firstdayofperiod in date,
                           fp_lastdayofperiod  in date) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(c.legacycustomernumber), to_char(c.customernumber))
                          else
                           to_char(c.customernumber)
                        end customernumber,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(wc.legacyweighingcategorycode), wc.code)
                          else
                           wc.code
                        end code,
                       (select nvl(sum(wtl.grossweight - wtl.tareweight), 0)
                         from   weighingticket wt
                         join   weighingticketline wtl
                         on     wtl.weighingticket_id = wt.weighingticket_id
                         where  wt.customer_id = wcc.customer_id
                         and    wtl.weighingcategory_id = wcc.weighingcategory_id
                         and    wt.soilticket = 'Y'
                         and    wt.weighingdate between fp_firstdayofperiod and fp_lastdayofperiod) soil,
                       (select nvl(sum(wtl.grossweight - wtl.tareweight), 0)
                         from   weighingticket wt
                         join   weighingticketline wtl
                         on     wtl.weighingticket_id = wt.weighingticket_id
                         where  wt.customer_id = wcc.customer_id
                         and    wtl.weighingcategory_id = wcc.weighingcategory_id
                         and    wt.soilticket = 'N'
                         and    wt.weighingdate between fp_firstdayofperiod and fp_lastdayofperiod) +
                        (select nvl(sum(pnc.grossweight - pnc.tareweight), 0)
                         from   packingnote pn
                         join   packingnotecontainer pnc
                         on     pn.packingnote_id = pnc.packingnote_id
                         join   deliverypoint dp
                         on     dp.deliverypoint_id = pn.deliverypoint_id
                         where  dp.customer_id = wcc.customer_id
                         and    pn.status_id = (select s.status_id
                                                from   status s
                                                where  s.statustype = 'PN'
                                                and    s.code = '30')
                         and    pnc.weighingcategory_id = wcc.weighingcategory_id
                         and    pn.deliverydate between fp_firstdayofperiod and fp_lastdayofperiod) clean,
                       case
                         when max(wcc.invoicemethod) = 1 then
                          0
                         when max(wcc.invoicemethod) = 2 then
                          max(pack_price.weight_price(c.customer_id, wcc.weighingcategory_id, 'Y',
                                                      gv_currentdate))
                         else
                          max(pack_price.weight_price(c.customer_id, wcc.weighingcategory_id, 'N',
                                                      gv_currentdate))
                       end price
                from   weighingcategpercustomer wcc
                join   customer c
                on     c.customer_id = wcc.customer_id
                join   weighingcategory wc
                on     wc.weighingcategory_id = wcc.weighingcategory_id
                where  exists (select 1
                        from   customeractivities ca
                        join   businessunit bu
                        on     bu.businessunit_id = ca.processbusinessunit_id
                        where  ca.customer_id = wcc.customer_id
                        and    ca.activity_id = wc.activity_id
                        and    bu.plant_id = gv_plantid)
                group  by c.customernumber, wc.code, wcc.customer_id, wcc.weighingcategory_id
                order  by c.customernumber, wc.code) loop
        begin
          write_line(lv_filehandle,
                     x.customernumber || gv_separator || x.code || gv_separator || x.soil ||
                      gv_separator || x.clean || gv_separator || x.price);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlweight
    write_log('EXPORTVLWEIGHT; Processing started ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLWEIGHT for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMEWEIGHT');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLWEIGHT; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLWEIGHT; Number recors exported ' || gv_counter);
    write_log('EXPORTVLWEIGHT; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLWEIGHT; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLWEIGHT; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLWEIGHT; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLWEIGHT; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLWEIGHT; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLWEIGHT; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvlweight;

  procedure exportvldelivered(fp_plantcode        in plant.code%type,
                              fp_firstdayofperiod in date,
                              fp_lastdayofperiod  in date) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(c.legacycustomernumber), to_char(c.customernumber))
                          else
                           to_char(c.customernumber)
                        end customernumber,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(p.legacyproductcode), p.code) || f.code
                          else
                           p.code || f.code
                        end code, nvl(sum(pnl.deliveredamount), 0) qty_delivered,
                       max(case p.typeofmerchandise
                              when 3 then
                               pack_price.sales_price(c.customer_id, p.product_id,
                                                      pnl.sizedefinition_id, pn.deliverydate)
                              else
                               pack_price.wash_price(c.customer_id, p.product_id, pnl.sizedefinition_id,
                                                     pnl.finishingmethod_id, pn.deliverydate)
                            end) price,
                       max(pack_price.weight_price(c.customer_id, p.weighingcategory_id, 'N',
                                                    gv_currentdate)) additional_charge
                from   packingnote pn
                join   packingnoteline pnl
                on     pnl.packingnote_id = pn.packingnote_id
                join   deliverypoint dp
                on     dp.deliverypoint_id = pn.deliverypoint_id
                join   customer c
                on     c.customer_id = dp.customer_id
                join   product p
                on     p.product_id = pnl.product_id
                join   finishingmethod f
                on     f.finishingmethod_id = pnl.finishingmethod_id
                join   businessunit bu
                on     bu.businessunit_id = pn.processbusinessunit_id
                where  pn.status_id = (select s.status_id
                                       from   status s
                                       where  s.statustype = 'PN'
                                       and    s.code = '30')
                and    pn.deliverydate between fp_firstdayofperiod and fp_lastdayofperiod
                and    bu.plant_id = gv_plantid
                group  by c.customernumber, p.code, f.code
                union all
                select case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(c.legacycustomernumber), to_char(c.customernumber))
                          else
                           to_char(c.customernumber)
                        end customernumber,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(p.legacyproductcode), p.code) || f.code
                          else
                           p.code || f.code
                        end code, nvl(sum(cnl.qtyscannedout + cnl.qtycountedout), 0) qty_delivered,
                       max(case p.typeofmerchandise
                              when 3 then
                               pack_price.sales_price(c.customer_id, p.product_id,
                                                      cnl.sizedefinition_link_id, cn.deliverydate)
                              else
                               pack_price.wash_price(c.customer_id, p.product_id,
                                                     cnl.sizedefinition_link_id, cnl.finishingmethod_id,
                                                     cn.deliverydate)
                            end) price,
                       max(pack_price.weight_price(c.customer_id, p.weighingcategory_id, 'N',
                                                    gv_currentdate)) additional_charge
                from   clientdeliverynote cn
                join   clientdeliverynoteline cnl
                on     cnl.clientdeliverinote_id = cn.clientdeliverynote_id
                join   customer c
                on     c.customer_id = cn.customer_link_id
                join   product p
                on     p.product_id = cnl.product_link_id
                join   finishingmethod f
                on     f.finishingmethod_id = cnl.finishingmethod_id
                join   businessunit bu
                on     bu.businessunit_id = cn.processbusinessunit_id
                where  cn.status = 0
                and    cn.deliverydate between fp_firstdayofperiod and fp_lastdayofperiod
                and    bu.plant_id = gv_plantid
                and    cn.closingdate is not null
                group  by c.customernumber, p.code, f.code
                order  by 1, 2) loop
        begin
          write_line(lv_filehandle,
                     x.customernumber || gv_separator || x.code || gv_separator || x.qty_delivered ||
                      gv_separator || x.price || gv_separator || x.additional_charge);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlweight
    write_log('EXPORTVLDELIVERED; Processing started ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLDELIVERED for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMEQUANTITY');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLDELIVERED; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLDELIVERED; Number recors exported ' || gv_counter);
    write_log('EXPORTVLDELIVERED; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLDELIVERED; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLDELIVERED; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLDELIVERED; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLDELIVERED; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLDELIVERED; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLDELIVERED; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvldelivered;

  procedure exportvlcustomer(fp_plantcode        in plant.code%type,
                             fp_firstdayofperiod in date,
                             fp_lastdayofperiod  in date) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(cu.legacycustomernumber), to_char(cu.customernumber))
                          else
                           to_char(cu.customernumber)
                        end customernumber, max(cu.name) name, max(x.firstweek) firstweek,
                       max(x.lastweek) lastweek, nvl(sum(x.turnovertotal), 0) turnovertotal,
                       sum(x.vlturnover_grp1) vlturnover_grp1, sum(x.vlturnover_grp2) vlturnover_grp2,
                       sum(x.vlturnover_grp3) vlturnover_grp3, sum(x.vlturnover_grp4) vlturnover_grp4,
                       sum(x.vlturnover_grp5) vlturnover_grp5, sum(x.vlturnover_grp6) vlturnover_grp6,
                       sum(x.vlturnover_grp7) vlturnover_grp7, sum(x.vlturnover_grp8) vlturnover_grp8,
                       sum(x.vlturnover_grp9) vlturnover_grp9, max(x.soilweight) soilweight,
                       max(x.cleanweight) cleanweight, max(ms.code) salesarea
                from   customer cu
                join   salesarea ms
                on     cu.salesarea_id = ms.salesarea_id
                join   (select ih.deltocustomer_link_id customer_id,
                              to_char(fp_firstdayofperiod, 'IYYYIW') firstweek,
                              to_char(fp_lastdayofperiod, 'IYYYIW') lastweek,
                              sum(ard.amount) turnovertotal,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 1) vlturnover_grp1,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 2) vlturnover_grp2,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 3) vlturnover_grp3,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 4) vlturnover_grp4,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 5) vlturnover_grp5,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 6) vlturnover_grp6,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 7) vlturnover_grp7,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 8) vlturnover_grp8,
                              pack_virtuallaundry.f_getvlturnovercolumn(ih.deltocustomer_link_id,
                                                                         ih.startdate, ih.enddate, 9) vlturnover_grp9,
                              sum((select nvl(sum(wtl.grossweight - wtl.tareweight), 0)
                                   from   weighingticket wt
                                   join   weighingticketline wtl
                                   on     wtl.weighingticket_id = wt.weighingticket_id
                                   where  wt.soilticket = 'Y'
                                   and    wtl.invoiceheader_id = ih.invoiceheader_id)) soilweight,
                              sum(((select nvl(sum(wtl.grossweight - wtl.tareweight), 0)
                                     from   weighingticket wt
                                     join   weighingticketline wtl
                                     on     wtl.weighingticket_id = wt.weighingticket_id
                                     where  wt.soilticket = 'N'
                                     and    wtl.invoiceheader_id = ih.invoiceheader_id) +
                                   (select nvl(sum(pnc.grossweight - pnc.tareweight), 0)
                                     from   packingnote pn
                                     join   packingnotecontainer pnc
                                     on     pnc.packingnote_id = pn.packingnote_id
                                     where  pnc.invoiceheader_id = ih.invoiceheader_id))) cleanweight
                       from   artransactiondetail ard
                       join   artransaction ar
                       on     ar.artransaction_id = ard.artransaction_id
                       join   invoiceheader ih
                       on     ih.invoiceheader_id = ar.invoiceheader_id
                       join   businessunit bu
                       on     bu.businessunit_id = ard.businessunit_id
                       where  ih.startdate >= fp_firstdayofperiod
                       and    ih.enddate <= fp_lastdayofperiod
                       and    bu.plant_id = gv_plantid
                       group  by ih.deltocustomer_link_id, ih.startdate, ih.enddate) x
                on     x.customer_id = cu.customer_id
                group  by cu.customernumber
                order  by 1) loop
        begin
          write_line(lv_filehandle,
                     x.customernumber || gv_separator || x.name || gv_separator || x.firstweek ||
                      gv_separator || x.lastweek || gv_separator || x.turnovertotal || gv_separator ||
                      x.vlturnover_grp1 || gv_separator || x.vlturnover_grp2 || gv_separator ||
                      x.vlturnover_grp3 || gv_separator || x.vlturnover_grp4 || gv_separator ||
                      x.vlturnover_grp5 || gv_separator || x.vlturnover_grp6 || gv_separator ||
                      x.vlturnover_grp7 || gv_separator || x.vlturnover_grp8 || gv_separator ||
                      x.vlturnover_grp9 || gv_separator || x.soilweight || gv_separator ||
                      x.cleanweight || gv_separator || x.salesarea);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlweight
    write_log('EXPORTVLCUSTOMER; Processing started ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLCUSTOMER for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMECUSTOMER');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLCUSTOMER; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLCUSTOMER; Number recors exported ' || gv_counter);
    write_log('EXPORTVLCUSTOMER; Processing ended ' || to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLCUSTOMER; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLCUSTOMER; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLCUSTOMER; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLCUSTOMER; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLCUSTOMER; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLCUSTOMER; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvlcustomer;

  procedure exportvlweightprocessedweek(fp_plantcode        in plant.code%type,
                                        fp_firstdayofperiod in date,
                                        fp_lastdayofperiod  in date) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select to_char(ih.enddate, 'IYYYIW') yearwk, ms.code marketsegmentcode,
                       sum((select nvl(sum(wtl.grossweight - wtl.tareweight), 0)
                            from   weighingticket wt
                            join   weighingticketline wtl
                            on     wtl.weighingticket_id = wt.weighingticket_id
                            where  wt.soilticket = 'Y'
                            and    wtl.invoiceheader_id = ih.invoiceheader_id)) soilweight,
                       sum(((select nvl(sum(wtl.grossweight - wtl.tareweight), 0)
                              from   weighingticket wt
                              join   weighingticketline wtl
                              on     wtl.weighingticket_id = wt.weighingticket_id
                              where  wtl.invoiceheader_id = ih.invoiceheader_id
                              and    wt.soilticket = 'N') +
                            (select nvl(sum(pnc.grossweight - pnc.tareweight), 0)
                              from   packingnote pn
                              join   packingnotecontainer pnc
                              on     pnc.packingnote_id = pn.packingnote_id
                              where  pnc.invoiceheader_id = ih.invoiceheader_id))) cleanweight,
                       sum(ard.amount) turnovertotal
                from   artransactiondetail ard
                join   artransaction ar
                on     ar.artransaction_id = ard.artransaction_id
                join   invoiceheader ih
                on     ih.invoiceheader_id = ar.invoiceheader_id
                join   customer cu
                on     cu.customer_id = ih.deltocustomer_link_id
                join   marketsegment ms
                on     ms.marketsegment_id = cu.marketsegment_id
                join   businessunit bu
                on     bu.businessunit_id = ard.businessunit_id
                where  bu.plant_id = gv_plantid
                and    ih.startdate >= fp_firstdayofperiod
                and    ih.enddate <= fp_lastdayofperiod
                group  by ms.code, to_char(ih.enddate, 'IYYYIW')
                order  by 1, 2) loop
        begin
          write_line(lv_filehandle,
                     x.yearwk || gv_separator || x.marketsegmentcode || gv_separator ||
                      x.soilweight || gv_separator || x.cleanweight || gv_separator ||
                      x.turnovertotal);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlweight
    write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Processing started ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLWEIGHTPROCESSEDWEEK for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMEWTWP');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLWEIGHTPROCESSEDWEEK; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Number recors exported ' || gv_counter);
    write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Processing ended ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLWEIGHTPROCESSEDWEEK; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvlweightprocessedweek;

  procedure exportvlpiecesdeliveredweek(fp_plantcode        in plant.code%type,
                                        fp_firstdayofperiod in date,
                                        fp_lastdayofperiod  in date) is
    lv_filename   varchar2(1000);
    lv_filehandle utl_file.file_type;
  
    procedure export_data is
    begin
      --export_data
      gv_message := 'export_data';
      for x in (select to_char(pn.year) || lpad(to_char(pn.week), 2, '0') yearweek,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(c.legacycustomernumber), to_char(c.customernumber))
                          else
                           to_char(c.customernumber)
                        end customernumber,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(p.legacyproductcode), p.code) || f.code
                          else
                           p.code || f.code
                        end code, sum(pnl.deliveredamount) qtydelivered
                from   packingnote pn
                join   packingnoteline pnl
                on     pnl.packingnote_id = pn.packingnote_id
                join   deliverypoint dp
                on     dp.deliverypoint_id = pn.deliverypoint_id
                join   customer c
                on     c.customer_id = dp.customer_id
                join   product p
                on     p.product_id = pnl.product_id
                join   finishingmethod f
                on     f.finishingmethod_id = pnl.finishingmethod_id
                join   businessunit bu
                on     bu.businessunit_id = pn.processbusinessunit_id
                where  pn.status_id = (select s.status_id
                                       from   status s
                                       where  s.statustype = 'PN'
                                       and    s.code = '30')
                and    pn.deliverydate between fp_firstdayofperiod and fp_lastdayofperiod
                and    bu.plant_id = gv_plantid
                group  by c.customernumber, p.code, f.code,
                          to_char(pn.year) || lpad(to_char(pn.week), 2, '0')
                union all
                select to_char(cn.deliverydate, 'IYYYIW') yearweek,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(c.legacycustomernumber), to_char(c.customernumber))
                          else
                           to_char(c.customernumber)
                        end customernumber,
                       case gv_vlexpuselegacycode
                          when 'Y' then
                           nvl(max(p.legacyproductcode), p.code) || f.code
                          else
                           p.code || f.code
                        end code, sum(cnl.qtyscannedout + cnl.qtycountedout) qtydelivered
                from   clientdeliverynote cn
                join   clientdeliverynoteline cnl
                on     cnl.clientdeliverinote_id = cn.clientdeliverynote_id
                join   customer c
                on     c.customer_id = cn.customer_link_id
                join   product p
                on     p.product_id = cnl.product_link_id
                join   finishingmethod f
                on     f.finishingmethod_id = cnl.finishingmethod_id
                join   businessunit bu
                on     bu.businessunit_id = cn.processbusinessunit_id
                where  cn.status = 0
                and    cn.deliverydate between fp_firstdayofperiod and fp_lastdayofperiod
                and    bu.plant_id = gv_plantid
                and    cn.closingdate is not null
                group  by c.customernumber, p.code, f.code, to_char(cn.deliverydate, 'IYYYIW')
                order  by 1, 2, 3) loop
        begin
          write_line(lv_filehandle,
                     x.customernumber || gv_separator || x.code || gv_separator || x.qtydelivered);
          gv_counter := gv_counter + 1;
        end;
      end loop; --x
    end export_data;
  begin
    --exportvlweight
    write_log('EXPORTVLPIECESDELIVEREDWEEK; Processing started ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
    gv_message    := 'EXPORTVLPIECESDELIVEREDWEEK for plant code ' || fp_plantcode;
    lv_filename   := initialize(fp_plantcode, 'VLEXPFILENAMEPIECESWK');
    lv_filehandle := open_file(lv_filename);
    write_log('EXPORTVLPIECESDELIVEREDWEEK; File Name ' || lv_filename || ' Directory ' || gv_dir);
    --export data
    export_data;
    close_file(lv_filehandle);
    write_log('EXPORTVLPIECESDELIVEREDWEEK; Number recors exported ' || gv_counter);
    write_log('EXPORTVLPIECESDELIVEREDWEEK; Processing ended ' ||
              to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
  exception
    --exception handling
    when gv_user_exception then
      begin
        rollback;
        write_log('EXPORTVLPIECESDELIVEREDWEEK; Error occurred;' || gv_message, 3);
        write_log('EXPORTVLPIECESDELIVEREDWEEK; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when no_data_found then
      begin
        rollback;
        write_log('EXPORTVLPIECESDELIVEREDWEEK; Error No Data Found ' || gv_message, 3);
        write_log('EXPORTVLPIECESDELIVEREDWEEK; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
    when others then
      begin
        rollback;
        write_log('EXPORTVLPIECESDELIVEREDWEEK; Error ' || sqlerrm || ' ' || gv_message, 3);
        write_log('EXPORTVLPIECESDELIVEREDWEEK; Processing ended ' ||
                  to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'));
        close_file(lv_filehandle);
      end;
  end exportvlpiecesdeliveredweek;

  procedure exportvlall(fp_plantcode        in plant.code%type,
                        fp_firstdayofperiod in date,
                        fp_lastdayofperiod  in date) is
  begin
    --exportvlall
    gv_message := 'exportvlall';
    exportvlmarketsegment(fp_plantcode);
    exportvlproduct(fp_plantcode);
    exportvlweight(fp_plantcode, fp_firstdayofperiod, fp_lastdayofperiod);
    exportvldelivered(fp_plantcode, fp_firstdayofperiod, fp_lastdayofperiod);
    exportvlcustomer(fp_plantcode, fp_firstdayofperiod, fp_lastdayofperiod);
    exportvlweightprocessedweek(fp_plantcode, fp_firstdayofperiod, fp_lastdayofperiod);
    exportvlpiecesdeliveredweek(fp_plantcode, fp_firstdayofperiod, fp_lastdayofperiod);
  exception
    when others then
      begin
        write_log('exportvlall; Error ' || sqlerrm || ' ' || gv_message, 3);
      end;
  end exportvlall;
end pack_virtuallaundry;

/
create or replace PACKAGE PACK_WEARER is

procedure CFbStoreOrCreate (
        FPnWEARER_ID                              in out WEARER.WEARER_ID%type,
        FPnCUSTOMER_ID                            in out WEARER.CUSTOMER_ID%type,
        FPnWEARERNUMBER                           in out WEARER.WEARERNUMBER%type,
        FPsFULLNAME                               in out WEARER.FULLNAME%type,
        FPsSEARCHNAME                             in out WEARER.SEARCHNAME%type,
        FPsEMBLEMNAME                             in out WEARER.EMBLEMNAME%type,
        FPsCUSTOMEREMPLOYEENUMBER                 in out WEARER.CUSTOMEREMPLOYEENUMBER%type,
        FPsSEX                                    in out WEARER.SEX%type,
        FPsDUMMYFORPOOL                           in out WEARER.DUMMYFORPOOL%type,
        FPdtDATEACTIVE                            in out WEARER.DATEACTIVE%type,
        FPdtDATEINACTIVE                          in out WEARER.DATEINACTIVE%type,
        FPsREMARK                                 in out WEARER.REMARK%type,
        FPnFLAG_ID                                in out WEARER.FLAG_ID%type,
        FPdtFLAGSTARTDATE                         in out WEARER.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in out WEARER.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEARER.TIMESTAMP%type);

end PACK_WEARER;

/
create or replace PACKAGE BODY PACK_WEARER is

procedure CFbStoreOrCreate (
        FPnWEARER_ID                              in out WEARER.WEARER_ID%type,
        FPnCUSTOMER_ID                            in out WEARER.CUSTOMER_ID%type,
        FPnWEARERNUMBER                           in out WEARER.WEARERNUMBER%type,
        FPsFULLNAME                               in out WEARER.FULLNAME%type,
        FPsSEARCHNAME                             in out WEARER.SEARCHNAME%type,
        FPsEMBLEMNAME                             in out WEARER.EMBLEMNAME%type,
        FPsCUSTOMEREMPLOYEENUMBER                 in out WEARER.CUSTOMEREMPLOYEENUMBER%type,
        FPsSEX                                    in out WEARER.SEX%type,
        FPsDUMMYFORPOOL                           in out WEARER.DUMMYFORPOOL%type,
        FPdtDATEACTIVE                            in out WEARER.DATEACTIVE%type,
        FPdtDATEINACTIVE                          in out WEARER.DATEINACTIVE%type,
        FPsREMARK                                 in out WEARER.REMARK%type,
        FPnFLAG_ID                                in out WEARER.FLAG_ID%type,
        FPdtFLAGSTARTDATE                         in out WEARER.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in out WEARER.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEARER.TIMESTAMP%type
) is
begin
    insert into WEARER(
        WEARER_ID,
        CUSTOMER_ID,
        WEARERNUMBER,
        FULLNAME,
        SEARCHNAME,
        EMBLEMNAME,
        CUSTOMEREMPLOYEENUMBER,
        SEX,
        DUMMYFORPOOL,
        DATEACTIVE,
        DATEINACTIVE,
        REMARK,
        FLAG_ID,
        FLAGSTARTDATE,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        SEQ_WEARER.nextval,
        FPnCUSTOMER_ID,
        FPnWEARERNUMBER,
        FPsFULLNAME,
        FPsSEARCHNAME,
        FPsEMBLEMNAME,
        FPsCUSTOMEREMPLOYEENUMBER,
        FPsSEX,
        FPsDUMMYFORPOOL,
        FPdtDATEACTIVE,
        FPdtDATEINACTIVE,
        FPsREMARK,
        FPnFLAG_ID,
        FPdtFLAGSTARTDATE,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
    select SEQ_WEARER.currval into FPnWEARER_ID from dual;
exception when dup_val_on_index then
    update WEARER
    set
        CUSTOMER_ID = FPnCUSTOMER_ID,
        WEARERNUMBER = FPnWEARERNUMBER,
        FULLNAME = FPsFULLNAME,
        SEARCHNAME = FPsSEARCHNAME,
        EMBLEMNAME = FPsEMBLEMNAME,
        CUSTOMEREMPLOYEENUMBER = FPsCUSTOMEREMPLOYEENUMBER,
        SEX = FPsSEX,
        DUMMYFORPOOL = FPsDUMMYFORPOOL,
        DATEACTIVE = FPdtDATEACTIVE,
        DATEINACTIVE = FPdtDATEINACTIVE,
        REMARK = FPsREMARK,
        FLAG_ID = FPnFLAG_ID,
        FLAGSTARTDATE = FPdtFLAGSTARTDATE,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where WEARERNUMBER = FPnWEARERNUMBER and CUSTOMER_ID = FPnCUSTOMER_ID;

    select WEARER_ID into FPnWEARER_ID
    from WEARER
    where WEARERNUMBER = FPnWEARERNUMBER and CUSTOMER_ID = FPnCUSTOMER_ID;
end;

end PACK_WEARER;

/
create or replace PACKAGE PACK_WEAREREMPLOYMENT is

procedure CFbCreate (
        FPnWEAREREMPLOYMENT_ID                    in out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
        FPnWEARER_ID                              in     WEAREREMPLOYMENT.WEARER_ID%type,
        FPnSEQUENCENUMBER                         in     WEAREREMPLOYMENT.SEQUENCENUMBER%type,
        FPnDISTRIBUTIONPOINT_ID                   in     WEAREREMPLOYMENT.DISTRIBUTIONPOINT_ID%type,
        FPnWEARERFUNCTION_ID                      in     WEAREREMPLOYMENT.WEARERFUNCTION_ID%type,
        FPnFLAG_ID                                in     WEAREREMPLOYMENT.FLAG_ID%type,
        FPnDELIVERYPOINT_ID                       in     WEAREREMPLOYMENT.DELIVERYPOINT_ID%type,
        FPnLOCKER_ID                              in     WEAREREMPLOYMENT.LOCKER_ID%type,
        FPnGARMENTDISPENSER_ID                    in     WEAREREMPLOYMENT.GARMENTDISPENSER_ID%type,
        FPnDISPENSECREDIT                         in     WEAREREMPLOYMENT.DISPENSECREDIT%type,
        FPdtFLAGSTARTDATE                         in     WEAREREMPLOYMENT.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in     WEAREREMPLOYMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in     WEAREREMPLOYMENT.TIMESTAMP%type,
        FPsCARDNUMBER                             in     WEAREREMPLOYMENT.CARDNUMBER%type);

procedure CFbStore (
        FPnWEAREREMPLOYMENT_ID                    in out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
        FPnWEARER_ID                              in out WEAREREMPLOYMENT.WEARER_ID%type,
        FPnSEQUENCENUMBER                         in out WEAREREMPLOYMENT.SEQUENCENUMBER%type,
        FPnDISTRIBUTIONPOINT_ID                   in out WEAREREMPLOYMENT.DISTRIBUTIONPOINT_ID%type,
        FPnWEARERFUNCTION_ID                      in out WEAREREMPLOYMENT.WEARERFUNCTION_ID%type,
        FPnFLAG_ID                                in out WEAREREMPLOYMENT.FLAG_ID%type,
        FPnDELIVERYPOINT_ID                       in out WEAREREMPLOYMENT.DELIVERYPOINT_ID%type,
        FPnLOCKER_ID                              in out WEAREREMPLOYMENT.LOCKER_ID%type,
        FPnGARMENTDISPENSER_ID                    in out WEAREREMPLOYMENT.GARMENTDISPENSER_ID%type,
        FPnDISPENSECREDIT                         in out WEAREREMPLOYMENT.DISPENSECREDIT%type,
        FPdtFLAGSTARTDATE                         in out WEAREREMPLOYMENT.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in out WEAREREMPLOYMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEAREREMPLOYMENT.TIMESTAMP%type,
        FPsCARDNUMBER                             in out WEAREREMPLOYMENT.CARDNUMBER%type);

procedure CFbStoreOrCreate (
        FPnWEAREREMPLOYMENT_ID                    in out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
        FPnWEARER_ID                              in out WEAREREMPLOYMENT.WEARER_ID%type,
        FPnSEQUENCENUMBER                         in out WEAREREMPLOYMENT.SEQUENCENUMBER%type,
        FPnDISTRIBUTIONPOINT_ID                   in out WEAREREMPLOYMENT.DISTRIBUTIONPOINT_ID%type,
        FPnWEARERFUNCTION_ID                      in out WEAREREMPLOYMENT.WEARERFUNCTION_ID%type,
        FPnFLAG_ID                                in out WEAREREMPLOYMENT.FLAG_ID%type,
        FPnDELIVERYPOINT_ID                       in out WEAREREMPLOYMENT.DELIVERYPOINT_ID%type,
        FPnLOCKER_ID                              in out WEAREREMPLOYMENT.LOCKER_ID%type,
        FPnGARMENTDISPENSER_ID                    in out WEAREREMPLOYMENT.GARMENTDISPENSER_ID%type,
        FPnDISPENSECREDIT                         in out WEAREREMPLOYMENT.DISPENSECREDIT%type,
        FPdtFLAGSTARTDATE                         in out WEAREREMPLOYMENT.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in out WEAREREMPLOYMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEAREREMPLOYMENT.TIMESTAMP%type,
        FPsCARDNUMBER                             in out WEAREREMPLOYMENT.CARDNUMBER%type);

end PACK_WEAREREMPLOYMENT;

/
create or replace PACKAGE BODY PACK_WEAREREMPLOYMENT is

procedure CFbCreate (
        FPnWEAREREMPLOYMENT_ID                    in out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
        FPnWEARER_ID                              in     WEAREREMPLOYMENT.WEARER_ID%type,
        FPnSEQUENCENUMBER                         in     WEAREREMPLOYMENT.SEQUENCENUMBER%type,
        FPnDISTRIBUTIONPOINT_ID                   in     WEAREREMPLOYMENT.DISTRIBUTIONPOINT_ID%type,
        FPnWEARERFUNCTION_ID                      in     WEAREREMPLOYMENT.WEARERFUNCTION_ID%type,
        FPnFLAG_ID                                in     WEAREREMPLOYMENT.FLAG_ID%type,
        FPnDELIVERYPOINT_ID                       in     WEAREREMPLOYMENT.DELIVERYPOINT_ID%type,
        FPnLOCKER_ID                              in     WEAREREMPLOYMENT.LOCKER_ID%type,
        FPnGARMENTDISPENSER_ID                    in     WEAREREMPLOYMENT.GARMENTDISPENSER_ID%type,
        FPnDISPENSECREDIT                         in     WEAREREMPLOYMENT.DISPENSECREDIT%type,
        FPdtFLAGSTARTDATE                         in     WEAREREMPLOYMENT.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in     WEAREREMPLOYMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in     WEAREREMPLOYMENT.TIMESTAMP%type,
        FPsCARDNUMBER                             in     WEAREREMPLOYMENT.CARDNUMBER%type
) is
begin
    insert into WEAREREMPLOYMENT(
        WEAREREMPLOYMENT_ID,
        WEARER_ID,
        SEQUENCENUMBER,
        DISTRIBUTIONPOINT_ID,
        WEARERFUNCTION_ID,
        FLAG_ID,
        DELIVERYPOINT_ID,
        LOCKER_ID,
        GARMENTDISPENSER_ID,
        DISPENSECREDIT,
        FLAGSTARTDATE,
        SYSTEMUSER_ID,
        TIMESTAMP,
        CARDNUMBER
    )
    values (
        SEQ_WEAREREMPLOYMENT.nextval,
        FPnWEARER_ID,
        FPnSEQUENCENUMBER,
        FPnDISTRIBUTIONPOINT_ID,
        FPnWEARERFUNCTION_ID,
        FPnFLAG_ID,
        FPnDELIVERYPOINT_ID,
        FPnLOCKER_ID,
        FPnGARMENTDISPENSER_ID,
        FPnDISPENSECREDIT,
        FPdtFLAGSTARTDATE,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
        FPsCARDNUMBER
    ) returning WEAREREMPLOYMENT_ID into FPnWEAREREMPLOYMENT_ID;
end;

procedure CFbStore (
        FPnWEAREREMPLOYMENT_ID                    in out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
        FPnWEARER_ID                              in out WEAREREMPLOYMENT.WEARER_ID%type,
        FPnSEQUENCENUMBER                         in out WEAREREMPLOYMENT.SEQUENCENUMBER%type,
        FPnDISTRIBUTIONPOINT_ID                   in out WEAREREMPLOYMENT.DISTRIBUTIONPOINT_ID%type,
        FPnWEARERFUNCTION_ID                      in out WEAREREMPLOYMENT.WEARERFUNCTION_ID%type,
        FPnFLAG_ID                                in out WEAREREMPLOYMENT.FLAG_ID%type,
        FPnDELIVERYPOINT_ID                       in out WEAREREMPLOYMENT.DELIVERYPOINT_ID%type,
        FPnLOCKER_ID                              in out WEAREREMPLOYMENT.LOCKER_ID%type,
        FPnGARMENTDISPENSER_ID                    in out WEAREREMPLOYMENT.GARMENTDISPENSER_ID%type,
        FPnDISPENSECREDIT                         in out WEAREREMPLOYMENT.DISPENSECREDIT%type,
        FPdtFLAGSTARTDATE                         in out WEAREREMPLOYMENT.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in out WEAREREMPLOYMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEAREREMPLOYMENT.TIMESTAMP%type,
        FPsCARDNUMBER                             in out WEAREREMPLOYMENT.CARDNUMBER%type
) is
begin
    update WEAREREMPLOYMENT
    set
        WEAREREMPLOYMENT_ID = FPnWEAREREMPLOYMENT_ID,
        WEARER_ID = FPnWEARER_ID,
        SEQUENCENUMBER = FPnSEQUENCENUMBER,
        DISTRIBUTIONPOINT_ID = FPnDISTRIBUTIONPOINT_ID,
        WEARERFUNCTION_ID = FPnWEARERFUNCTION_ID,
        FLAG_ID = FPnFLAG_ID,
        DELIVERYPOINT_ID = FPnDELIVERYPOINT_ID,
        LOCKER_ID = FPnLOCKER_ID,
        GARMENTDISPENSER_ID = FPnGARMENTDISPENSER_ID,
        DISPENSECREDIT = FPnDISPENSECREDIT,
        FLAGSTARTDATE = FPdtFLAGSTARTDATE,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP,
        CARDNUMBER = FPsCARDNUMBER
    where WEAREREMPLOYMENT_ID = FPnWEAREREMPLOYMENT_ID;
    if sql%rowcount < 1 then raise no_data_found; end if;
end;

procedure CFbStoreOrCreate (
        FPnWEAREREMPLOYMENT_ID                    in out WEAREREMPLOYMENT.WEAREREMPLOYMENT_ID%type,
        FPnWEARER_ID                              in out WEAREREMPLOYMENT.WEARER_ID%type,
        FPnSEQUENCENUMBER                         in out WEAREREMPLOYMENT.SEQUENCENUMBER%type,
        FPnDISTRIBUTIONPOINT_ID                   in out WEAREREMPLOYMENT.DISTRIBUTIONPOINT_ID%type,
        FPnWEARERFUNCTION_ID                      in out WEAREREMPLOYMENT.WEARERFUNCTION_ID%type,
        FPnFLAG_ID                                in out WEAREREMPLOYMENT.FLAG_ID%type,
        FPnDELIVERYPOINT_ID                       in out WEAREREMPLOYMENT.DELIVERYPOINT_ID%type,
        FPnLOCKER_ID                              in out WEAREREMPLOYMENT.LOCKER_ID%type,
        FPnGARMENTDISPENSER_ID                    in out WEAREREMPLOYMENT.GARMENTDISPENSER_ID%type,
        FPnDISPENSECREDIT                         in out WEAREREMPLOYMENT.DISPENSECREDIT%type,
        FPdtFLAGSTARTDATE                         in out WEAREREMPLOYMENT.FLAGSTARTDATE%type,
        FPnSYSTEMUSER_ID                          in out WEAREREMPLOYMENT.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEAREREMPLOYMENT.TIMESTAMP%type,
        FPsCARDNUMBER                             in out WEAREREMPLOYMENT.CARDNUMBER%type
) is
	doInsert	boolean;
  nWearerNumber								wearer.wearernumber%type;
  sWearerName									wearer.fullname%type;
  sWearerSearchName						wearer.searchname%type;
begin

	if FPnGARMENTDISPENSER_ID is not null then
  	begin
	    select WEAREREMPLOYMENT_ID, SEQUENCENUMBER into FPnWEAREREMPLOYMENT_ID, FPnSEQUENCENUMBER
  	  	from WEAREREMPLOYMENT
        where WEARER_ID = FPnWEARER_ID and GARMENTDISPENSER_ID is not null;
			doInsert:=false;
  	exception
    	when no_data_found then doInsert:=true;
    end;
  end if;

  if FPnLOCKER_ID is not null then
  	begin
	    select WEAREREMPLOYMENT_ID, SEQUENCENUMBER into FPnWEAREREMPLOYMENT_ID, FPnSEQUENCENUMBER
  	  	from WEAREREMPLOYMENT
        where WEARER_ID = FPnWEARER_ID and LOCKER_ID is not null;
			doInsert:=false;
  	exception
    	when no_data_found then doInsert:=true;
    end;
  end if;

  if FPnDELIVERYPOINT_ID is not null then
  	begin
	    select WEAREREMPLOYMENT_ID, SEQUENCENUMBER into FPnWEAREREMPLOYMENT_ID, FPnSEQUENCENUMBER
  	  	from WEAREREMPLOYMENT
        where WEARER_ID = FPnWEARER_ID and DELIVERYPOINT_ID is not null;
			doInsert:=false;
  	exception
    	when no_data_found then doInsert:=true;
    end;
  end if;

  if doInsert then
  	select nvl(max(sequencenumber), 0)+1 into FPnSEQUENCENUMBER
    	from WEAREREMPLOYMENT
      where WEARER_ID = FPnWEARER_ID;

  	CFbCreate(FPnWEAREREMPLOYMENT_ID,
      		  	FPnWEARER_ID,
	        		FPnSEQUENCENUMBER,
		  	      FPnDISTRIBUTIONPOINT_ID,
    			    FPnWEARERFUNCTION_ID,
        			FPnFLAG_ID,
			        FPnDELIVERYPOINT_ID,
      			  FPnLOCKER_ID,
			        FPnGARMENTDISPENSER_ID,
      			  FPnDISPENSECREDIT,
              FPdtFLAGSTARTDATE,
			        FPnSYSTEMUSER_ID,
      			  FPdtTIMESTAMP,
              FPsCARDNUMBER);

			select wearernumber, fullname, searchname into nWearerNumber, sWearerName, sWearerSearchName
  			from wearer
		    where wearer_id = FPnWEARER_ID;
			insert into weareremployment_link (
  			weareremployment_link_id,
		    weareremployment_id,
		    distributionpoint_link_id,
    		sequencenumber,
		    wearernumber,
    		wearername,
		    wearersearchname,
    		systemuser_id,
		    timestamp)
			values (
  			FPnWEAREREMPLOYMENT_ID,
		    FPnWEAREREMPLOYMENT_ID,
    		FPnDISTRIBUTIONPOINT_ID,
		    FPnSEQUENCENUMBER,
    		nWearerNumber,
		    sWearerName,
    		sWearerSearchName,
		    FPnSYSTEMUSER_ID,
    		FPdtTIMESTAMP);


  else
  	CFbStore(	FPnWEAREREMPLOYMENT_ID,
      		  	FPnWEARER_ID,
	        		FPnSEQUENCENUMBER,
		  	      FPnDISTRIBUTIONPOINT_ID,
    			    FPnWEARERFUNCTION_ID,
        			FPnFLAG_ID,
			        FPnDELIVERYPOINT_ID,
      			  FPnLOCKER_ID,
			        FPnGARMENTDISPENSER_ID,
      			  FPnDISPENSECREDIT,
              FPdtFLAGSTARTDATE,
			        FPnSYSTEMUSER_ID,
      			  FPdtTIMESTAMP,
              FPsCARDNUMBER);

		update weareremployment_link
			set distributionpoint_link_id = FPnDISTRIBUTIONPOINT_ID,
      		sequencenumber = FPnSEQUENCENUMBER,
          SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
          TIMESTAMP = FPdtTIMESTAMP
  		where weareremployment_id = FPnWEAREREMPLOYMENT_ID;
  end if;

end;

end PACK_WEAREREMPLOYMENT;

/
create or replace PACKAGE PACK_WEARERINVENTORY is

procedure CFbStoreOrCreate (
        FPnWEARERINVENTORY_ID                     in out WEARERINVENTORY.WEARERINVENTORY_ID%type,
        FPnWEAREREMPLOYMENT_ID                    in out WEARERINVENTORY.WEAREREMPLOYMENT_ID%type,
        FPnPRODUCT_ID                             in out WEARERINVENTORY.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out WEARERINVENTORY.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out WEARERINVENTORY.FINISHINGMETHOD_ID%type,
        FPnEMBLEMTEMPLATE_ID                      in out WEARERINVENTORY.EMBLEMTEMPLATE_ID%type,
        FPnSPECIALGRADE_ID                        in out WEARERINVENTORY.SPECIALGRADE_ID%type,
        FPnMAXINVENTORY                           in out WEARERINVENTORY.MAXINVENTORY%type,
        FPnFREEOFCHARGEQTY                        in out WEARERINVENTORY.FREEOFCHARGEQTY%type,
        FPnCIRCINVENTORY                          in out WEARERINVENTORY.CIRCINVENTORY%type,
        FPnCHANGESPERWEEK                         in out WEARERINVENTORY.CHANGESPERWEEK%type,
        FPnSYSTEMUSER_ID                          in out WEARERINVENTORY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEARERINVENTORY.TIMESTAMP%type,
        FPnMAXFREEOFCHARGE                        in out WEARERINVENTORY.MAXFREEOFCHARGE%type,
        FPdtDATEACTIVE                            in out WEARERINVENTORY.DATEACTIVE%type,
        FPdtDATEINACTIVE                          in out WEARERINVENTORY.DATEINACTIVE%type,
        FPnSWINGSUITSTATUS                        in out WEARERINVENTORY.SWINGSUITSTATUS%type);

end PACK_WEARERINVENTORY;

/
create or replace PACKAGE BODY PACK_WEARERINVENTORY is

procedure CFbStoreOrCreate (
        FPnWEARERINVENTORY_ID                     in out WEARERINVENTORY.WEARERINVENTORY_ID%type,
        FPnWEAREREMPLOYMENT_ID                    in out WEARERINVENTORY.WEAREREMPLOYMENT_ID%type,
        FPnPRODUCT_ID                             in out WEARERINVENTORY.PRODUCT_ID%type,
        FPnSIZEDEFINITION_ID                      in out WEARERINVENTORY.SIZEDEFINITION_ID%type,
        FPnFINISHINGMETHOD_ID                     in out WEARERINVENTORY.FINISHINGMETHOD_ID%type,
        FPnEMBLEMTEMPLATE_ID                      in out WEARERINVENTORY.EMBLEMTEMPLATE_ID%type,
        FPnSPECIALGRADE_ID                        in out WEARERINVENTORY.SPECIALGRADE_ID%type,
        FPnMAXINVENTORY                           in out WEARERINVENTORY.MAXINVENTORY%type,
        FPnFREEOFCHARGEQTY                        in out WEARERINVENTORY.FREEOFCHARGEQTY%type,
        FPnCIRCINVENTORY                          in out WEARERINVENTORY.CIRCINVENTORY%type,
        FPnCHANGESPERWEEK                         in out WEARERINVENTORY.CHANGESPERWEEK%type,
        FPnSYSTEMUSER_ID                          in out WEARERINVENTORY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEARERINVENTORY.TIMESTAMP%type,
        FPnMAXFREEOFCHARGE                        in out WEARERINVENTORY.MAXFREEOFCHARGE%type,
        FPdtDATEACTIVE                            in out WEARERINVENTORY.DATEACTIVE%type,
        FPdtDATEINACTIVE                          in out WEARERINVENTORY.DATEINACTIVE%type,
        FPnSWINGSUITSTATUS                        in out WEARERINVENTORY.SWINGSUITSTATUS%type
)is
begin
  begin
   insert into WEARERINVENTORY(
        WEARERINVENTORY_ID,
        WEAREREMPLOYMENT_ID,
        PRODUCT_ID,
        SIZEDEFINITION_ID,
        FINISHINGMETHOD_ID,
        EMBLEMTEMPLATE_ID,
        SPECIALGRADE_ID,
        MAXINVENTORY,
        FREEOFCHARGEQTY,
        CIRCINVENTORY,
        CHANGESPERWEEK,
        SYSTEMUSER_ID,
        TIMESTAMP,
        MAXFREEOFCHARGE,
        DATEACTIVE,
        DATEINACTIVE,
        SWINGSUITSTATUS,
        SEASON_ID,
				RETURNEDQTY,
        QTYTOBERETURNEDREPLACEMENT,
        QTYTOBERETURNEDDECREASEMAX,
        TEMPORARYRENTSTOPSTARTDATE,
        TEMPORARYRENTSTOPENDDATE,
        DISPENSECREDIT,
        PERSONALIZEDGARMENT
    )
    values (
        SEQ_WEARERINVENTORY.nextval,
        FPnWEAREREMPLOYMENT_ID,
        FPnPRODUCT_ID,
        FPnSIZEDEFINITION_ID,
        FPnFINISHINGMETHOD_ID,
        FPnEMBLEMTEMPLATE_ID,
        FPnSPECIALGRADE_ID,
        FPnMAXINVENTORY,
        FPnFREEOFCHARGEQTY,
        FPnCIRCINVENTORY,
        FPnCHANGESPERWEEK,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP,
        FPnMAXFREEOFCHARGE,
        FPdtDATEACTIVE,
        FPdtDATEINACTIVE,
        FPnSWINGSUITSTATUS,
        null,
				0,
        0,
        0,
        null,
        null,
        0,
        'Y'
    );
    select SEQ_WEARERINVENTORY.currval into FPnWEARERINVENTORY_ID from dual;
  exception
  	when dup_val_on_index then
	      update WEARERINVENTORY
        set
        WEAREREMPLOYMENT_ID = FPnWEAREREMPLOYMENT_ID,
        PRODUCT_ID = FPnPRODUCT_ID,
        SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID,
        FINISHINGMETHOD_ID = FPnFINISHINGMETHOD_ID,
        EMBLEMTEMPLATE_ID = FPnEMBLEMTEMPLATE_ID,
        SPECIALGRADE_ID = FPnSPECIALGRADE_ID,
        MAXINVENTORY = FPnMAXINVENTORY,
        FREEOFCHARGEQTY = FPnFREEOFCHARGEQTY,
        CIRCINVENTORY = FPnCIRCINVENTORY,
        CHANGESPERWEEK = FPnCHANGESPERWEEK,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP,
        MAXFREEOFCHARGE = FPnMAXFREEOFCHARGE,
        DATEACTIVE = FPdtDATEACTIVE,
        DATEINACTIVE = FPdtDATEINACTIVE,
        SWINGSUITSTATUS = FPnSWINGSUITSTATUS
        where WEAREREMPLOYMENT_ID = FPnWEAREREMPLOYMENT_ID and
        PRODUCT_ID = FPnPRODUCT_ID and
        SIZEDEFINITION_ID = FPnSIZEDEFINITION_ID
				returning WEARERINVENTORY_ID into FPnWEARERINVENTORY_ID;
  end;
end;

end PACK_WEARERINVENTORY;

/
create or replace package pack_webinterface_wmu is

  /******************************************************************************\
  * -- Author   : PVD                                                            *
  * -- Created  : 2010-12-03                                                     *
  * -- Updated  : 2010-12-22 Updated into functions so a number can be returned  *
  *               2010-02-03 Updated because of extra column in workorder table  *
  *               2011-04-11 Updated because of requested changes                *
  *               2011-04-27 Updated because of improved folder/file validations *
  *               2013-10-24 Updated because of wrong reason code used in import *
  *               2017-06-19 ABS-52273 Update finishingmethodcode from S to PRESS*
  *               2017-07-13 ABS 15537 Processing stockroom default ID = 41      *
  *               2017-10-04 ASD-17057 using the order date for needed date TOM=3*
  *               2018-01-15 ABS-59306 Add sales person to import procedure      *
  *               2019-12-20 ABS-88664 Refresh issue in dlg maintain sales notes *
  * -- Purpose  : Import WMU Web Sales                                           *
  *               Export WMU Web Sales                                           *
  \******************************************************************************/

  function import(fp_plantprocessid in plantprocess.plantprocess_id%type) return number;
  function export(fp_plantprocessid in plantprocess.plantprocess_id%type) return number;
end pack_webinterface_wmu;
/
create or replace package body pack_webinterface_wmu is
  gv_userexception exception;
  gv_plantid                 plant.plant_id%type;
  gv_abslogprocessjobid      abslogprocessjob.abslogprocessjob_id%type;
  gv_abslogprocessjobpartid  abslogprocessjobpart.abslogprocessjobpart_id%type;
  gv_processname             abslogprocessjobpart.processname%type;
  gv_systemuserid            systemuser.systemuser_id%type := 0;
  gv_message                 abslog.message%type;
  gv_okcount                 number := 0;
  gv_canclecount             number := 0;
  gv_wo_status_waitforapp_id status.status_id%type;
  gv_reasoncodeid            reasoncode.reasoncode_id%type;
  gv_finishingmethodid       finishingmethod.finishingmethod_id%type;
  gv_requestedgradeid        qualitygrade.qualitygrade_id%type;
  gv_no_date                 date := to_date('31-12-2099', 'DD-MM-YYYY');
  gv_wo_status_05_id         status.status_id%type;
  gv_returnvalue             number := 0;
  gv_orderpriorityid_default orderpriority.orderpriority_id%type;
  -- RVI 20110427, BEGIN
  gv_filehandle utl_file.file_type;
  gv_filename   varchar2(100) := 'ABSTEST.txt';
  ge_wrongpath exception;
  ge_wrongfile exception;
  -- RVI 20110427, END

  procedure write_log(fp_message  in abslogprocessjobline.message%type,
                      fp_priority in abslogprocessjobline.priority%type default 1) is
  begin
    --write_log part
    if gv_abslogprocessjobpartid is null and gv_abslogprocessjobid is not null then
      gv_abslogprocessjobpartid := abslogwrite.abslogprocessjobpart_write(gv_abslogprocessjobid,
                                                                          gv_processname,
                                                                          gv_systemuserid);
    end if;
    abslogwrite.abslogprocessjobline_write(gv_abslogprocessjobpartid, fp_priority, fp_message,
                                           gv_systemuserid);
  exception
    when others then
      begin
        dbms_output.put_line(fp_message);
        dbms_output.put_line(sqlerrm);
        gv_returnvalue := 4;
        abslogwrite.abslog_write(5, 'pack_webinterface_wmu', gv_plantid, 3,
                                 fp_message || ' ' || sqlerrm, gv_systemuserid);
        raise gv_userexception;
      end;
  end write_log;

  procedure end_log is
  begin
    --end_log
    if gv_abslogprocessjobid is not null then
      abslogwrite.abslogprocessjob_update(gv_abslogprocessjobid, sysdate, gv_systemuserid);
    end if;
  exception
    when others then
      begin
        dbms_output.put_line(gv_message);
        dbms_output.put_line(sqlerrm);
      end;
  end end_log;

  procedure initialize(fp_plantprocessid in plantprocess.plantprocess_id%type) is
    procedure get_abslogprocessjobid(fp_plantprocessid in plantprocess.plantprocess_id%type) is
    begin
      --write_log
      gv_abslogprocessjobid := abslogwrite.abslogprocessjob_write(gv_plantid, sysdate, null, null,
                                                                  fp_plantprocessid, gv_systemuserid);
    end get_abslogprocessjobid;
  begin
    --initialize
    gv_message     := 'initialize';
    gv_okcount     := 0;
    gv_canclecount := 0;
    gv_returnvalue := 0;
    execute immediate 'alter session set NLS_NUMERIC_CHARACTERS=''.,''';
    gv_abslogprocessjobid := null;
    --get plant id
    gv_message := 'initialize get plant id for plantprocess id ' || to_char(fp_plantprocessid);
    select pp.plant_id, pp.systemuser_id
    into   gv_plantid, gv_systemuserid
    from   plantprocess pp
    where  pp.plantprocess_id = fp_plantprocessid;
    --get abslog process job id
    get_abslogprocessjobid(fp_plantprocessid);
    --get status id
    select st.status_id
    into   gv_wo_status_waitforapp_id
    from   status st
    where  st.statustype = 'WO'
    and    st.code = '05';
    -- RVI 20131024, BEGIN
    --get reasoncode '02'
    gv_message := 'get reasoncode ''02''';
    select rs.reasoncode_id into gv_reasoncodeid from reasoncode rs where rs.code = '02';
    -- RVI 20131024, END
    --get finishingmethod 'S'
    gv_message := 'get finishingmethod ''PRESS''';
    select f.finishingmethod_id
    into   gv_finishingmethodid
    from   finishingmethod f
    where  f.code = 'PRESS';
    --requested grade 1
    gv_message := 'get requested quality grade with priority 1';
    select q.qualitygrade_id into gv_requestedgradeid from qualitygrade q where q.priority = 1;
    --get status 05 for wo waiting on approval
    gv_message := 'get WO status 05 waiting for approval';
    select st.status_id
    into   gv_wo_status_05_id
    from   status st
    where  st.statustype = 'WO'
    and    st.code = '05';
    --get orderpriority
    gv_message := 'No active default order priority found for order type 1 (= Work Order)';
    select op.orderpriority_id
    into   gv_orderpriorityid_default
    from   orderpriority op
    where  op.active = 'Y'
    and    op.ordertype = 1
    and    op.standardpriority = 'Y';
  exception
    when others then
      begin
        gv_returnvalue := 4;
        raise gv_userexception;
      end;
  end initialize;

  function get_systemsetting(fp_systemsettingname systemsetting.name%type)
    return systemsetting.value%type is
    lv_value systemsetting.value%type;
  begin
    --get_systemsetting
    gv_message := 'get_systemsetting ' || fp_systemsettingname;
    select nvl(ss.value, ss.factorydefault)
    into   lv_value
    from   systemsetting ss
    where  ss.plant_id = gv_plantid
    and    ss.name = fp_systemsettingname;
    return lv_value;
  end get_systemsetting;

  -- RVI 20110427, BEGIN
  function check_dir(fp_dir       in varchar2,
                     fp_filename  in varchar2,
                     fp_direction in varchar2,
                     fp_result    in varchar2) return utl_file.file_type is
  begin
    --determine directory level
    if (upper(fp_direction) = 'IMPORT') then
      begin
        gv_message := 'Import failed: directory is invalid. Please check system setting IMPDIRWEBSALES!';
        if ((upper(fp_result) = 'OK') or (upper(fp_result) = 'FAIL')) then
          gv_message := 'No "OK" and/or "Fail" sub directory found in directory "';
          gv_message := gv_message || substr(fp_dir, 1, length(fp_dir) - (length(fp_result) + 1)) ||
                        '". Please correct this!';
        end if;
      end;
    else
      gv_message := 'Export failed: directory is invalid. Please check system setting EXPDIRWEBSALES!';
    end if;
    --open (dummy) file
    return utl_file.fopen(fp_dir, fp_filename, 'w', 32767);
    utl_file.put_line(gv_filehandle, 'dummy');
    -- close file
    if utl_file.is_open(gv_filehandle) = true then
      utl_file.fclose(gv_filehandle);
    end if;
  exception
    when others then
      raise ge_wrongpath;
  end check_dir;

  function check_file(fp_dir in varchar2, fp_filename in varchar2) return utl_file.file_type is
  begin
    --
    gv_message := 'No import file "' || fp_filename || '" found in directory "' || fp_dir ||
                  '". Please correct this!';
    --open file
    return utl_file.fopen(fp_dir, fp_filename, 'r');
    -- close file
    if utl_file.is_open(gv_filehandle) = true then
      utl_file.fclose(gv_filehandle);
    end if;
  exception
    when others then
      raise ge_wrongfile;
  end check_file;
  -- RVI 20110427, END

  function open_file(fp_filedir in varchar2, fp_filename in varchar2, fp_open_mode in varchar2)
    return utl_file.file_type is
  begin
    --open the file
    gv_message := 'file ' || fp_filename || ' in directory ' || fp_filedir;
    return utl_file.fopen(fp_filedir, fp_filename, fp_open_mode);
  exception
    when utl_file.invalid_path then
      begin
        gv_message     := gv_message || ' Invalid Path';
        gv_returnvalue := 1;
        raise;
      end;
    when utl_file.invalid_mode then
      begin
        gv_message     := gv_message || ' Invalid Mode';
        gv_returnvalue := 1;
        raise;
      end;
    when utl_file.invalid_operation then
      begin
        gv_message     := gv_message || ' Invalid Path or File';
        gv_returnvalue := 2;
        raise;
      end;
    when utl_file.invalid_filehandle then
      begin
        gv_message     := gv_message || ' Invalid Filehandle';
        gv_returnvalue := 1;
        raise;
      end;
    when utl_file.write_error then
      begin
        gv_message     := gv_message || ' Write Error';
        gv_returnvalue := 1;
        raise;
      end;
    when utl_file.read_error then
      begin
        gv_message     := gv_message || ' Read Error';
        gv_returnvalue := 1;
        raise;
      end;
    when utl_file.internal_error then
      begin
        gv_message     := gv_message || ' Internal Error';
        gv_returnvalue := 4;
        raise;
      end;
  end open_file;

  procedure close_files is
  begin
    --close_files
    gv_message := 'close_files';
    utl_file.fclose_all;
  end close_files;

  procedure process_line(fp_readline          in varchar2,
                         fp_ok_filehandle     in utl_file.file_type,
                         fp_cancel_filehandle in utl_file.file_type,
                         fp_seperator         in varchar2 default ',') is
    lv_currentposition           number := 0;
    lv_nextposition              number := 0;
    lv_customernumber            customer.customernumber%type;
    lv_customerid                customer.customer_id%type;
    lv_firstdistributionpointid  distributionpoint.distributionpoint_id%type;
    lv_businessunitid            businessunit.businessunit_id%type;
    lv_plantid                   businessunit.plant_id%type;
    lv_invoicebusinessunitid     businessunit.businessunit_id%type;
    lv_businessunitcode          businessunit.code%type;
    lv_plantdepartmentid         plantdepartment.plantdepartment_id%type;
    lv_workorder_referencenumber workorder.referencenumber%type;
    lv_workorderid               workorder.workorder_id%type;
    lv_workorderlineid           workorderline.workorderline_id%type;
    lv_orderdate                 workorder.requestdate%type;
    lv_productcode               product.code%type;
    lv_productid                 product.product_id%type;
    lv_product_tom               product.typeofmerchandise%type;
    lv_mountingproduct           product.mountingproduct%type;
    lv_sizecode                  sizedefinition.code%type;
    lv_sizeid                    sizedefinition.sizedefinition_id%type;
    lv_price                     workorderline.salesprice%type;
    lv_amount                    workorderline.quantityordered%type;
    lv_websalesnote              workorder.websalesnote%type;
    lv_emblemtemplatecode        emblemtemplate.code%type;
    lv_emblemtemplateid          emblemtemplate.emblemtemplate_id%type;
    lv_remark                    workorder.remark%type;
    lv_instructions              workorderline.instructions%type;
    lv_salespersonnumber         employee.employeenumber%type;
    lv_salesemployee1id          workorder.salesemployee1_id%type;
    lv_codeuniquely              productlistpercustomer.codeuniquely%type;

    function get_nextvalue return varchar2 is
      function get_position(fp_startpos in number) return number is
      begin
        --get_position
        return instr(substr(fp_readline, fp_startpos + 1), fp_seperator) + fp_startpos;
      end get_position;
    begin
      --get_nextvalue
      lv_currentposition := lv_nextposition;
      lv_nextposition    := get_position(lv_currentposition);
      if lv_nextposition = lv_currentposition then
        --last string, repeat it, if nothing else...
        return substr(fp_readline, lv_currentposition + 1);
      else
        return substr(fp_readline, lv_currentposition + 1, lv_nextposition - lv_currentposition - 1);
      end if;
    end get_nextvalue;

    procedure read_line is
    begin
      --read_line
      gv_message                   := 'read_line customernumber ';
      lv_customernumber            := get_nextvalue;
      gv_message                   := 'read_line workorder_referencenumber / order number ';
      lv_workorder_referencenumber := get_nextvalue;
      gv_message                   := 'read_line request date ';
      lv_orderdate                 := to_date(get_nextvalue, 'DD-MM-YYYY');
      gv_message                   := 'read_line product code ';
      lv_productcode               := get_nextvalue;
      gv_message                   := 'read_line size code ';
      lv_sizecode                  := get_nextvalue;
      gv_message                   := 'read_line price ';
      lv_price                     := to_number(get_nextvalue);
      gv_message                   := 'read_line amount ';
      lv_amount                    := to_number(get_nextvalue);
      gv_message                   := 'read_line billed Y/N ';
      lv_websalesnote := case
                           when get_nextvalue = 'Y' then
                            2
                           else
                            1
                         end;
      gv_message                   := 'read_line emblem template code ';
      lv_emblemtemplatecode        := get_nextvalue;
      gv_message                   := 'read_line order remark ';
      lv_remark                    := get_nextvalue;
      gv_message                   := 'read_line instructions ';
      lv_instructions              := get_nextvalue;
      gv_message                   := 'read_line salesperson number ';
      lv_salespersonnumber         := get_nextvalue;
      --one line read
    end read_line;

    procedure write_line(fp_filehandle in utl_file.file_type) is
    begin
      --write_line
      gv_message := 'write_line';
      utl_file.put_line(fp_filehandle, fp_readline);
    end write_line;

    procedure get_values is
      lv_activeyn     emblemtemplate.active%type;
      lv_dateactive   customer.dateactive%type;
      lv_dateinactive customer.dateinactive%type;
      lv_activityid   activity.activity_id%type;
      lv_activitycode activity.code%type;
    begin
      --get_values
      --customer
      gv_message := ' customer number ' || to_char(lv_customernumber);
      select c.customer_id, c.defaultbusinessunit_id, bu.code, bu.plant_id,
             (select min(dp.distributionpoint_id)
               from   department t, distributionpoint dp
               where  t.active = 'Y'
               and    t.customer_id = c.customer_id
               and    t.department_id = dp.department_id
               and    dp.active = 'Y'), c.plantdepartment_id, c.active, c.dateactive, c.dateinactive
      into   lv_customerid, lv_businessunitid, lv_businessunitcode, lv_plantid,
             lv_firstdistributionpointid, lv_plantdepartmentid, lv_activeyn, lv_dateactive,
             lv_dateinactive
      from   customer c
      join   businessunit bu
      on     bu.businessunit_id = c.defaultbusinessunit_id
      where  c.customernumber = lv_customernumber;
      if (lv_activeyn <> 'Y') or not (sysdate between lv_dateactive and lv_dateinactive) then
        begin
          gv_message := gv_message || ' is not active';
          raise gv_userexception;
        end;
      end if;
      --product
      gv_message := ' product code ' || lv_productcode;
      select p.product_id, p.typeofmerchandise, pg.activity_id, p.mountingproduct, p.active
      into   lv_productid, lv_product_tom, lv_activityid, lv_mountingproduct, lv_activeyn
      from   product p, productgroup pg
      where  p.code = lv_productcode
      and    p.productgroup_id = pg.productgroup_id;
      if lv_activeyn <> 'Y' then
        begin
          gv_message := gv_message || ' is not active';
          raise gv_userexception;
        end;
      end if;
      --get activty code
      gv_message := ' activity code not found for activity id ' || lv_activityid;
      select a.code into lv_activitycode from activity a where a.activity_id = lv_activityid;
      --get customer activity invoicebusinessunit
      gv_message := 'get invoicebusinessunit for customer ' || to_char(lv_customernumber) ||
                    ' process businessunit ' || lv_businessunitcode || ' activitycode ' ||
                    lv_activitycode;
      select ca.invoicebusinessunit_id
      into   lv_invoicebusinessunitid
      from   customeractivities ca
      where  ca.customer_id = lv_customerid
      and    ca.activity_id = lv_activityid
      and    ca.processbusinessunit_id = lv_businessunitid;
      --size
      gv_message := ' size code ' || lv_sizecode;
      select s.sizedefinition_id into lv_sizeid from sizedefinition s where s.code = lv_sizecode;
      --product size
      gv_message := ' size code ' || lv_sizecode || ' for product code ' || lv_productcode;
      select ps.defaultstockroom_id
      into   lv_emblemtemplateid --misused, value not needed, reset net check
      from   productsize ps
      where  ps.product_id = lv_productid
      and    ps.sizedefinition_id = lv_sizeid;
      --emblem
      if lv_emblemtemplatecode is null then
        begin
          lv_emblemtemplateid := null;
        end;
      else
        begin
          gv_message := ' emblem template code ' || lv_emblemtemplatecode || ' for customer ' ||
                        to_char(lv_customernumber);
          select emt.emblemtemplate_id, emt.active
          into   lv_emblemtemplateid, lv_activeyn
          from   emblemtemplate emt
          where  emt.code = lv_emblemtemplatecode
          and    emt.customer_id = lv_customerid;
          if lv_activeyn = 'N' then
            begin
              gv_message := gv_message || ' is not active';
              raise gv_userexception;
            end;
          end if;
        end;
      end if;
      begin
        --get plpc line
        gv_message := 'get active product list per customer for customer ' || lv_customernumber ||
                      ' product ' || lv_productcode || ' size ' || lv_sizecode ||
                      ' and finishingmethod S';
        select l.codeuniquely
        into   lv_codeuniquely
        from   productlistpercustomer l
        where  l.customer_id = lv_customerid
        and    l.product_id = lv_productid
        and    l.sizedefinition_id = lv_sizeid
        and    l.finishingmethod_id = gv_finishingmethodid
        and    sysdate between l.dateactive and l.dateinactive;
      exception
        when no_data_found then
          begin
            --PLPC is not needed for Sales Items
            lv_codeuniquely := 'N';
          end;
      end;
      --get workorder.salesemployee1_id
      if lv_salespersonnumber is null then
        begin
          lv_salesemployee1id := null;
        end;
      else
        begin
          select em.employee_id
          into   lv_salesemployee1id
          from   employee em
          where  em.employeenumber = lv_salespersonnumber
          and    em.plant_id = lv_plantid;
        exception
          when no_data_found then
            begin
              select em.employee_id
              into   lv_salesemployee1id
              from   employee em
              where  em.employeenumber = lv_salespersonnumber;
            exception
              when no_data_found then
                begin
                  lv_salesemployee1id := null;
                  write_log('Warning Sales Employee number ' || lv_salespersonnumber ||
                            ' not found!', 3);
                end;
            end;
        end;
      end if;
    end get_values;

    function get_or_create_workorder return workorder.workorder_id%type is
      lv_rec_workorder workorder%rowtype;

      procedure get_workorder is
      begin
        --get workorder
        select *
        into   lv_rec_workorder
        from   workorder wo
        where  wo.referencenumber = lv_workorder_referencenumber
        and    wo.origin = 6;
        --check status
        if lv_rec_workorder.status_id <> gv_wo_status_05_id then
          begin
            gv_message := 'Order ' || to_char(lv_rec_workorder.workordernumber) ||
                          ' has already been imported';
            raise gv_userexception;
          end;
        end if;
      exception
        when no_data_found then
          begin
            lv_rec_workorder.workorder_id := null;
          end;
      end get_workorder;

      procedure create_workorder is
        procedure init_workorder(fp_workorderrec in out workorder%rowtype) is
          lv_query varchar2(1000);
          type cur_typ is ref cursor;
          rcur_typ cur_typ;
        begin
          --fill the workorder row fp_workorderrec with default values from table workorder
          for rec in (select data_default, data_type
                      from   user_tab_columns
                      where  table_name = 'WORKORDER'
                      order  by column_id) loop
            if rec.data_default is null then
              lv_query := lv_query || ', null';
            else
              lv_query := lv_query || ', ' || rec.data_default;
            end if;
          end loop;
          lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
          open rcur_typ for lv_query;
          fetch rcur_typ
            into fp_workorderrec;
          close rcur_typ;
        end init_workorder;
      begin
        --create_workorder
        gv_message := 'create_workorder';
        --init
        init_workorder(lv_rec_workorder);
        --get workorder id
        select seq_workorder.nextval into lv_rec_workorder.workorder_id from dual;
        --get workorder number
        gv_message := 'create_workorder get workorder number for businessunit ' ||
                      lv_businessunitcode;
        execute immediate 'select seq_workorder_' || lv_businessunitcode || '.nextval from dual'
          into lv_rec_workorder.workordernumber;
        --get other values
        gv_message                                 := 'fill create workorder values';
        lv_rec_workorder.weareremployment_link_id  := null;
        lv_rec_workorder.status_id                 := gv_wo_status_waitforapp_id;
        lv_rec_workorder.businessunit_id           := lv_businessunitid;
        lv_rec_workorder.requestdate               := lv_orderdate;
        lv_rec_workorder.entrydate                 := trunc(sysdate);
        lv_rec_workorder.neededdate := case
                                         when lv_product_tom in (1, 2) then
                                          nvl(pack_sort.getnextdeliverydate(sysdate, lv_customerid,
                                                                            lv_product_tom), lv_orderdate)
                                         else
                                          lv_orderdate
                                       end;
        --get route id
        select max(rs.route_id)
        into   lv_rec_workorder.route_id
        from   routestop rs
        join   route r
        on     r.route_id = rs.route_id
        where  rs.customer_id = lv_customerid
        and    r.active = 'Y'
        and    lv_rec_workorder.neededdate between rs.dateactive and rs.dateinactive
        and    r.drivingday_id = getabsdaynumber(lv_rec_workorder.neededdate);
        lv_rec_workorder.expectedcompletedate      := gv_no_date;
        lv_rec_workorder.completiondate            := gv_no_date;
        lv_rec_workorder.referencenumber           := lv_workorder_referencenumber;
        lv_rec_workorder.remark                    := lv_remark;
        lv_rec_workorder.customerowned             := 'N';
        lv_rec_workorder.billtocustomerrelated     := 'N';
        lv_rec_workorder.deliverfrom               := 0;
        lv_rec_workorder.systemuser_id             := gv_systemuserid;
        lv_rec_workorder.timestamp                 := sysdate;
        lv_rec_workorder.allowphasedelivery        := 'N';
        lv_rec_workorder.labelsprinted             := 'N';
        lv_rec_workorder.emblempicklistprinted     := 'N';
        lv_rec_workorder.picklistprinted           := 'N';
        lv_rec_workorder.customer_link_id          := lv_customerid;
        lv_rec_workorder.ordered                   := 'N';
        lv_rec_workorder.origin                    := 6; --salesnote
        lv_rec_workorder.pickdate                  := gv_no_date;
        lv_rec_workorder.pickuser_id               := null;
        lv_rec_workorder.availability              := 0;
        lv_rec_workorder.creditworkorder_id        := null;
        lv_rec_workorder.invoiceheader_id := case
                                               when lv_websalesnote = 2 then
                                                -1
                                               else
                                                null
                                             end;
        lv_rec_workorder.invoicebusinessunit_id    := lv_invoicebusinessunitid;
        lv_rec_workorder.distributionpoint_link_id := lv_firstdistributionpointid;
        lv_rec_workorder.exported                  := 'Y';
        lv_rec_workorder.exportdate                := trunc(sysdate);
        lv_rec_workorder.sladeliverydate           := null;
        lv_rec_workorder.axaptavkonr               := null;
        lv_rec_workorder.reasoncode_id             := gv_reasoncodeid;
        lv_rec_workorder.startrentfrom             := 0;
        lv_rec_workorder.startrentdate             := null;
        lv_rec_workorder.plantdepartment_id        := lv_plantdepartmentid;
        lv_rec_workorder.creationuser_id           := gv_systemuserid;
        lv_rec_workorder.webuser                   := null;
        lv_rec_workorder.replacement               := 'N';
        lv_rec_workorder.workorderprinted          := 'N';
        lv_rec_workorder.activatereplacementflag   := 0;
        lv_rec_workorder.salespricedefined         := 'Y';
        lv_rec_workorder.creationtimestamp         := sysdate;
        lv_rec_workorder.inprocessstarted          := null;
        lv_rec_workorder.inprocessatworkstation_id := null;
        lv_rec_workorder.dialog_id                 := null;
        lv_rec_workorder.processingstockroom_id    := 41;
        lv_rec_workorder.workorderpicked           := 'N';
        lv_rec_workorder.driversales               := 'N';
        lv_rec_workorder.truck_id                  := null;
        lv_rec_workorder.driveremployee_id         := null;
        lv_rec_workorder.routecontrol_id           := null;
        lv_rec_workorder.stop_id                   := null;
        lv_rec_workorder.routestop_id              := null;
        lv_rec_workorder.expectedmountingdate      := gv_no_date;
        lv_rec_workorder.mountingdate              := gv_no_date;
        lv_rec_workorder.confirmationdate          := gv_no_date;
        lv_rec_workorder.mountingorder_id          := null;
        lv_rec_workorder.mountingordersales        := 'N';
        lv_rec_workorder.stopnumber                := null;
        lv_rec_workorder.reservationtimestamp      := null;
        lv_rec_workorder.salesemployee1_id         := null;
        lv_rec_workorder.salesemployee2_id         := null;
        lv_rec_workorder.lastprinted_date          := null;
        lv_rec_workorder.lastprintedsystemuser_id  := null;
        lv_rec_workorder.websalesnote              := lv_websalesnote;
        lv_rec_workorder.directinvoice             := 'Y';
        lv_rec_workorder.orderpriority_id          := gv_orderpriorityid_default;
        lv_rec_workorder.salesemployee1_id         := lv_salesemployee1id;
        --insert workorder records
        gv_message := 'insert into workorder';
        insert into workorder values lv_rec_workorder;
        --write log
        write_log('Web order ' || lv_workorder_referencenumber || ' has been processed.' ||
                  chr(10) || ' a corresponding Sales Order with number ' ||
                  to_char(lv_rec_workorder.workordernumber) || ' has been created.');
      end create_workorder;
    begin
      --get_or_create_workorder
      gv_message := 'get_or_create_workorder';
      --get workorder
      get_workorder;
      if lv_rec_workorder.workorder_id is null then
        begin
          --create workorder
          create_workorder;
        end;
      end if;
      return lv_rec_workorder.workorder_id;
    end get_or_create_workorder;

    function create_or_update_workorderline(fp_workorderid in workorder.workorder_id%type)
      return workorderline.workorderline_id%type is
      lv_rec_workorderline workorderline%rowtype;

      procedure get_workorderline is
        lv_emblemcode emblemtemplate.code%type := null;
      begin
        --get_workorderline
        --PRODUCT_LINK_ID, SIZEDEFINITION_LINK_ID, FINISHINGMETHOD_ID, AUXILIARYSTATUS
        select wol.*
        into   lv_rec_workorderline
        from   workorderline wol
        where  wol.workorder_id = fp_workorderid
        and    wol.product_link_id = lv_productid
        and    wol.sizedefinition_link_id = lv_sizeid
        and    wol.finishingmethod_id = gv_finishingmethodid
        and    (wol.auxiliarystatus is null or wol.auxiliarystatus = 0);
        --check emblem template
        if (lv_rec_workorderline.emblemtemplate_id is null and lv_emblemtemplateid is not null) then
          begin
            gv_message := 'Emblem ' || lv_emblemtemplatecode ||
                          ' was not connected to existing order line. ';
            raise gv_userexception;
          end;
        end if;
        if (lv_rec_workorderline.emblemtemplate_id is not null and lv_emblemtemplateid is null) then
          begin
            --get linked emblemtemplate code
            select t.code
            into   lv_emblemcode
            from   emblemtemplate t
            where  t.emblemtemplate_id = lv_rec_workorderline.emblemtemplate_id;
            gv_message := 'No emblem specified in import file but emblem ' || lv_emblemcode ||
                          ' was connected to existing order line. ';
            raise gv_userexception;
          end;
        end if;
        if (lv_rec_workorderline.emblemtemplate_id <> lv_emblemtemplateid) then
          begin
            --get linked emblemtemplate code
            select t.code
            into   lv_emblemcode
            from   emblemtemplate t
            where  t.emblemtemplate_id = lv_rec_workorderline.emblemtemplate_id;
            gv_message := 'Emblem ' || lv_emblemtemplatecode ||
                          ' from import file does not match with emblem ' || lv_emblemcode ||
                          ' connected to existing order line. ';
            raise gv_userexception;
          end;
        end if;
        --update
        update workorderline wol
        set    wol.quantityordered = wol.quantityordered + lv_amount
        where  wol.workorderline_id = lv_rec_workorderline.workorderline_id;
      exception
        when no_data_found then
          begin
            lv_rec_workorderline.workorderline_id := null;
          end;
      end get_workorderline;

      procedure create_workorderline is
        procedure init_workorderline(fp_workorderlinerec in out workorderline%rowtype) is
          lv_query varchar2(1000);
          type cur_typ is ref cursor;
          rcur_typ cur_typ;
        begin
          --fill the workorder row fp_workorderrec with default values from table workorder
          for rec in (select data_default, data_type
                      from   user_tab_columns
                      where  table_name = 'WORKORDERLINE'
                      order  by column_id) loop
            if rec.data_default is null then
              lv_query := lv_query || ', null';
            else
              lv_query := lv_query || ', ' || rec.data_default;
            end if;
          end loop;
          lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
          open rcur_typ for lv_query;
          fetch rcur_typ
            into fp_workorderlinerec;
          close rcur_typ;
        end init_workorderline;
      begin
        --create_workorderline
        gv_message := 'create_workorderline';
        --init
        init_workorderline(lv_rec_workorderline);
        --get workorderline id
        select seq_workorderline.nextval into lv_rec_workorderline.workorderline_id from dual;
        --get other values
        gv_message                                     := 'fill create workorderline values';
        lv_rec_workorderline.workorder_id              := fp_workorderid;
        lv_rec_workorderline.product_link_id           := lv_productid;
        lv_rec_workorderline.sizedefinition_link_id    := lv_sizeid;
        lv_rec_workorderline.finishingmethod_id        := gv_finishingmethodid;
        lv_rec_workorderline.requestedgrade_id         := gv_requestedgradeid;
        lv_rec_workorderline.reasoncode_id             := gv_reasoncodeid;
        lv_rec_workorderline.quantityordered           := lv_amount;
        lv_rec_workorderline.completiondate            := gv_no_date;
        lv_rec_workorderline.codeuniquely              := lv_codeuniquely;
        lv_rec_workorderline.instructions              := lv_instructions;
        lv_rec_workorderline.systemuser_id             := gv_systemuserid;
        lv_rec_workorderline.timestamp                 := sysdate;
        lv_rec_workorderline.quantityfilled            := 0;
        lv_rec_workorderline.quantitypendingorder      := 0;
        lv_rec_workorderline.quantitycancelled         := 0;
        lv_rec_workorderline.purchaseorderline_id      := null;
        lv_rec_workorderline.emblemtemplate_id         := lv_emblemtemplateid;
        lv_rec_workorderline.purchaserequest_id        := null;
        lv_rec_workorderline.quantitypicked            := 0;
        lv_rec_workorderline.expecteddate              := gv_no_date;
        lv_rec_workorderline.auxiliarystatus           := null;
        lv_rec_workorderline.quantitysubstitute        := 0;
        lv_rec_workorderline.salesprice                := lv_price;
        lv_rec_workorderline.quantitytobecredited      := 0;
        lv_rec_workorderline.quantityreturned          := 0;
        lv_rec_workorderline.sladeliverydate           := null;
        lv_rec_workorderline.wearergarmentsbudgetvalue := 0;
        lv_rec_workorderline.discountpercentage        := 0;
        lv_rec_workorderline.salesitem                 := 'Y';
        lv_rec_workorderline.startservice              := 'N';
        lv_rec_workorderline.tobemounted               := lv_mountingproduct;
        lv_rec_workorderline.quantityfirstdelivery     := 0;
        lv_rec_workorderline.rentalqtyadjustment_id    := null;
        --insert record
        gv_message := 'insert into workorderline ';
        insert into workorderline values lv_rec_workorderline;
      end create_workorderline;
    begin
      --create_or_update_workorderline
      gv_message := 'create_or_update_workorderline';
      --get workorderline
      get_workorderline;
      if lv_rec_workorderline.workorderline_id is null then
        begin
          create_workorderline;
        end;
      end if;
      return lv_rec_workorderline.workorderline_id;
    end create_or_update_workorderline;

    procedure create_or_upd_workordlinembl(fp_workorderlineid in workorderline.workorderline_id%type) is
      lv_rec_workorderlineemblem workorderlineemblem%rowtype;

      procedure get_workorderlineemblem(fp_emblemtemplatelinerec in emblemtemplateline%rowtype) is
      begin
        --get_workorderlineemblem
        gv_message := 'get_workorderlineemblem';
        --select
        select wole.*
        into   lv_rec_workorderlineemblem
        from   workorderlineemblem wole
        where  wole.emblemtemplateline_id = fp_emblemtemplatelinerec.emblemtemplateline_id
        and    wole.workorderline_id = fp_workorderlineid;
        --update
        update workorderlineemblem wole
        set    wole.qtyrequested = wole.qtyrequested +
                                    (fp_emblemtemplatelinerec.qtypergarment * lv_amount)
        where  wole.workorderlineemblem_id = lv_rec_workorderlineemblem.workorderlineemblem_id;
      exception
        when no_data_found then
          begin
            lv_rec_workorderlineemblem.workorderlineemblem_id := null;
          end;
      end get_workorderlineemblem;

      procedure create_workorderlineemblem(fp_emblemtemplatelinerec in emblemtemplateline%rowtype) is
        procedure init_workorderlineemblem(fp_workorderlineemblemrec in out workorderlineemblem%rowtype) is
          lv_query varchar2(1000);
          type cur_typ is ref cursor;
          rcur_typ cur_typ;
        begin
          --fill the workorderlineemblem row fp_workorderlineemblemrec
          --with default values from table workorderlineemblem
          for rec in (select data_default, data_type
                      from   user_tab_columns
                      where  table_name = 'WORKORDERLINEEMBLEM'
                      order  by column_id) loop
            if rec.data_default is null then
              lv_query := lv_query || ', null';
            else
              lv_query := lv_query || ', ' || rec.data_default;
            end if;
          end loop;
          lv_query := 'SELECT' || substr(lv_query, 2) || ' FROM DUAL';
          open rcur_typ for lv_query;
          fetch rcur_typ
            into fp_workorderlineemblemrec;
          close rcur_typ;
        end init_workorderlineemblem;
      begin
        --create_workorderlineemblem
        gv_message := 'create_workorderlineemblem';
        --init workorderlineemblem
        init_workorderlineemblem(lv_rec_workorderlineemblem);
        --get workorderlineemblem_id
        select seq_workorderlineemblem.nextval
        into   lv_rec_workorderlineemblem.workorderlineemblem_id
        from   dual;
        --get other values
        gv_message                                       := 'fill create workorderlineemblem values';
        lv_rec_workorderlineemblem.workorderline_id      := fp_workorderlineid;
        lv_rec_workorderlineemblem.emblemtemplateline_id := fp_emblemtemplatelinerec.emblemtemplateline_id;
        lv_rec_workorderlineemblem.product_id            := null;
        lv_rec_workorderlineemblem.sizedefinition_id     := null;
        lv_rec_workorderlineemblem.attachmentby          := fp_emblemtemplatelinerec.attachmentby;
        lv_rec_workorderlineemblem.qtyrequested          := fp_emblemtemplatelinerec.qtypergarment *
                                                            lv_amount;
        lv_rec_workorderlineemblem.qtyissued             := 0;
        lv_rec_workorderlineemblem.systemuser_id         := gv_systemuserid;
        lv_rec_workorderlineemblem.timestamp             := sysdate;
        lv_rec_workorderlineemblem.placement_id          := fp_emblemtemplatelinerec.placement_id;
        lv_rec_workorderlineemblem.purchaserequest_id    := null;
        lv_rec_workorderlineemblem.purchaseorderline_id  := null;
        lv_rec_workorderlineemblem.embroiderylettering   := fp_emblemtemplatelinerec.embroiderylettering;
        if (lv_rec_workorderlineemblem.embroiderylettering = 'Y' and
           fp_emblemtemplatelinerec.emblemtype = 1) then
          begin
            lv_rec_workorderlineemblem.embroideryletteringline1 := fp_emblemtemplatelinerec.embroideryletteringline1;
            lv_rec_workorderlineemblem.embroideryletteringline2 := fp_emblemtemplatelinerec.embroideryletteringline2;
            lv_rec_workorderlineemblem.embroideryletteringline3 := fp_emblemtemplatelinerec.embroideryletteringline3;
          end;
        end if;
        --insert record
        gv_message := 'insert into workorderlineemblem ';
        insert into workorderlineemblem values lv_rec_workorderlineemblem;
      end create_workorderlineemblem;
    begin
      --create_or_upd_workordlinembl
      gv_message := 'create_or_update_workorderlineemblem';
      --get all emblemtemplate lines
      for e in (select etl.*
                from   emblemtemplateline etl
                where  etl.emblemtemplate_id = lv_emblemtemplateid) loop
        begin
          --get workorderlineemblem
          get_workorderlineemblem(e);
          if lv_rec_workorderlineemblem.workorderlineemblem_id is null then
            begin
              create_workorderlineemblem(e);
            end;
          end if;
        end;
      end loop; --e
    end create_or_upd_workordlinembl;
  begin
    --read line
    read_line;
    --check line
    get_values;
    --get_or_create_workorder
    lv_workorderid := get_or_create_workorder;
    --create_or_update_workorderline
    lv_workorderlineid := create_or_update_workorderline(lv_workorderid);
    if lv_emblemtemplateid is not null then
      --create_or_update_workorderlineemblem
      create_or_upd_workordlinembl(lv_workorderlineid);
    end if;
    --process ok line
    write_line(fp_ok_filehandle);
    commit;
    gv_okcount := gv_okcount + 1;
  exception
    --process cancled lines
    when gv_userexception then
      begin
        rollback;
        write_log(gv_message || '. Line is not imported', 3);
        write_line(fp_cancel_filehandle);
        gv_canclecount := gv_canclecount + 1;
        gv_returnvalue := 3;
      end;
    when no_data_found then
      begin
        rollback;
        gv_message := gv_message || ' does not exist. Line is not imported';
        write_log(gv_message, 3);
        write_line(fp_cancel_filehandle);
        gv_canclecount := gv_canclecount + 1;
        gv_returnvalue := 3;
      end;
    when others then
      begin
        rollback;
        gv_message := gv_message ||
                      ' errors ''others'' see detail debug info. Line is not imported';
        write_log(gv_message, 3);
        write_log(sqlerrm, 5);
        write_line(fp_cancel_filehandle);
        gv_canclecount := gv_canclecount + 1;
        gv_returnvalue := 4;
      end;
  end process_line;

  function import(fp_plantprocessid in plantprocess.plantprocess_id%type) return number is
    lv_filename          varchar2(1000) := 'daily_' || to_char(sysdate, 'YYYYMMDD') || '.csv';
    lv_read_filedir      varchar2(1000);
    lv_read_filehandle   utl_file.file_type;
    lv_ok_filedir        varchar2(1000);
    lv_ok_filehandle     utl_file.file_type;
    lv_cancel_filedir    varchar2(1000);
    lv_cancel_filehandle utl_file.file_type;

    procedure process_file is
      lv_readline varchar2(4000);
      lv_counter  number := 0;
    begin
      --process_file
      gv_message := ' process file ' || lv_read_filedir || lv_filename;
      --loop go through lines
      loop
        begin
          begin
            -- get line from file.
            utl_file.get_line(lv_read_filehandle, lv_readline);
          exception
            when no_data_found then
              exit;
          end;
          --process_line
          process_line(lv_readline, lv_ok_filehandle, lv_cancel_filehandle);
          lv_counter := lv_counter + 1;
        end;
      end loop;
      write_log(lv_counter || ' lines processed, successfully processed ' || gv_okcount ||
                ' lines ' || case when gv_canclecount > 0 then
                to_char(gv_canclecount) || ' errors see log' end);
    end process_file;

    procedure open_files is
    begin
      --
      lv_read_filedir := rtrim(get_systemsetting('IMPDIRWEBSALES'), '\');
      -- RVI 20110427, BEGIN
      -- check import directory
      gv_filehandle := check_dir(lv_read_filedir, gv_filename, 'import', null);
      lv_ok_filedir := lv_read_filedir || '\OK\';
      -- check Ok import directory
      gv_filehandle     := check_dir(lv_ok_filedir, gv_filename, 'import', 'ok');
      lv_cancel_filedir := lv_read_filedir || '\Fail\';
      -- check Fail import directory
      gv_filehandle := check_dir(lv_cancel_filedir, gv_filename, 'import', 'fail');

      -- check import file
      gv_filehandle := check_file(lv_read_filedir, lv_filename);
      -- RVI 20110427, END

      --open_files
      lv_read_filehandle := open_file(lv_read_filedir, lv_filename, 'r');
      --lv_ok_filedir        := lv_read_filedir || '\OK\';
      lv_ok_filehandle := open_file(lv_ok_filedir, lv_filename, 'a');
      --lv_cancel_filedir    := lv_read_filedir || '\Fail\';
      lv_cancel_filehandle := open_file(lv_cancel_filedir, lv_filename, 'a');
    end open_files;

    procedure close_files_endlog is
    begin
      --close_files
      close_files;
      --end log
      end_log;
    end close_files_endlog;
  begin
    --import
    gv_processname := 'pack_webinterface_wmu.import';
    gv_message     := gv_processname;
    --check parameter not null
    if fp_plantprocessid is null then
      begin
        gv_message     := 'parameter fp_plantprocessid cannot be left empty!';
        gv_returnvalue := 1;
        raise gv_userexception;
      end;
    end if;
    initialize(fp_plantprocessid);
    --open files
    open_files;
    --process file
    process_file;
    --close files
    close_files_endlog;
    return gv_returnvalue;
  exception
    when gv_userexception then
      begin
        dbms_output.put_line(gv_message);
        rollback;
        close_files_endlog;
        if gv_returnvalue = 0 then
          gv_returnvalue := 2;
        end if;
        return gv_returnvalue;
      end;
    when others then
      begin
        write_log(sqlerrm, 5);
        write_log(gv_message, 3);
        rollback;
        close_files_endlog;
        if gv_returnvalue = 0 then
          gv_returnvalue := 4;
        end if;
        return gv_returnvalue;
      end;
  end import;

  function export(fp_plantprocessid in plantprocess.plantprocess_id%type) return number is
    lv_filename   varchar2(1000) := 'WEBORDER' || to_char(sysdate, 'YYYYMMDDHH24MI') || '.csv';
    lv_filedir    varchar2(1000);
    lv_filehandle utl_file.file_type;

    procedure open_files is
    begin
      --open_files
      lv_filedir := rtrim(get_systemsetting('EXPDIRWEBSALES'), '\');
      -- RVI 20110427, BEGIN
      -- check export directory
      gv_filehandle := check_dir(lv_filedir, gv_filename, 'export', null);
      -- RVI 20110427, END
      lv_filehandle := open_file(lv_filedir, lv_filename, 'w');
    end open_files;

    procedure export_file(fp_seperator in varchar2 default ',') is
      procedure write_line(fp_writeline in varchar2) is
      begin
        --write_line
        gv_message := 'write_line';
        utl_file.put_line(lv_filehandle, fp_writeline);
      end write_line;

      procedure set_wo_to_exported(fp_workorderid in workorder.workorder_id%type) is
      begin
        --set_wo_to_exported
        gv_message := 'set_wo_to_exported workorder id ' || to_char(fp_workorderid);
        update workorder wo
        set    wo.exported = 'Y', wo.exportdate = trunc(sysdate)
        where  wo.workorder_id = fp_workorderid;
      end set_wo_to_exported;
    begin
      --export file
      gv_message := 'export_file';
      for x in (select wo.referencenumber, wo.workordernumber,
                       (select st.code from status st where st.status_id = wo.status_id) statuscode,
                       case
                         when ((wo.websalesnote = 2) or
                              (wo.invoiceheader_id is not null and wo.websalesnote = 1)) then
                          'Y'
                         else
                          'N'
                       end billed,
                       (select c.customernumber
                         from   customer_link c
                         where  c.customer_id = wo.customer_link_id) customernumber, wo.workorder_id
                from   workorder wo
                where  wo.exported = 'N'
                and    wo.websalesnote in (1, 2)
                order  by wo.referencenumber, wo.workordernumber) loop
        begin
          --export line
          write_line(x.referencenumber || fp_seperator || to_char(x.workordernumber) ||
                     fp_seperator || x.statuscode || fp_seperator || x.billed);
          --set to exported
          set_wo_to_exported(x.workorder_id);
          --write log
          write_log('Sales Order ' || to_char(x.workordernumber) || ' from customer ' ||
                    x.customernumber || ' that corresponds with Web Order ' || x.referencenumber ||
                    ' has been exported');
          gv_okcount := gv_okcount + 1;
        end;
      end loop; --x
      commit;
    end export_file;

    procedure close_files_endlog is
    begin
      --
      case
        when gv_canclecount > 0 then
          write_log('Errors please check log');
        when gv_okcount = 0 then
          write_log('No Sales Orders found to be exported');
        else
          write_log(gv_okcount || ' lines exported successfully');
      end case;
      --close_files
      close_files;
      --end log
      end_log;
    end close_files_endlog;
  begin
    --import
    gv_processname := 'pack_webinterface_wmu.export';
    gv_message     := gv_processname;
    --check parameter not null
    if fp_plantprocessid is null then
      begin
        gv_message     := 'parameter fp_plantprocessid cannot be left empty!';
        gv_returnvalue := 1;
        raise gv_userexception;
      end;
    end if;
    initialize(fp_plantprocessid);
    --open files
    open_files;
    --export file
    export_file;
    --close files
    close_files_endlog;
    return gv_returnvalue;
  exception
    when gv_userexception then
      begin
        gv_canclecount := gv_canclecount + 1;
        dbms_output.put_line(gv_message);
        rollback;
        close_files_endlog;
        if gv_returnvalue = 0 then
          gv_returnvalue := 2;
        end if;
        return gv_returnvalue;
      end;
    when others then
      begin
        gv_canclecount := gv_canclecount + 1;
        write_log(sqlerrm, 5);
        write_log(gv_message, 3);
        rollback;
        close_files_endlog;
        if gv_returnvalue = 0 then
          gv_returnvalue := 4;
        end if;
        return gv_returnvalue;
      end;
  end export;
end pack_webinterface_wmu;
/
create or replace PACKAGE PACK_WEIGHINGHISTORY is

procedure CFbStoreOrCreate (
        FPnWEIGHINGHISTORY_ID                     in out WEIGHINGHISTORY.WEIGHINGHISTORY_ID%type,
        FPnCUSTOMER_LINK_ID                       in out WEIGHINGHISTORY.CUSTOMER_LINK_ID%type,
        FPnDEPARTMENT_LINK_ID                     in out WEIGHINGHISTORY.DEPARTMENT_LINK_ID%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out WEIGHINGHISTORY.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnWEIGHINGCATEGORY_LINK_ID               in out WEIGHINGHISTORY.WEIGHINGCATEGORY_LINK_ID%type,
        FPdtWEIGHINGDATE                          in out WEIGHINGHISTORY.WEIGHINGDATE%type,
        FPnYEAR                                   in out WEIGHINGHISTORY.YEAR%type,
        FPnWEEK                                   in out WEIGHINGHISTORY.WEEK%type,
        FPnDAYNUMBER                              in out WEIGHINGHISTORY.DAYNUMBER%type,
        FPnSOILWEIGHT                             in out WEIGHINGHISTORY.SOILWEIGHT%type,
        FPnCLEANWEIGHT                            in out WEIGHINGHISTORY.CLEANWEIGHT%type,
        FPnPROCESSBUSINESSUNIT_ID                 in out WEIGHINGHISTORY.PROCESSBUSINESSUNIT_ID%type,
        FPnINVOICEBUSINESSUNIT_ID                 in out WEIGHINGHISTORY.INVOICEBUSINESSUNIT_ID%type,
        FPnSYSTEMUSER_ID                          in out WEIGHINGHISTORY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEIGHINGHISTORY.TIMESTAMP%type);

end PACK_WEIGHINGHISTORY;

/
create or replace PACKAGE BODY PACK_WEIGHINGHISTORY is

procedure CFbStoreOrCreate (
        FPnWEIGHINGHISTORY_ID                     in out WEIGHINGHISTORY.WEIGHINGHISTORY_ID%type,
        FPnCUSTOMER_LINK_ID                       in out WEIGHINGHISTORY.CUSTOMER_LINK_ID%type,
        FPnDEPARTMENT_LINK_ID                     in out WEIGHINGHISTORY.DEPARTMENT_LINK_ID%type,
        FPnDISTRIBUTIONPOINT_LINK_ID              in out WEIGHINGHISTORY.DISTRIBUTIONPOINT_LINK_ID%type,
        FPnWEIGHINGCATEGORY_LINK_ID               in out WEIGHINGHISTORY.WEIGHINGCATEGORY_LINK_ID%type,
        FPdtWEIGHINGDATE                          in out WEIGHINGHISTORY.WEIGHINGDATE%type,
        FPnYEAR                                   in out WEIGHINGHISTORY.YEAR%type,
        FPnWEEK                                   in out WEIGHINGHISTORY.WEEK%type,
        FPnDAYNUMBER                              in out WEIGHINGHISTORY.DAYNUMBER%type,
        FPnSOILWEIGHT                             in out WEIGHINGHISTORY.SOILWEIGHT%type,
        FPnCLEANWEIGHT                            in out WEIGHINGHISTORY.CLEANWEIGHT%type,
        FPnPROCESSBUSINESSUNIT_ID                 in out WEIGHINGHISTORY.PROCESSBUSINESSUNIT_ID%type,
        FPnINVOICEBUSINESSUNIT_ID                 in out WEIGHINGHISTORY.INVOICEBUSINESSUNIT_ID%type,
        FPnSYSTEMUSER_ID                          in out WEIGHINGHISTORY.SYSTEMUSER_ID%type,
        FPdtTIMESTAMP                             in out WEIGHINGHISTORY.TIMESTAMP%type
) is
begin
    insert into WEIGHINGHISTORY(
        WEIGHINGHISTORY_ID,
        CUSTOMER_LINK_ID,
        DEPARTMENT_LINK_ID,
        DISTRIBUTIONPOINT_LINK_ID,
        WEIGHINGCATEGORY_LINK_ID,
        WEIGHINGDATE,
        YEAR,
        WEEK,
        DAYNUMBER,
        SOILWEIGHT,
        CLEANWEIGHT,
        PROCESSBUSINESSUNIT_ID,
        INVOICEBUSINESSUNIT_ID,
        SYSTEMUSER_ID,
        TIMESTAMP
    )
    values (
        SEQ_WEIGHINGHISTORY.nextval,
        FPnCUSTOMER_LINK_ID,
        FPnDEPARTMENT_LINK_ID,
        FPnDISTRIBUTIONPOINT_LINK_ID,
        FPnWEIGHINGCATEGORY_LINK_ID,
        FPdtWEIGHINGDATE,
        FPnYEAR,
        FPnWEEK,
        FPnDAYNUMBER,
        FPnSOILWEIGHT,
        FPnCLEANWEIGHT,
        FPnPROCESSBUSINESSUNIT_ID,
        FPnINVOICEBUSINESSUNIT_ID,
        FPnSYSTEMUSER_ID,
        FPdtTIMESTAMP
    );
    select SEQ_WEIGHINGHISTORY.currval into FPnWEIGHINGHISTORY_ID from dual;
exception when dup_val_on_index then
    update WEIGHINGHISTORY
    set
        CUSTOMER_LINK_ID = FPnCUSTOMER_LINK_ID,
        DEPARTMENT_LINK_ID = FPnDEPARTMENT_LINK_ID,
        DISTRIBUTIONPOINT_LINK_ID = FPnDISTRIBUTIONPOINT_LINK_ID,
        WEIGHINGCATEGORY_LINK_ID = FPnWEIGHINGCATEGORY_LINK_ID,
        WEIGHINGDATE = FPdtWEIGHINGDATE,
        YEAR = FPnYEAR,
        WEEK = FPnWEEK,
        DAYNUMBER = FPnDAYNUMBER,
        SOILWEIGHT = FPnSOILWEIGHT,
        CLEANWEIGHT = FPnCLEANWEIGHT,
        PROCESSBUSINESSUNIT_ID = FPnPROCESSBUSINESSUNIT_ID,
        INVOICEBUSINESSUNIT_ID = FPnINVOICEBUSINESSUNIT_ID,
        SYSTEMUSER_ID = FPnSYSTEMUSER_ID,
        TIMESTAMP = FPdtTIMESTAMP
    where CUSTOMER_LINK_ID = FPnCUSTOMER_LINK_ID and
            DEPARTMENT_LINK_ID = FPnDEPARTMENT_LINK_ID and
            DISTRIBUTIONPOINT_LINK_ID = FPnDISTRIBUTIONPOINT_LINK_ID and
	        WEIGHINGCATEGORY_LINK_ID = FPnWEIGHINGCATEGORY_LINK_ID and
            WEIGHINGDATE = FPdtWEIGHINGDATE and
            PROCESSBUSINESSUNIT_ID = FPnPROCESSBUSINESSUNIT_ID;

end;

end PACK_WEIGHINGHISTORY;

/
create or replace PACKAGE PACK_WORKORDERLINE is

  procedure CFbCreateOrStore(FPnWORKORDERLINE_ID       in out WORKORDERLINE.WORKORDERLINE_ID%type,
                             FPnWORKORDER_ID           in WORKORDERLINE.WORKORDER_ID%type,
                             FPnPRODUCT_LINK_ID        in WORKORDERLINE.PRODUCT_LINK_ID%type,
                             FPnSIZEDEFINITION_LINK_ID in WORKORDERLINE.SIZEDEFINITION_LINK_ID%type,
                             FPnFINISHINGMETHOD_ID     in WORKORDERLINE.FINISHINGMETHOD_ID%type,
                             FPnREQUESTEDGRADE_ID      in WORKORDERLINE.REQUESTEDGRADE_ID%type,
                             FPnREASONCODE_ID          in WORKORDERLINE.REASONCODE_ID%type,
                             FPnQUANTITYORDERED        in WORKORDERLINE.QUANTITYORDERED%type,
                             FPdtCOMPLETIONDATE        in WORKORDERLINE.COMPLETIONDATE%type,
                             FPsCODEUNIQUELY           in WORKORDERLINE.CODEUNIQUELY%type,
                             FPsINSTRUCTIONS           in WORKORDERLINE.INSTRUCTIONS%type,
                             FPnQUANTITYFILLED         in WORKORDERLINE.QUANTITYFILLED%type,
                             FPnQUANTITYPENDINGORDER   in WORKORDERLINE.QUANTITYPENDINGORDER%type,
                             FPnQUANTITYCANCELLED      in WORKORDERLINE.QUANTITYCANCELLED%type,
                             FPnSYSTEMUSER_ID          in WORKORDERLINE.SYSTEMUSER_ID%type,
                             FPdtTIMESTAMP             in WORKORDERLINE.TIMESTAMP%type,
                             FPnPURCHASEORDERLINE_ID   in WORKORDERLINE.PURCHASEORDERLINE_ID%type,
                             FPnEMBLEMTEMPLATE_ID      out WORKORDERLINE.EMBLEMTEMPLATE_ID%type,
                             FPnQUANTITYPICKED         in WORKORDERLINE.QUANTITYPICKED%type);

end PACK_WORKORDERLINE;

/
create or replace PACKAGE BODY PACK_WORKORDERLINE is

  procedure CFbCreateOrStore(FPnWORKORDERLINE_ID       in out WORKORDERLINE.WORKORDERLINE_ID%type,
                             FPnWORKORDER_ID           in WORKORDERLINE.WORKORDER_ID%type,
                             FPnPRODUCT_LINK_ID        in WORKORDERLINE.PRODUCT_LINK_ID%type,
                             FPnSIZEDEFINITION_LINK_ID in WORKORDERLINE.SIZEDEFINITION_LINK_ID%type,
                             FPnFINISHINGMETHOD_ID     in WORKORDERLINE.FINISHINGMETHOD_ID%type,
                             FPnREQUESTEDGRADE_ID      in WORKORDERLINE.REQUESTEDGRADE_ID%type,
                             FPnREASONCODE_ID          in WORKORDERLINE.REASONCODE_ID%type,
                             FPnQUANTITYORDERED        in WORKORDERLINE.QUANTITYORDERED%type,
                             FPdtCOMPLETIONDATE        in WORKORDERLINE.COMPLETIONDATE%type,
                             FPsCODEUNIQUELY           in WORKORDERLINE.CODEUNIQUELY%type,
                             FPsINSTRUCTIONS           in WORKORDERLINE.INSTRUCTIONS%type,
                             FPnQUANTITYFILLED         in WORKORDERLINE.QUANTITYFILLED%type,
                             FPnQUANTITYPENDINGORDER   in WORKORDERLINE.QUANTITYPENDINGORDER%type,
                             FPnQUANTITYCANCELLED      in WORKORDERLINE.QUANTITYCANCELLED%type,
                             FPnSYSTEMUSER_ID          in WORKORDERLINE.SYSTEMUSER_ID%type,
                             FPdtTIMESTAMP             in WORKORDERLINE.TIMESTAMP%type,
                             FPnPURCHASEORDERLINE_ID   in WORKORDERLINE.PURCHASEORDERLINE_ID%type,
                             FPnEMBLEMTEMPLATE_ID      out WORKORDERLINE.EMBLEMTEMPLATE_ID%type,
                             FPnQUANTITYPICKED         in WORKORDERLINE.QUANTITYPICKED%type) is

  	thisExpectedDate date := to_date('31/12/2004', 'dd/mm/yyyy');

	begin
    insert into WORKORDERLINE
      (WORKORDERLINE_ID,
       WORKORDER_ID,
       PRODUCT_LINK_ID,
       SIZEDEFINITION_LINK_ID,
       FINISHINGMETHOD_ID,
       REQUESTEDGRADE_ID,
       REASONCODE_ID,
       QUANTITYORDERED,
       COMPLETIONDATE,
       CODEUNIQUELY,
       INSTRUCTIONS,
       QUANTITYFILLED,
       QUANTITYPENDINGORDER,
       QUANTITYCANCELLED,
       SYSTEMUSER_ID,
       TIMESTAMP,
       PURCHASEORDERLINE_ID,
       EMBLEMTEMPLATE_ID,
       QUANTITYPICKED,
			 expectedDate)
    values
      (SEQ_WORKORDERLINE.nextval,
       FPnWORKORDER_ID,
       FPnPRODUCT_LINK_ID,
       FPnSIZEDEFINITION_LINK_ID,
       FPnFINISHINGMETHOD_ID,
       FPnREQUESTEDGRADE_ID,
       FPnREASONCODE_ID,
       FPnQUANTITYORDERED,
       FPdtCOMPLETIONDATE,
       FPsCODEUNIQUELY,
       FPsINSTRUCTIONS,
       FPnQUANTITYFILLED,
       FPnQUANTITYPENDINGORDER,
       FPnQUANTITYCANCELLED,
       FPnSYSTEMUSER_ID,
       FPdtTIMESTAMP,
       FPnPURCHASEORDERLINE_ID,
       FPnEMBLEMTEMPLATE_ID,
       FPnQUANTITYPICKED,
			 thisExpectedDate)
    returning WORKORDERLINE_ID into FPnWORKORDERLINE_ID;
  exception
    when dup_val_on_index then
      begin
        update WORKORDERLINE
           set FINISHINGMETHOD_ID   = FPnFINISHINGMETHOD_ID,
               QUANTITYORDERED      = FPnQUANTITYORDERED,
               COMPLETIONDATE       = FPdtCOMPLETIONDATE,
               CODEUNIQUELY         = FPsCODEUNIQUELY,
               INSTRUCTIONS         = FPsINSTRUCTIONS,
               QUANTITYFILLED       = FPnQUANTITYFILLED,
               QUANTITYPENDINGORDER = FPnQUANTITYPENDINGORDER,
               QUANTITYCANCELLED    = FPnQUANTITYCANCELLED,
               SYSTEMUSER_ID        = FPnSYSTEMUSER_ID,
               TIMESTAMP            = FPdtTIMESTAMP,
               PURCHASEORDERLINE_ID = FPnPURCHASEORDERLINE_ID,
               EMBLEMTEMPLATE_ID    = FPnEMBLEMTEMPLATE_ID,
               QUANTITYPICKED       = FPnQUANTITYPICKED
         where WORKORDER_ID = FPnWORKORDER_ID and
               PRODUCT_LINK_ID = FPnPRODUCT_LINK_ID and
               SIZEDEFINITION_LINK_ID = FPnSIZEDEFINITION_LINK_ID and
               REQUESTEDGRADE_ID = FPnREQUESTEDGRADE_ID and
               REASONCODE_ID = FPnREASONCODE_ID returning
         WORKORDERLINE_ID into FPnWORKORDERLINE_ID;
      end;
  end;


end PACK_WORKORDERLINE;

/
create or replace package types as
    type cursortype is ref cursor;
  end;

/
set define on 
/

