project QadFinancials > class BPaymentSelection > method SplitSupplierInvoice

Description

Split the PaySelLine to batches by Supplier Code ,Currency, Min & Max Batch size(SysProperty).


Parameters


oiReturnStatusoutputintegerReturn status of the method.


Internal usage


QadFinancials
method BPaymentSelection.ChangeStatusPaymentSelInBatch


program code (program1/bpaymentselection.p)

/* ===================================================================================================================== */
/* Assign GroupUnionType to each PaySelLine: the combination of CreditorCode, InvoiceCurrencyCode and PayFormatTypeCode. */
/* ===================================================================================================================== */
for each tPaySelLine:
    define variable i as integer no-undo.

    assign tPaySelLine.tcGroupUnionType = tPaySelLine.tcGroupUnionType + tPaySelLine.tcCreditorCode.
    if length(tPaySelLine.tcCreditorCode, "CHARACTER") < 8 then
    do:
        viAddSpaceNum = 8 - length(tPaySelLine.tcCreditorCode, "CHARACTER").
        repeat i = 1 to viAddSpaceNum:
            assign tPaySelLine.tcGroupUnionType = tPaySelLine.tcGroupUnionType + " ".
        end. 
    end.

    assign tPaySelLine.tcGroupUnionType = tPaySelLine.tcGroupUnionType + tPaySelLine.tcInvoiceCurrencyCode.
    if length(tPaySelLine.tcInvoiceCurrencyCode, "CHARACTER") < 3 then
    do:
        viAddSpaceNum = 3 - length(tPaySelLine.tcInvoiceCurrencyCode, "CHARACTER").
        repeat i = 1 to viAddSpaceNum:
            assign tPaySelLine.tcGroupUnionType = tPaySelLine.tcGroupUnionType + " ".
        end. 
    end.

    assign tPaySelLine.tcGroupUnionType = tPaySelLine.tcGroupUnionType + tPaySelLine.PayFormatTypeCode.
    if length(tPaySelLine.PayFormatTypeCode, "CHARACTER") < 20 then
    do:
        viAddSpaceNum = 20 - length(tPaySelLine.tcCreditorCode, "CHARACTER").
        repeat i = 1 to viAddSpaceNum:
            assign tPaySelLine.tcGroupUnionType = tPaySelLine.tcGroupUnionType + " ".
        end. 
    end.
    
end.

empty temp-table tPaySelLineDS.

/* ================================================== */
/* Copy tPaySelLine to tPaySelLineDS for modification. */
/* ================================================== */
assign viGroupLinesCnt = 0.
for each tPaySelLine where tPaySelLine.PaySelLineIsConfirmed <> yes 
    break by tPaySelLine.tcGroupUnionType by tPaySelLine.PaySelLineParentObject_ID:
    viGroupLinesCnt = viGroupLinesCnt + 1.
    create tPaySelLineDS.
    assign tPaySelLineDS.tibMaster_ID = viGroupLinesCnt
           tPaySelLineDS.tibPaySel_ID = tPaySelLine.PaySel_ID
           tPaySelLineDS.tibPaySelLine_ID = tPaySelLine.PaySelLine_ID
           tPaySelLineDS.tcbGroupUnionType = tPaySelLine.tcGroupUnionType
           tPaySelLineDS.tdbPaySelLineAmountTC = 0 - tPaySelLine.tdInvoiceBalanceTCSigned
           tPaySelLineDS.tibPaySelLineParentObject_ID = tPaySelLine.PaySelLineParentObject_ID.
end.

/* ========================================================================================================= */
/* Group PaySelLine by GroupUnionType. Assign GroupID and calculate the number of PaySelLine for each group. */
/* ========================================================================================================= */
empty temp-table tInvoiceGroup.
assign viGroupNum = 1.

