Optomistic/Pessimistic Record Locking
 
Forums / SmartComponent Library - Developer Forum / Optomistic/Pessimistic Record Locking

Optomistic/Pessimistic Record Locking

3 posts, 0 answered
  1. Roger Blanchard
    Roger Blanchard avatar
    413 posts
    Registered:
    29 Jun 2018
    04 Dec 2019
    Link to this post
    We are having an issue with optimistic locking. We have pos transaction processing logic that can update up to 18 tables in the database. We have been using a pessimistic locking approach for years and years with no record locking issues. We decided to try an move to use a Dataset Model class so we created a BE with the 18 tables. We are seeing the “DatasetException: record locked by another user” quite often.

    We do surround all of the SaveChanges with a DO TRANSACTION as we want ALL tables to be updated or none.

    For example, we have the following.

    Before I go back to the pessimistic locking approach and bypass the DatasetModel class I wanted to post this and see if I am missing something. Maybe the optimistic locking approach is not a good solution for what we need to do in this use case.

    Thanks in advance.

    DO TRANSACTION ON ERROR UNDO, THROW:

                      /* Roger Blanchard / Osprey Retail Systems Apr 2, 2019
                            Now update our DB records as one DB transaction. 
                      */

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateGeneralTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                       oGeneralTotal
                                                                                                                   ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateDeptTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                    oGeneralTotal
                                                                                                                ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateMediaTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                     oGeneralTotal
                                                                                                                 ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateHistoryTots (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                      oGeneralTotal
                                                                                                                  ).                                                                                                                                                                                                                              

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateModifierTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                        oGeneralTotal
                                                                                                                    ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateNonSaleTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                       oGeneralTotal
                                                                                                                   ).                                                                                                              

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateSpecialFunctTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                            oGeneralTotal
                                                                                                                       ).   

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateCardTypeTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                        oGeneralTotal
                                                                                                                    ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateTaxTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                   oGeneralTotal
                                                                                                               ).                                                                                                                                                                                                                                                                                                                                                

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateCommDet (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                  oGeneralTotal
                                                                                                              ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateForeignCurrencyTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                               oGeneralTotal
                                                                                                                           ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateSalesmanTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                        oGeneralTotal
                                                                                                                    ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateSalesmanProdTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                            oGeneralTotal
                                                                                                                        ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateCustItemHist (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE
                                                                                                                 ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateCustomerTotals (oTransactionTotals,
                                                                                   oLoyaltyTotals
                                                                                    )):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE
                                                                                                                 ).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateBuydownHist (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                      oGeneralTotal
                                                                                                                  ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateBuydownTotals (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE
                                                                                                                    ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateChargeTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE
                                                                                                                  ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateRebateItemHist (oTransactionTotals)):PerformDBUpdate(DATASET dsPosTransaction BY-REFERENCE
                                                                                                                 ).

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateEcoupon (oTransactionTotals)):PerformDBUpdate(DATASET dsPosTransaction BY-REFERENCE
                                                                                                                 ).                                                                                                                                                                                                                               
                      /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
                            Any error thrown we want to just throw up up the call stack
                      */
                      CATCH e AS Progress.Lang.Error:
                            UNDO, THROW e.
                      END CATCH.

                END.    


    [19/11/20@18:16:08.578-0500] P-010172 T-009192 1 AS-4 ORS_ERR        An Consultingwerk.Exceptions.DatasetException has occurred:
    [19/11/20@18:16:08.578-0500] P-010172 T-009192 1 AS-4 ORS_ERR        Unable to update GeneralTotal record because it is locked by another user! (12300)
    [19/11/20@18:16:08.578-0500] P-010172 T-009192 1 AS-4 ORS_ERR          Table: eGeneralTotal
    [19/11/20@18:16:08.578-0500] P-010172 T-009192 1 AS-4 ORS_ERR        
    [19/11/20@18:16:08.578-0500] P-010172 T-009192 1 AS-4 ORS_ERR        ThrowDatasetErrors Consultingwerk.Util.DatasetHelper at line 3803  (Consultingwerk/Util/DatasetHelper.r)
  2. Mike Fechner
    Mike Fechner avatar
    342 posts
    Registered:
    14 Sep 2016
    08 Dec 2019 in reply to Roger Blanchard
    Link to this post
    Where exactly is the above code used? 

    On the client? On the AppServer? 

    And what's happening in those methods:

                      (NEW Osprey.PointOfSale.PosTransaction.UpdateGeneralTotal (oTransactionTotals)):PerformDBUpdate (DATASET dsPosTransaction BY-REFERENCE,
                                                                                                                       oGeneralTotal
                                                                                                                   ).

    As a client (and AppServer agent/session) cannot lock records against itself, there must be a second client involved somewhere. 

    A "classical" issue in an environment where an AppServer client and AppServer agent/session are both processing records might be that those two processes lock records from each other. That fact that the AppServer serves a request from a certain client does not make any exception. 

    May that be part of your problem? 
  3. Roger Blanchard
    Roger Blanchard avatar
    413 posts
    Registered:
    29 Jun 2018
    08 Dec 2019 in reply to Mike Fechner
    Link to this post
    Its all server-side code. We are creating TT records from parsing our electronic journal and then we call the PerformDBUpdate in each class that will use the dataset model classes to update the DB.

    Yes, we have many clients sending requests to PASOE. We will have many POS devices in a store all sending POS transactions. I am sure it is a deadly embrace where each request is waiting on the other. After the lock wait timeout expires one request will throw the error and the other will finish just fine.

    As a test, I changed the code to use pessimistic locking and the issue goes away.



    FOR FIRST eGeneralTotal ON ERROR UNDO, THROW:
           
       // UPDATE CASHIER TOTALS FIRST
       
       poGeneralTotal:NewFilter(oTransactionTotals:PostingDate, // SaleDate
                                "D", // Period
                                oTransactionTotals:CashierNum, // CashierNum
                                ""  // RegNum
                                ).
                              
       poGeneralTotal:TrackingChanges = TRUE.  // enable TrackingChanges
       
       IF NOT poGeneralTotal:GeneralTotal:Available THEN // create if does not exist
       DO:
        poGeneralTotal:GeneralTotal:Create().
        poGeneralTotal:GeneralTotal:SaleDate   = oTransactionTotals:PostingDate.
        poGeneralTotal:GeneralTotal:Period    = "D".
        poGeneralTotal:GeneralTotal:CashierNum   = oTransactionTotals:CashierNum.
        poGeneralTotal:GeneralTotal:RegNum    = "". 
       END. 
       
       /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
        Now update existing fields with values from TT
       */
       
       ASSIGN
           /* let's save current values so we can pass to RulesEngine */
           iNumNoSales          = poGeneralTotal:GeneralTotal:NumNoSales
           iNumCancels          = poGeneralTotal:GeneralTotal:NumCancels
           iNumPrevCancels         = poGeneralTotal:GeneralTotal:NumPrevCancels
           iNumCusts          = poGeneralTotal:GeneralTotal:NumCusts
              poGeneralTotal:GeneralTotal:NumCusts            = poGeneralTotal:GeneralTotal:NumCusts         + eGeneralTotal.NumCusts
              poGeneralTotal:GeneralTotal:NumCustRtn   = poGeneralTotal:GeneralTotal:NumCustRtn            + eGeneralTotal.NumCustRtn
              poGeneralTotal:GeneralTotal:NumItemSold         = poGeneralTotal:GeneralTotal:NumItemSold      + eGeneralTotal.NumItemSold
              poGeneralTotal:GeneralTotal:NumNoSales          = poGeneralTotal:GeneralTotal:NumNoSales       + eGeneralTotal.NumNoSales
              poGeneralTotal:GeneralTotal:GrossSales          = poGeneralTotal:GeneralTotal:GrossSales       + eGeneralTotal.GrossSales
              poGeneralTotal:GeneralTotal:ARChange            = poGeneralTotal:GeneralTotal:ARChange         + eGeneralTotal.ARChange
              poGeneralTotal:GeneralTotal:Grandtotal          = poGeneralTotal:GeneralTotal:Grandtotal       + eGeneralTotal.Grandtotal
              poGeneralTotal:GeneralTotal:NonAddSales         = poGeneralTotal:GeneralTotal:NonAddSales      + eGeneralTotal.NonAddSales
              poGeneralTotal:GeneralTotal:NumCancels          = poGeneralTotal:GeneralTotal:NumCancels       + eGeneralTotal.NumCancels
              poGeneralTotal:GeneralTotal:CancelSaleAmt       = poGeneralTotal:GeneralTotal:CancelSaleAmt    + eGeneralTotal.CancelSaleAmt
              poGeneralTotal:GeneralTotal:NumItemEntry        = poGeneralTotal:GeneralTotal:NumItemEntry     + eGeneralTotal.NumItemEntry
              poGeneralTotal:GeneralTotal:NonTaxableSale      = poGeneralTotal:GeneralTotal:NonTaxableSale   + eGeneralTotal.NonTaxableSale
              poGeneralTotal:GeneralTotal:NumCreditTrans      = poGeneralTotal:GeneralTotal:NumCreditTrans   + eGeneralTotal.NumCreditTrans
              poGeneralTotal:GeneralTotal:CreditTransAmt      = poGeneralTotal:GeneralTotal:CreditTransAmt   + eGeneralTotal.CreditTransAmt
              poGeneralTotal:GeneralTotal:NumPrevCancels  = poGeneralTotal:GeneralTotal:NumPrevCancels   + eGeneralTotal.NumPrevCancels
              poGeneralTotal:GeneralTotal:PrevCancelSaleAmt = poGeneralTotal:GeneralTotal:PrevCancelSaleAmt  + eGeneralTotal.PrevCancelSaleAmt
              poGeneralTotal:GeneralTotal:DonorCnt   = poGeneralTotal:GeneralTotal:DonorCnt    + eGeneralTotal.DonorCnt
              poGeneralTotal:GeneralTotal:TrainingSaleCnt  = poGeneralTotal:GeneralTotal:TrainingSaleCnt  + eGeneralTotal.TrainingSaleCnt
              poGeneralTotal:GeneralTotal:SuspendedSaleCnt = poGeneralTotal:GeneralTotal:SuspendedSaleCnt  + eGeneralTotal.SuspendedSaleCnt
          NO-ERROR.
          
          poGeneralTotal:SaveChanges(). // save changes to the DB
          
          /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
           Call RuleEngine here. I am thinking turning RuleEngine into a service
           and load in Servicex.xml
       */
       
          // do we want to add a System Parameter to enable this? */
       // RulesEngine:Instance:CheckGeneralTotal(BUFFER GeneralTotal, iNumNoSales, iNumCancels, iNumPrevCancels, iNumCusts).
          
          /* now update monthly cashier totals */
          
       poGeneralTotal:NewFilter(oTransactionTotals:MonthEnd,
                                "M",
                                oTransactionTotals:CashierNum,
                                ""
                                ).
                              
       poGeneralTotal:TrackingChanges = TRUE. // enable TrackingChanges 
       
       IF NOT poGeneralTotal:GeneralTotal:Available THEN // create record if it does not already exist
       DO:
        poGeneralTotal:GeneralTotal:Create().
        poGeneralTotal:GeneralTotal:SaleDate   = oTransactionTotals:MonthEnd.
        poGeneralTotal:GeneralTotal:Period    = "M".
        poGeneralTotal:GeneralTotal:CashierNum   = oTransactionTotals:CashierNum.
        poGeneralTotal:GeneralTotal:RegNum    = "". 
       END. 
       
       /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
        Now update existing fields with values from TT
       */
       
       ASSIGN
              poGeneralTotal:GeneralTotal:NumCusts            = poGeneralTotal:GeneralTotal:NumCusts         + eGeneralTotal.NumCusts
              poGeneralTotal:GeneralTotal:NumCustRtn   = poGeneralTotal:GeneralTotal:NumCustRtn            + eGeneralTotal.NumCustRtn
              poGeneralTotal:GeneralTotal:NumItemSold         = poGeneralTotal:GeneralTotal:NumItemSold      + eGeneralTotal.NumItemSold
              poGeneralTotal:GeneralTotal:NumNoSales          = poGeneralTotal:GeneralTotal:NumNoSales       + eGeneralTotal.NumNoSales
              poGeneralTotal:GeneralTotal:GrossSales          = poGeneralTotal:GeneralTotal:GrossSales       + eGeneralTotal.GrossSales
              poGeneralTotal:GeneralTotal:ARChange            = poGeneralTotal:GeneralTotal:ARChange         + eGeneralTotal.ARChange
              poGeneralTotal:GeneralTotal:Grandtotal          = poGeneralTotal:GeneralTotal:Grandtotal       + eGeneralTotal.Grandtotal
              poGeneralTotal:GeneralTotal:NonAddSales         = poGeneralTotal:GeneralTotal:NonAddSales      + eGeneralTotal.NonAddSales
              poGeneralTotal:GeneralTotal:NumCancels          = poGeneralTotal:GeneralTotal:NumCancels       + eGeneralTotal.NumCancels
              poGeneralTotal:GeneralTotal:CancelSaleAmt       = poGeneralTotal:GeneralTotal:CancelSaleAmt    + eGeneralTotal.CancelSaleAmt
              poGeneralTotal:GeneralTotal:NumItemEntry        = poGeneralTotal:GeneralTotal:NumItemEntry     + eGeneralTotal.NumItemEntry
              poGeneralTotal:GeneralTotal:NonTaxableSale      = poGeneralTotal:GeneralTotal:NonTaxableSale   + eGeneralTotal.NonTaxableSale
              poGeneralTotal:GeneralTotal:NumCreditTrans      = poGeneralTotal:GeneralTotal:NumCreditTrans   + eGeneralTotal.NumCreditTrans
              poGeneralTotal:GeneralTotal:CreditTransAmt      = poGeneralTotal:GeneralTotal:CreditTransAmt   + eGeneralTotal.CreditTransAmt
              poGeneralTotal:GeneralTotal:NumPrevCancels  = poGeneralTotal:GeneralTotal:NumPrevCancels   + eGeneralTotal.NumPrevCancels
              poGeneralTotal:GeneralTotal:PrevCancelSaleAmt = poGeneralTotal:GeneralTotal:PrevCancelSaleAmt  + eGeneralTotal.PrevCancelSaleAmt
              poGeneralTotal:GeneralTotal:DonorCnt   = poGeneralTotal:GeneralTotal:DonorCnt    + eGeneralTotal.DonorCnt
              poGeneralTotal:GeneralTotal:TrainingSaleCnt  = poGeneralTotal:GeneralTotal:TrainingSaleCnt  + eGeneralTotal.TrainingSaleCnt
              poGeneralTotal:GeneralTotal:SuspendedSaleCnt = poGeneralTotal:GeneralTotal:SuspendedSaleCnt  + eGeneralTotal.SuspendedSaleCnt
          NO-ERROR.
          
          poGeneralTotal:SaveChanges(). // save changes to the DB
          
          
          // NOW UPDATE REGISTER TOTALS
          
       
       poGeneralTotal:NewFilter(oTransactionTotals:PostingDate,
                                "D",
                                0,
                                oTransactionTotals:RegNum
                                ).
                              
       poGeneralTotal:TrackingChanges = TRUE.  // enable TrackingChanges
       
       IF NOT poGeneralTotal:GeneralTotal:Available THEN // create if does not exist
       DO:
        poGeneralTotal:GeneralTotal:Create().
        poGeneralTotal:GeneralTotal:SaleDate   = oTransactionTotals:PostingDate.
        poGeneralTotal:GeneralTotal:Period    = "D".
        poGeneralTotal:GeneralTotal:CashierNum   = 0.
        poGeneralTotal:GeneralTotal:RegNum    = oTransactionTotals:RegNum.  
       END. 
       
       /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
        Now update existing fields with values from TT
       */
       
       ASSIGN
              poGeneralTotal:GeneralTotal:NumCusts            = poGeneralTotal:GeneralTotal:NumCusts         + eGeneralTotal.NumCusts
              poGeneralTotal:GeneralTotal:NumCustRtn   = poGeneralTotal:GeneralTotal:NumCustRtn            + eGeneralTotal.NumCustRtn
              poGeneralTotal:GeneralTotal:NumItemSold         = poGeneralTotal:GeneralTotal:NumItemSold      + eGeneralTotal.NumItemSold
              poGeneralTotal:GeneralTotal:NumNoSales          = poGeneralTotal:GeneralTotal:NumNoSales       + eGeneralTotal.NumNoSales
              poGeneralTotal:GeneralTotal:GrossSales          = poGeneralTotal:GeneralTotal:GrossSales       + eGeneralTotal.GrossSales
              poGeneralTotal:GeneralTotal:ARChange            = poGeneralTotal:GeneralTotal:ARChange         + eGeneralTotal.ARChange
              poGeneralTotal:GeneralTotal:Grandtotal          = poGeneralTotal:GeneralTotal:Grandtotal       + eGeneralTotal.Grandtotal
              poGeneralTotal:GeneralTotal:NonAddSales         = poGeneralTotal:GeneralTotal:NonAddSales      + eGeneralTotal.NonAddSales
              poGeneralTotal:GeneralTotal:NumCancels          = poGeneralTotal:GeneralTotal:NumCancels       + eGeneralTotal.NumCancels
              poGeneralTotal:GeneralTotal:CancelSaleAmt       = poGeneralTotal:GeneralTotal:CancelSaleAmt    + eGeneralTotal.CancelSaleAmt
              poGeneralTotal:GeneralTotal:NumItemEntry        = poGeneralTotal:GeneralTotal:NumItemEntry     + eGeneralTotal.NumItemEntry
              poGeneralTotal:GeneralTotal:NonTaxableSale      = poGeneralTotal:GeneralTotal:NonTaxableSale   + eGeneralTotal.NonTaxableSale
              poGeneralTotal:GeneralTotal:NumCreditTrans      = poGeneralTotal:GeneralTotal:NumCreditTrans   + eGeneralTotal.NumCreditTrans
              poGeneralTotal:GeneralTotal:CreditTransAmt      = poGeneralTotal:GeneralTotal:CreditTransAmt   + eGeneralTotal.CreditTransAmt
              poGeneralTotal:GeneralTotal:NumPrevCancels  = poGeneralTotal:GeneralTotal:NumPrevCancels   + eGeneralTotal.NumPrevCancels
              poGeneralTotal:GeneralTotal:PrevCancelSaleAmt = poGeneralTotal:GeneralTotal:PrevCancelSaleAmt  + eGeneralTotal.PrevCancelSaleAmt
              poGeneralTotal:GeneralTotal:DonorCnt   = poGeneralTotal:GeneralTotal:DonorCnt    + eGeneralTotal.DonorCnt
              poGeneralTotal:GeneralTotal:TrainingSaleCnt  = poGeneralTotal:GeneralTotal:TrainingSaleCnt  + eGeneralTotal.TrainingSaleCnt
              poGeneralTotal:GeneralTotal:SuspendedSaleCnt = poGeneralTotal:GeneralTotal:SuspendedSaleCnt  + eGeneralTotal.SuspendedSaleCnt
          NO-ERROR.
          
          poGeneralTotal:SaveChanges(). // save changes to the DB
          
          /* now update monthly register totals */
       
       
       poGeneralTotal:NewFilter(oTransactionTotals:MonthEnd,
                                "M",
                                0,
                                oTransactionTotals:RegNum
                                ).
                              
       poGeneralTotal:TrackingChanges = TRUE. // enable TrackingChanges 
       
       IF NOT poGeneralTotal:GeneralTotal:Available THEN // create record if it does not already exist
       DO:
        poGeneralTotal:GeneralTotal:Create().
        poGeneralTotal:GeneralTotal:SaleDate   = oTransactionTotals:MonthEnd.
        poGeneralTotal:GeneralTotal:Period    = "M".
        poGeneralTotal:GeneralTotal:CashierNum   = 0.
        poGeneralTotal:GeneralTotal:RegNum    = oTransactionTotals:RegNum. 
       END. 
       
       /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
        Now update existing fields with values from TT
       */
       
       ASSIGN
              poGeneralTotal:GeneralTotal:NumCusts            = poGeneralTotal:GeneralTotal:NumCusts         + eGeneralTotal.NumCusts
              poGeneralTotal:GeneralTotal:NumCustRtn   = poGeneralTotal:GeneralTotal:NumCustRtn            + eGeneralTotal.NumCustRtn
              poGeneralTotal:GeneralTotal:NumItemSold         = poGeneralTotal:GeneralTotal:NumItemSold      + eGeneralTotal.NumItemSold
              poGeneralTotal:GeneralTotal:NumNoSales          = poGeneralTotal:GeneralTotal:NumNoSales       + eGeneralTotal.NumNoSales
              poGeneralTotal:GeneralTotal:GrossSales          = poGeneralTotal:GeneralTotal:GrossSales       + eGeneralTotal.GrossSales
              poGeneralTotal:GeneralTotal:ARChange            = poGeneralTotal:GeneralTotal:ARChange         + eGeneralTotal.ARChange
              poGeneralTotal:GeneralTotal:Grandtotal          = poGeneralTotal:GeneralTotal:Grandtotal       + eGeneralTotal.Grandtotal
              poGeneralTotal:GeneralTotal:NonAddSales         = poGeneralTotal:GeneralTotal:NonAddSales      + eGeneralTotal.NonAddSales
              poGeneralTotal:GeneralTotal:NumCancels          = poGeneralTotal:GeneralTotal:NumCancels       + eGeneralTotal.NumCancels
              poGeneralTotal:GeneralTotal:CancelSaleAmt       = poGeneralTotal:GeneralTotal:CancelSaleAmt    + eGeneralTotal.CancelSaleAmt
              poGeneralTotal:GeneralTotal:NumItemEntry        = poGeneralTotal:GeneralTotal:NumItemEntry     + eGeneralTotal.NumItemEntry
              poGeneralTotal:GeneralTotal:NonTaxableSale      = poGeneralTotal:GeneralTotal:NonTaxableSale   + eGeneralTotal.NonTaxableSale
              poGeneralTotal:GeneralTotal:NumCreditTrans      = poGeneralTotal:GeneralTotal:NumCreditTrans   + eGeneralTotal.NumCreditTrans
              poGeneralTotal:GeneralTotal:CreditTransAmt      = poGeneralTotal:GeneralTotal:CreditTransAmt   + eGeneralTotal.CreditTransAmt
              poGeneralTotal:GeneralTotal:NumPrevCancels  = poGeneralTotal:GeneralTotal:NumPrevCancels   + eGeneralTotal.NumPrevCancels
              poGeneralTotal:GeneralTotal:PrevCancelSaleAmt = poGeneralTotal:GeneralTotal:PrevCancelSaleAmt  + eGeneralTotal.PrevCancelSaleAmt
              poGeneralTotal:GeneralTotal:DonorCnt   = poGeneralTotal:GeneralTotal:DonorCnt    + eGeneralTotal.DonorCnt
              poGeneralTotal:GeneralTotal:TrainingSaleCnt  = poGeneralTotal:GeneralTotal:TrainingSaleCnt  + eGeneralTotal.TrainingSaleCnt
              poGeneralTotal:GeneralTotal:SuspendedSaleCnt = poGeneralTotal:GeneralTotal:SuspendedSaleCnt  + eGeneralTotal.SuspendedSaleCnt
          NO-ERROR.
          
          poGeneralTotal:SaveChanges(). // save changes to the DB
          
          THIS-OBJECT:UpdateZipCodeTotal(poGeneralTotal). // UPDATE our ZipCodeTotal table as well
          THIS-OBJECT:UpdateProductivityTotal(poGeneralTotal). // update our Productivitytotal table as well
       THIS-OBJECT:UpdateActiveCashier(poGeneralTotal). // update ActiveCashier record 
       THIS-OBJECT:UpdateCashierReconcil(poGeneralTotal). // update CashierReconcil reocrd
       
          /* Roger Blanchard / Osprey Retail Systems Apr 3, 2019
           Log any error here and then throw to caller 
          */
          CATCH e AS Progress.Lang.Error:
        LogManagerWrapper:WriteError(e).
        UNDO, THROW e.
       END CATCH.
       
      END.
3 posts, 0 answered