From 019817d6dc3dcc24512f88eaeef58b0476bf6a58 Mon Sep 17 00:00:00 2001 From: liuwenxin <1009266660@qq.com> Date: Mon, 2 Nov 2026 09:42:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E5=B7=A5=E8=B5=84=E6=A0=B8=E7=AE=97):=20?= =?UTF-8?q?=E6=8E=92=E9=99=A4=E8=B5=B7=E4=BB=98=E6=AF=94=E4=BE=8B=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E5=8E=86=E5=8F=B2=E5=8F=91=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 旧应收已经由期初余额承接,启用前发货再次进入分母, 会使新业务足额回款仍未达到起付门槛。 将销售额日期范围与 FIFO 的启用边界保持一致, 补充普通历史日期及二月末的两项回归用例。 --- backend/app/services/payroll_calculation.py | 6 ++- backend/tests/unit/test_formal_payroll.py | 56 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/backend/app/services/payroll_calculation.py b/backend/app/services/payroll_calculation.py index 96e3ba8..e46f398 100644 --- a/backend/app/services/payroll_calculation.py +++ b/backend/app/services/payroll_calculation.py @@ -25,7 +25,7 @@ from app.services import audit_service, formula, payroll_months from app.services.audit_service import AuditRecord from app.services.param_service import resolve_snapshot from app.services.tplus.calculation_preview import _parameters -from app.services.tplus.fifo import _beneficiary, amount_text, money, preview_group +from app.services.tplus.fifo import START, _beneficiary, amount_text, money, preview_group from app.services.tplus.workbench import digest @@ -308,11 +308,13 @@ def _calculate_month(session, business, record, month, reason=None): } if set(previous) - current.keys(): raise BadRequestError("历史已核算事件发生变化,请核对更正或调整,不可直接覆盖") + # 启用前的发货由期初应收承接,不再进入新业务的起付比例分母。 sales = sum( ( money(s["amount"]) for s in values["shipments"] - if s["date"] <= until.isoformat() and not s.get("performance_excluded") + if START.isoformat() <= s["date"] <= until.isoformat() + and not s.get("performance_excluded") ), Decimal(0), ) diff --git a/backend/tests/unit/test_formal_payroll.py b/backend/tests/unit/test_formal_payroll.py index 0531c1f..01f65ab 100644 --- a/backend/tests/unit/test_formal_payroll.py +++ b/backend/tests/unit/test_formal_payroll.py @@ -22,6 +22,7 @@ from app.models import ( Personnel, Product, Receipt, + Shipment, ShipmentItem, TPlusSourceLink, TPlusWorkRun, @@ -268,6 +269,61 @@ def test_起付百分之六十与平方权重(payroll_case, amount, performance, ) +@pytest.mark.parametrize("legacy_date", [date(2026, 2, 10), date(2026, 2, 28)]) +def test_历史发货不重复计入新业务起付分母(payroll_case, legacy_date): + """旧应收先冲抵,启用前发货不得再次压低新业务的回款比例。""" + s, user, _ = payroll_case + business = imported(payroll_case) + record = payroll_calculation.latest_input(s, business.id) + data = copy.deepcopy(record.data_json) + legacy = Shipment( + business_id=business.id, + shipment_no="SH-LEGACY", + ship_date=legacy_date, + total_amount=Decimal("100"), + freight_amount=Decimal("0"), + ) + s.add(legacy) + s.flush() + original = s.get(ShipmentItem, data["maps"]["shipment_items"][data["shipments"][0]["line_id"]]) + item = ShipmentItem( + shipment_id=legacy.id, + product_id=original.product_id, + product_name=original.product_name, + spec_model=original.spec_model, + unit=original.unit, + quantity=Decimal("2"), + sale_price=Decimal("50"), + amount=Decimal("100"), + ) + s.add(item) + s.flush() + data["shipments"].append( + { + **data["shipments"][0], + "source_id": "99", + "line_id": "99", + "date": legacy_date.isoformat(), + } + ) + data["maps"]["shipments"]["99"] = legacy.id + data["maps"]["shipment_items"]["99"] = item.id + data["group"]["opening_balance"] = "100" + data["receipts"][0]["amount"] = "200" + s.get(Receipt, data["maps"]["receipts"][data["receipts"][0]["source_id"]]).amount = Decimal( + "200" + ) + replace_input(s, record, data) + + result = payroll_calculation.calculate(s, business.id, "2026-03", operator=user) + + assert result["start_payment_ok"] is True + assert result["performance"] == result["payable"] == "0.20" + allocations = list(s.scalars(select(PayrollAllocation))) + assert sum(row.amount for row in allocations) == Decimal("100.00") + assert all(row.data_json["shipment_date"] == "2026-03-10" for row in allocations) + + def test_跨月续算仅计应付差额且离职未发给接手人(payroll_case): s, user, _manager = payroll_case business = imported(payroll_case)