for each tPaySelLine where tPaySelLine.PaySelLineIsConfirmed <> yes
    break by tPaySelLine.tcGroupUnionType:
    if first-of(tPaySelLine.tcGroupUnionType) then
    do:
        viGroupLinesCnt = 0.
        for each tPaySelLineDS where tPaySelLineDS.tcbGroupUnionType = tPaySelLine.tcGroupUnionType:
            viGroupLinesCnt = viGroupLinesCnt + 1.
        end.
        create tInvoiceGroup.
        assign tInvoiceGroup.tiGroupID = viGroupNum * 10000
               tInvoiceGroup.tiGroupLinesCnt = viGroupLinesCnt.
        viGroupNum = viGroupNum + 1.
    end.
end.

assign viBatchCnt = 0
       viCurrInvoiceGroupID = 0.
 
/* ============ */  
/* Output table */
/* ============ */  
empty temp-table tSupplierInvoiceGroups. 

/* ======================================================================================================================= */
/* BatchLoop is the main loop that keeps on fetching the next available group as the current group and starts a new batch. */
/* By BatchLoop, we split groups into small batches whose sizes are possibly fallen between MinBatchSize and MaxBatchSize. */
/* ======================================================================================================================= */
BatchLoop:
Do while true:
    assign viBatchCnt = viBatchCnt + 1    /* At the beginning of main loop, increase the batch count viBatchCnt and start a new batch. */
           viBatchLinesCnt = 0            /* The new batch has 0 lines. */
           vlStartNextBatch = false       /* No need to start next batch because the new batch is not filled yet. */
           vdTotalAmount = 0.             /* vdTotalAmount is a decimal to calculate the amount of several PaySelLines. */

    Do while true:
        assign vlGroupFound = false.      /* vlGroupFound is a flag to show if there is a next group available in the order of GroupIndex. */
         /* If there exists a next group, assign its ID and size to viCurrInvoiceGroupID and viCurrInvoiceGroupLinesCnt  */
        for first tInvoiceGroup where tInvoiceGroup.tiGroupID > viCurrInvoiceGroupID use-index GroupIndex: 
            assign viCurrInvoiceGroupID = tInvoiceGroup.tiGroupID
                   viCurrInvoiceGroupLinesCnt = tInvoiceGroup.tiGroupLinesCnt.
            vlGroupFound = true.               
        end.
        if vlGroupFound = false then do: /* If there is no available group, the main loop ends and splitting is over. */
            leave BatchLoop.
        end.
        if viCurrInvoiceGroupLinesCnt = 0 then next.            /* If the group found is empty
, go and find next available group. */
        
        /* If current group is added, current batch size will be less than or equal to MaxBatchSize */
        if viBatchLinesCnt + viCurrInvoiceGroupLinesCnt <= viMaxBatchSize then 
        do:
            find tInvoiceGroup where tInvoiceGroup.tiGroupID = viCurrInvoiceGroupID.
                assign tInvoiceGroup.tiBatchNum = viBatchCnt.
                assign viBatchLinesCnt = viBatchLinesCnt + viCurrInvoiceGroupLinesCnt.
         
            for each tPaySelLineDS where tPaySelLineDS.tibMaster_ID > viTotalLinesCnt and tPaySelLineDS.tibMaster_ID <= viTotalLinesCnt + viCurrInvoiceGroupLinesCnt
                break by tPaySelLineDS.tcbGroupUnionType:
                create tSupplierInvoiceGroups.
                    assign tSupplierInvoiceGroups.tiPaySel_ID = tPaySelLineDS.tibPaySel_ID
                           tSupplierInvoiceGroups.tiPaymentSelectionLineID = tPaySelLineDS.tibPaySelLine_ID
                           tSupplierInvoiceGroups.tiGroupNumber = viBatchCnt
                           tSupplierInvoiceGroups.tiPaySelLineParentObject_ID = tPaySelLineDS.tibPaySelLineParentObject_ID.
            end.
             
            viTotalLinesCnt = viTotalLinesCnt + viCurrInvoiceGroupLinesCnt.
        end.
        
        /* Current group is a single group whose size is greater than MaxBatchSize. Or if current group is added, current batch size will exceed MaxBatchSize. */
        else 
        do:
            if viBatchLinesCnt + viCurrInvoiceGroupLinesCnt > viMaxBatchSize then
            do:
                if vlStartNextBatch = true then   /* vlStartNextBatch indicates the necessity of start a new batch. */
                do:
                    assign  viCurrInvoiceGroupID = viCurrInvoiceGroupID - 1.
                    next BatchLoop.
                end.
                
                 /* Fetch the current group. */    
                find tInvoiceGroup where tInvoiceGroup.tiGroupID = viCurrInvoiceGroupID.
                if viBatchLinesCnt = 0 then do:   /* A single group size larger than MaxBatchSize */
                    /* Check if the group is divisible. */
                    vdTotalAmount = 0.
                    for each tPaySelLineDS where tPaySelLineDS.tibMaster_ID > viTotalLinesCnt and tPaySelLineDS.tibMaster_ID <= viTotalLinesCnt + viCurrInvoiceGroupLinesCnt
                        break by tPaySelLineDS.tcbGroupUnionType:
                        vdTotalAmount = vdTotalAmount + tPaySelLineDS.tdbPaySelLineAmountTC.
                        viCount = viCount + 1.
                        if viCount modulo viMaxBatchSize = 0 or viCount = viCurrInvoiceGroupLinesCnt then do:
                            if vdTotalAmount < 0 then do:
                                vlSplitable = false.
                                leave.
                            end.
                            else do:
                                vdTotalAmount = 0.
                            end.          
                        end.
                    end.                    
                        
                    /* If not divisible, the whole group is assigned to one batch, then start next main loop. */
                    if not vlSplitable then do:
                        for each tPaySelLineDS where tPaySelLineDS.tibMaster_ID > viTotalLinesCnt and tPaySelLineDS.tibMaster_ID <= viTotalLinesCnt + viCurrInvoiceGroupLinesCnt
                            break by tPaySelLineDS.tcbGroupUnionType:
                            create tSupplierInvoiceGroups.
                                assign tSupplierInvoiceGroups.tiPaySel_ID = tPaySelLineDS.tibPaySel_ID
                                       tSupplierInvoiceGroups.tiPaymentSelectionLineID = tPaySelLineDS.tibPaySelLine_ID
                                       tSupplierInvoiceGroups.tiGroupNumber = viBatchCnt
                                       tSupplierInvoiceGroups.tiPaySelLineParentObject_ID = tPaySelLineDS.tibPaySelLineParentObject_ID.
                        end. 
    
                        viTotalLinesCnt = viTotalLinesCnt + viCurrInvoiceGroupLinesCnt.
                        next BatchLoop.
                    end.
                end.
                else do:   /* Current batch size + curent group size exceeds MaxBatchSize, try to split the group. */               
                    /* Check if the amount of first (viMaxBatchSize - viBatchLinesCnt) PaySelLines is > 0 after merge. If not, cancel the merge. */
                    vdTotalAmount = 0.
                    viStartLine = viTotalLinesCnt.
                    viUsedLines = viCurrInvoiceGroupLinesCnt.
                    for each tPaySelLineDS where tPaySelLineDS.tibMaster_ID > viStartLine and tPaySelLineDS.tibMaster_ID <= viStartLine + viUsedLines
                        break by tPaySelLineDS.tcbGroupUnionType:
                        vdTotalAmount = vdTotalAmount + tPaySelLineDS.tdbPaySelLineAmountTC.
                    end.

                    if vdTotalAmount < 0 then do:
                        viCurrInvoiceGroupID = viCurrInvoiceGroupID - 1.
                        next BatchLoop.
                    end.

                    /* Check if the amount of the remainder is still > 0. If not, cancel the merge. */
                    vdTotalAmount = 0.
                    viStartLine = viTotalLinesCnt - viBatchLinesCnt + viMaxBatchSize.
                    viUsedLines = viCurrInvoiceGroupLinesCnt - viMaxBatchSize + viBatchLinesCnt.
                    for each tPaySelLineDS where tPaySelLineDS.tibMaster_ID > viStartLine and tPaySelLineDS.tibMaster_ID <= viStartLine + viUsedLines
                        break by tPaySelLineDS.tcbGroupUnionType:
                        vdTotalAmount = vdTotalAmount + tPaySelLineDS.tdbPaySelLineAmountTC.
                    end.
             
                    if vdTotalAmount < 0 then do:
                        viCurrInvoiceGroupID = viCurrInvoiceGroupID - 1.
                        next BatchLoop.
                    end.           
                end.
   
                /* After split, assign first (viMaxBatchSize - viBatchLinesCnt) PaySelLines in current group to this batch. */
                assign tInvoiceGroup.tiBatchNum = viBatchCnt
                       tInvoiceGroup.tiGroupLinesCnt = viMaxBatchSize - viBatchLinesCnt.
    
                for each tPaySelLineDS where tPaySelLineDS.tibMaster_ID > viTotalLinesCnt and tPaySelLineDS.tibMaster_ID <= viTotalLinesCnt + tInvoiceGroup.tiGroupLinesCnt
                    break by tPaySelLineDS.tcbGroupUnionType:
                    create tSupplierInvoiceGroups.
                        assign tSupplierInvoiceGroups.tiPaySel_ID = tPaySelLineDS.tibPaySel_ID
                               tSupplierInvoiceGroups.tiPaymentSelectionLineID = tPaySelLineDS.tibPaySelLine_ID
                               tSupplierInvoiceGroups.tiGroupNumber = viBatchCnt
                               tSupplierInvoiceGroups.tiPaySelLineParentObject_ID = tPaySelLineDS.tibPaySelLineParentObject_ID.
                end.
   
                viTotalLinesCnt = viTotalLinesCnt + tInvoiceGroup.tiGroupLinesCnt.
                
                /* Insert a new group with size of the remainder right after the current group. */
                create tInvoiceGroup.
                    assign tInvoiceGroup.tiGroupID = viCurrInvoiceGroupID + 1
                           tInvoiceGroup.tiGroupLinesCnt = viBatchLinesCnt + viCurrInvoiceGroupLinesCnt - viMaxBatchSize.
    
                next BatchLoop. /* Start next batch */
           end.
       end.
     
       /* When current batch size reach MinBatchSize, it is OK to start a new batch. As the loop goes to next group,   */
       /* if that group’s + current batch size exceeds MaxBatchSize, it will goes to the ELSE block and first check if */
       /* vlStartNextBatch is true. If true, go to next batch loop and start a new batch.                              */
       if viBatchLinesCnt >= viMinBatchSize then 
           assign vlStartNextBatch = true.
    end.  /* Next invoiceGroup */
end.  /* Next batchLoop */ 

/* Pull the payment selection line of the same invoice into one batch */
for each tSupplierInvoiceGroups 
    break by tSupplierInvoiceGroups.tiGroupNumber
          by tSupplierInvoiceGroups.tiPaySelLineParentObject_ID:
    if last-of(tSupplierInvoiceGroups.tiPaySelLineParentObject_ID) then
    do:
        for each bSupplierInvoiceGroups 
            where bSupplierInvoiceGroups.tiGroupNumber > tSupplierInvoiceGroups.tiGroupNumber and
                  bSupplierInvoiceGroups.tiPaySelLineParentObject_ID = tSupplierInvoiceGroups.tiPaySelLineParentObject_ID:
            bSupplierInvoiceGroups.tiGroupNumber = tSupplierInvoiceGroups.tiGroupNumber.
        end.
    end.
end.

/* Group Number Desc */
for last tSupplierInvoiceGroups by tSupplierInvoiceGroups.tiGroupNumber:
    viMaxGroupNbr = tSupplierInvoiceGroups.tiGroupNumber.
end.

for each tSupplierInvoiceGroups by tSupplierInvoiceGroups.tiPaymentSelectionLineID:
    viNewGroupNbr = viMaxGroupNbr - tSupplierInvoiceGroups.tiGroupNumber + 1.
    assign tSupplierInvoiceGroups.tiGroupNumber = viNewGroupNbr.
end.