create or replace package pack_multiread is
  -- Version 3.14 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

  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)
  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')
  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

  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

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_pnprocessed_statusid       NUMBER := 0;

  -- 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;
  gc_ss_laundrycode             varchar2(3);
  --------- 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;

  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(100) := '';
  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) := '';

  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,'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,'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,'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_pnprocessed_statusid
     from   status st
     where  st.statustype = 'PN' --Packingnote
     and    st.code = '20'; -- In progress

     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 = '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;

  end read_systemsettings;

 ------------------------------------------------------------------
 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
        into gv_businessunit_id,
             lv_outscanpoolitems,
             gv_plant_id,
             gv_workstation_id,
             gv_workstation_code,
             gv_packingnote_id,
             gv_prodprocessbuffer_id,
             gv_systemuser_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;

    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 m.timestamp < trunc(sysdate) - 5
                         and m.multireadscanbatch_id <> gv_multireadscanbatch_id
                         and (select max(mbc.scantimestamp)
                                from multireadscanbatchcontents mbc
                               where mbc.multireadscanbatch_id = m.multireadscanbatch_id) < trunc(sysdate) - 5)
      loop
        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;
        writemultireadwarninglog;
        delete from multireadscanbatch b where b.multireadscanbatch_id = c_batch.multireadscanbatch_id;
        commit;
      end loop;
    exception
      when no_data_found then null;
    end;

    gv_code_block := 'Purge Production Process Buffer Scans';
    begin
      writemultireaddebuglog('Purge Production Process Buffer Scans');
      DELETE
        FROM productionprocessscan p
       WHERE p.uniqueitembufferinfo_id is null
         and p.plant_id = gv_plant_id
         and p.scandate < trunc(sysdate) - gc_daystokeepinprodprocbufscan;
    exception
      when no_data_found then
        null;
    end;

    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; -- 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;
   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');
     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
           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
           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
       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

  -------------------------------------------
  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 PK_MULTIREADSCANBATCHCONTENT)*/ 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,
     uhfbundle_id,
     scantimestamp,
     systemuser_id,
     virtualyn
    )
    values
    (merge_subquery.multireadscanbatch_id,
     merge_subquery.subbatch,
     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_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
               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;
      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
               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;
      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 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 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;

      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;

      return 0;
   end f_validatescanbatchKNT;

  ----------------------------------------------------------------------------------------------
  function f_validateoutscanbatch 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 2
      -- Mark all other items as not found in database
      if (gv_items_in_batch > gv_items_found) then
        begin
        writemultireaddebuglog('Step 2');
        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 pool items
      begin
        writemultireaddebuglog('Step 3');
        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 4
      -- Mark all with flags that prohibit delivery with exception reason
      begin
        writemultireaddebuglog('Step 4');
        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;

      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
               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
                                             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
               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
                                             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 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 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
/* 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 6b 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 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
      -- check if not already scanned at this delivery note.
      begin
        writemultireaddebuglog('Step 8a 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;

      if gv_outscangarmentsaswell then
        begin
          writemultireaddebuglog('Step 8b 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 9 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)
         (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
            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 10A -- assign tags first to pack content products.
      if gv_outscantrackonly <> 'Y' then
      begin
        writemultireaddebuglog('Step 10a 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 10b 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 11
      -- find plpc
      begin
        writemultireaddebuglog('Step 11a 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 11b 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 12
      -- mark those for which no contract could be found.
      begin
        writemultireaddebuglog('Step 12 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 13
      -- populate finishingmethod and packingsequence
      begin
        writemultireaddebuglog('Step 13 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 14
      -- 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 14 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.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 MERGE_SUBQUERY.dateinactive <= trunc(sysdate)
                                          then 18 -- inactive container
                                          else null
                                         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 MERGE_SUBQUERY.dateinactive <= trunc(sysdate)
                                          then 18 -- inactive container
                                          else null
                                         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;
      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_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;
  ------------------------------------------
  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_main_code_block := 'Validate Stack';
      -- 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;

      -- 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.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, 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,
                    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;
      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.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, 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,
                    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;
      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 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;

        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
                      y.product_id
                     else
                      0
                   end) product_id,
               sum(case
                     when y.myrownr = 1 then
                      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'

      begin
        if lv_stackcheckpack = 'N' and gv_stacksize = 0 /*auto*/  and lv_stackcheck_product_id is not null
          then
             select trunc(p.packingamount)
               into gv_stacksize
               from product p
              where p.product_id = lv_stackcheck_stackproduct_id;
        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;

        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
         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 0;
   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 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_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 2
      -- 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 3
      -- Mark all type of merchandize 2 garments with rejection reason
      begin
        writemultireaddebuglog('Step 3 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 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;
      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 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 := 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,
                    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,
                    u.distributionpoint_id,
                    u.lastdistributionpoint_link_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.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,
                    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 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)
        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 inscan
           );
    exception
      when no_data_found then
        null;
    end;
   end create_delivery_variations;

   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)
            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
               );
        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
               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>0
                                      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 = gc_status_id_in_circ,
                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>0
                                      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);
    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,
           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
           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;

   ----------------------------------------------------------------
   -- 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
               ( SELECT COUNT(1) FROM DELIVERYSCAN DS JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
               WHERE DS.PACKINGNOTE_ID IS NOT NULL
               and DS.UNIQUEITEM_LINK_ID = m.uniqueitem_id
               and DS.WEAREREMPLOYMENT_LINK_ID = m.weareremployment_id )  > 0
               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 + lv_number_assigned_items_deliv )  > 0 and gs_ss_bringincircatinscan=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_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;

     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;

     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;

     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_assigned_items number := 0;
   lv_number_assigned_items_deliv     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,
                    u.distributionpoint_id,
                    u.lastdistributionpoint_link_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.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)
        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
           );
    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)
        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
           );
    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='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
               ( SELECT COUNT(1) FROM DELIVERYSCAN DS JOIN UNIQUEITEM UI ON DS.UNIQUEITEM_LINK_ID = UI.UNIQUEITEM_ID
               WHERE DS.PACKINGNOTE_ID IS NOT NULL
               and DS.UNIQUEITEM_LINK_ID = m.uniqueitem_id
               and DS.WEAREREMPLOYMENT_LINK_ID = m.weareremployment_id )  > 0
               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;
     --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>0
                                      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>0
                                      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
           )
    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
      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 = pl.deliveredamount + 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 = pl.deliveredamount + 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)
        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
           );
    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 pn.packingnote_id
            into lv_highestchildpn
            from packingnote pn, multireadscanbatch mb
           where mb.multireadscanbatch_id = gv_multireadscanbatch_id
             and pn.bulkpackingnote_id = mb.packingnote_id
             and rownum = 1
           order by pn.notenumber desc;
      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 = p.deliveredamount + 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 = p.deliveredamount + 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
               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>0
                                      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 gc_ss_laundrycode = 'ANG'
                                              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.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
                 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>0
                                        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 gc_ss_laundrycode = 'ANG'
                                           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.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
               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>0
                                      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.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>0
                                      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);
    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
             )
      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
        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)
        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
           );
    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>0
                                      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 gc_ss_laundrycode = 'ANG'
                                         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;


    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>0
                                            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 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>0
                                      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);
    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,
           null, -- 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)
    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
      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;

    ---------------------------------------------
    function f_getrelatedcustomer return number is
    -- returns relatedcustomerID if the same for all items in batch
    lv_relatedcustomerid   number;
    begin
      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;

    ---------------------------------------------
    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, store, pnremark, loadsequencenr, deliverysignature_id)
              values
                (seq_packingnote.nextval, lv_notenumber, trunc(sysdate), trunc(sysdate) + 1,
                 gc_pnprocessed_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, 'N', 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_pnprocessed_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>0
                                          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);
        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;
    ---------------------------------------------
  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;
               --
              insert into uhfbundle
                 (uhfbundle_id,
                  businessunit_id,
                  product_link_id,
                  sizedefinition_link_id,
                  bundlesize,
                  workstation,
                  systemuser_id,
                  timestamp,
                  deliverystatus,
                  pack,
                  bundleprimaryid,
                  creationdate,
                  relatedcustomer_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)
                        then null
                        else mb.stackcheckproduct_id
                      end,
                      case when mb.stackcheckpack='N' and lv_number_distinct_products = 1
                        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
                 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;

            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;


   ---------------------------------------------
   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
               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 = gc_status_id_in_circ,
                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);
    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,
           gc_status_id_in_circ,
           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

   ----------------------------------------------------------------
   -- 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
          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;

     -- bring in circ assigned items
    if gv_result = 0 and lv_number_assigned_items > 0 and gs_ss_bringincircatinscan=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

     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);
    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);
    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 1 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
   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)
        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
           );

    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_pnprocessed_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, store, pnremark, loadsequencenr,
            deliverysignature_id)
         values
           (seq_packingnote.nextval, lv_notenumber, trunc(sysdate), trunc(sysdate) + 1, gc_pnprocessed_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, 'N', 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)
    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;
      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;
    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_main_code_block := 'UHF Startup Phase Processing';
    gv_code_block := 'Read system setting';
    lc_ss_uhfpoolitemstartupcalc := 2; -- default
    gv_result := 0;
    writemultireaddebuglog('Start');
    begin
      select s.value
        into lc_ss_uhfpoolitemstartupcalc
        from systemsetting s
       where s.name = 'UHFPOOLITEMSTARTUPCALC'
         and s.plant_id = fp_plant_id;
    exception
      when no_data_found then
        lc_ss_uhfpoolitemstartupcalc := 2;
    end;
    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')
    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;

      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;

    begin   -- f_domultireadinscanbatch
      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 <> 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;

end pack_multiread;
/
