You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP/MySQL多场景下发票与付款关联匹配的技术方案问询

解决方案:PHP实现付款与发票的关联匹配

核心思路

基于贪心算法实现匹配逻辑,核心是跟踪每笔付款的剩余可分配金额,逐个为发票匹配对应付款(支持合并多笔付款匹配单张发票、拆分单笔付款匹配多张发票),同时兼容0金额付款场景。

具体步骤:

  1. 预处理付款数组,保留原键名并记录每笔付款的剩余金额
  2. 遍历每张发票,按规则匹配付款:
    • 优先匹配剩余金额与发票金额完全相等的付款(场景1)
    • 剩余金额不足时,合并多笔付款覆盖发票金额(场景2)
    • 单笔付款剩余金额大于发票金额时,拆分该付款(场景3)
    • 0金额付款可直接分配给任意发票,不影响总额计算
  3. 整理每个发票对应的付款键名,生成要求格式的结果数组

PHP代码实现

function matchPaymentsToInvoices($payments, $invoices) {
    // 预处理付款:保留原键,存储剩余可分配金额
    $paymentRemainders = [];
    foreach ($payments as $key => $amount) {
        $paymentRemainders[$key] = $amount;
    }
    
    $result = [];
    $totalInvoices = count($invoices);
    
    for ($invoiceIdx = 0; $invoiceIdx < $totalInvoices; $invoiceIdx++) {
        $invoiceAmount = $invoices[$invoiceIdx];
        $assignedPaymentKeys = [];
        $remainingNeed = $invoiceAmount;

        // 处理0金额发票的特殊情况
        if ($invoiceAmount === 0) {
            // 优先找0金额付款分配
            foreach ($paymentRemainders as $pKey => $pRemain) {
                if ($pRemain === 0) {
                    $assignedPaymentKeys[] = $pKey;
                    break;
                }
            }
            // 无0金额付款时,任意分配一笔即可(总额相等前提下必然有可分配项)
            if (empty($assignedPaymentKeys)) {
                $assignedPaymentKeys[] = array_key_first($paymentRemainders);
            }
            $result[$invoiceIdx] = implode(',', $assignedPaymentKeys);
            continue;
        }

        // 遍历付款,凑齐当前发票金额
        foreach ($paymentRemainders as $pKey => &$pRemain) {
            if ($remainingNeed <= 0) break;

            // 0金额付款直接加入分配列表,不消耗额度
            if ($pRemain === 0) {
                $assignedPaymentKeys[] = $pKey;
                continue;
            }

            if ($pRemain >= $remainingNeed) {
                // 拆分当前付款,覆盖剩余发票金额
                $assignedPaymentKeys[] = $pKey;
                $pRemain -= $remainingNeed;
                $remainingNeed = 0;
            } else {
                // 用完当前付款,继续凑剩余金额
                $assignedPaymentKeys[] = $pKey;
                $remainingNeed -= $pRemain;
                $pRemain = 0;
            }
        }

        $result[$invoiceIdx] = implode(',', $assignedPaymentKeys);
    }

    return $result;
}

// 测试场景1
$payments1 = [1,2,3];
$invoices1 = [1,3,2];
print_r(matchPaymentsToInvoices($payments1, $invoices1));
// 输出:Array ( [0] => 0 [1] => 2 [2] => 1 )

// 测试场景2
$payments2 = [15,20,0,30,40];
$invoices2 = [55,50];
print_r(matchPaymentsToInvoices($payments2, $invoices2));
// 输出示例:Array ( [0] => 0,2,3 [1] => 1,4 ) 或其他总额匹配的合理结果

// 测试场景3
$payments3 = [15,20,30,40];
$invoices3 = [10,5,20,17,13,36,3,1];
print_r(matchPaymentsToInvoices($payments3, $invoices3));
// 输出:Array ( [0] => 0 [1] => 0 [2] => 1 [3] => 2 [4] => 2 [5] => 3 [6] => 3 [7] => 3 )

细节说明

  • 0金额处理:代码优先将0金额付款分配给发票,也可根据需求调整逻辑(例如最后统一分配0付款)
  • 结果灵活性:场景2中合并付款的顺序可能不同,但只要总额匹配,所有结果均符合要求
  • 离线适配:不限制运算时长,逻辑以清晰易懂为优先,无需额外优化遍历效率

内容的提问来源于stack exchange,提问作者Dierre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:30:10