簡體   English   中英

信用卡費用子集的遞歸批量對帳

[英]recursive batch reconciliation of a subset of credit card charges

我找到了一個解決方案 ,請參見下面的答案和/或具有新的優化功能的Github Gist

我有一系列的信用卡費用和一批總金額...有時金額的SUM()=批總金額,因此很容易歸為一批,我們可以核對當天存入的交易支票帳戶。

有時,適當的金額是這些費用中的一部分,第二天將分批支付1或更多。 您會以編程方式幫助我解決這個問題嗎? 這是給我的authorize.net批處理記帳的,很麻煩,所以我正在為簿記員制作工具。

+------------+--------+
| transId    | amount |
+------------+--------+
| 2863996511 | 154.00 |
| 2863992361 | 762.20 |
| 2863898975 |  49.00 |
| 2863894564 |   5.44 |
| 2863879671 |  10.88 |
| 2863858891 | 209.00 |
| 2863856334 | 148.00 |
| 2863367273 | -25.01 |
+------------+--------+

當天的總批量為$ 1302.63。 經常發生的是,電荷並沒有最終出現在該批次中,因此該批次是陣列中電荷總和的一部分。 在這種情況下,$ 10.88的費用是在第二天的批次中。 這一點偽代碼可以通過兩個嵌套的for循環來捕獲:

        for( $skipdx=0; $skipdx<$size; $skipdx++){
            $total=0;
            for( $idx=0; $idx<$size; $idx++){
                if($idx!=$skipdx){
                    $total+=$charges[$idx]['amount'];
                    $thisBatch[]=$charges[$idx]['transId'];
                }
                if( abs($total-$batch['total']) < .04 ) {
                    echo "sum of charges matches $date batch total: $$total  (line: ". __LINE__ .")\n";
                    $foundIt=TRUE;
                    break;
                }
            }
            if($foundIt==TRUE)
                break;
        }

如何動態選擇搜索未添加兩個費用的費用? 那三點 我可以看到,如果$skipdx省略了一個費用,則跳過兩個費用將添加一個skip2dx嵌套循環。 如果仍然找不到,則skip3dx將是嵌套的第3級。

我通常非常擅長算法,直到遞歸為止,然后我變得愚蠢。

它來找我! 遞歸的“當前層”執行以下操作:

  1. 總計費用金額。
  2. 遍歷整個電荷陣列,一次減去1個電荷,並對照目標批次進行測試。
  3. 如果該次迭代中的金額匹配,請取消設置此費用的ID,然后返回結果數組。
  4. 如果未找到,則這次再次遍歷電荷陣列,以除去當前電荷。 再次以相同的目標數量調用函數,並將新的縮短的數組再次調用相同的函數。

工作代碼( Github也有更新的優化 ):

$charges=Array(
     '2863996511' => 154.00 ,'2863879671' => 10.88
    ,'2863992361' => 762.20 ,'2863858891' => 209.00
    ,'2863898975' => 49.00  ,'2863856334' => 148.00
    ,'2863894564' => 5.44   ,'2863367273' => -25.01
); print_r($charges);
$targets=Array(1302.63, 1327.64, 1322.20 );
foreach( $targets as $batch ) {
    printf( "We seek combination of transIds to = $%-7.2f\n", $batch);
    $answer=reco( $batch, $charges );
    if( is_array($answer) )
        echo eval( "return ".implode("+",$answer).";" )."\nWIN!\n";
    else
        echo "Bust!\n";
}   

function reco( $target, $arr ){
    if( count($arr) < 2 )
        return FALSE;
    $killid='';
    $sum = eval( "return ".implode("+",$arr).";" );
    foreach( $arr as $id=>$amt ){
        if( abs($sum-$target-$amt) < .01 ) {
            $killid=$id;
            break;
        }
    }
    if( strlen($killid) > 1 ) {
        echo ".  omit $killid : ".$arr[$killid]."\n";
        unset($arr[$killid]); 
        return $arr;
    }
    foreach( $arr as $id=>$amt ){
        $tmp=$arr;
        unset($tmp[$id]);
        $rtn = reco( $target, $tmp );
        if( is_array($rtn) ) {
            echo ".. omit $id : ".$arr[$id]."\n";
            return $rtn;
        }
    }
    return FALSE;
}

並輸出:

We seek combination of transIds to = $1302.63
. omit 2863879671 : 10.88
1302.63
WIN!
We seek combination of transIds to = $1327.64
. omit 2863367273 : -25.01
.. omit 2863879671 : 10.88
1327.64
WIN!
We seek combination of transIds to = $1322.20
. omit 2863367273 : -25.01
.. omit 2863879671 : 10.88
.. omit 2863894564 : 5.44
1322.2
WIN!

性能不是一個大問題。 到第三級遞歸,大約需要一秒鍾。

當您開始查看費用集合的所有可能子集時,您可能會發現有時尋找與批次金額匹配的第一個子集並不是一個好的會計解決方案。 可能有幾個可能的費用子集加起來總計為批次。

你會選哪一個?

其實這會導致所謂的子集和問題一個眾所周知的問題-看維基這里

還有一個便宜的Excel加載項SumMatch ,它將查找與給定總和匹配的所有數字組合。 考慮一下是否值得您花一些時間來研究正確的算法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM