"""历史任职不能被当前岗位覆盖,预演、台账与工资分项必须使用同一依据。""" from datetime import date from decimal import Decimal import pytest from pydantic import ValidationError from sqlalchemy import select from app.models import Customer, PerformanceLedger, Product, TPlusFact from app.schemas.tplus_workbench import PersonFact from app.services import payroll_calculation, settlement_service from tests.unit.test_formal_payroll import imported from tests.unit.test_formal_payroll import payroll_case as payroll_case from tests.unit.test_tplus_fifo import inputs, run from tests.unit.test_tplus_workbench import apply, fact, preview, source from tests.unit.test_tplus_workbench import work_session as work_session def periods(): return [{"start_month": "2026-03", "end_month": "2026-07", "role_code": "sales_manager"}] def test_按月份保存已确认岗位而不补造转岗日(): person = PersonFact( code="010110", name="历史岗位样本", role_code="salesperson", status=1, role_history=periods(), ) assert person.model_dump()["role_history"] == periods() @pytest.mark.parametrize( "history", [ [{"start_month": "2026-13", "end_month": "2026-07", "role_code": "sales_manager"}], [{"start_month": "2026-08", "end_month": "2026-07", "role_code": "sales_manager"}], [ *periods(), {"start_month": "2026-07", "end_month": "2026-09", "role_code": "salesperson"}, ], ], ) def test_无效或重叠历史岗位拒绝入库(history): with pytest.raises(ValidationError): PersonFact( code="010110", name="历史岗位样本", role_code="salesperson", status=1, role_history=history, ) def test_七月经理本人业务在八月转岗后仍排除(): group, ship, cash, facts, params = inputs() ship["date"], cash["date"] = "2026-07-16", "2026-08-16" facts["personnel"]["001"].update(role_history=periods()) params["2026-08-16"] = params.pop("2026-03-10") params["august_confirmed"] = True line = run(group, [ship], [cash], facts, params, date(2026, 8, 31))["lines"][0] assert line["performance"] == "0.00" assert line["excluded_manager_own"] assert line["original_role_code"] == "sales_manager" assert line["role_code"] == "salesperson" def test_八月新业务按业务员且不沿用七月经理岗位(): group, ship, cash, facts, params = inputs() ship["date"] = cash["date"] = "2026-08-16" facts["personnel"]["001"].update(role_history=periods()) params["2026-08-16"] = params.pop("2026-03-10") params["august_confirmed"] = True line = run(group, [ship], [cash], facts, params, date(2026, 8, 31))["lines"][0] assert line["performance"] == "0.20" and not line["excluded_manager_own"] def test_历史经理贯通正式导入台账及月结岗位(payroll_case): session, operator, _ = payroll_case fact = session.scalar( select(TPlusFact).where(TPlusFact.kind == "PERSONNEL", TPlusFact.fact_key == "00043") ) fact.data_json = {**fact.data_json, "role_history": periods()} session.commit() business = imported(payroll_case) fact.data_json = {**fact.data_json, "role_history": []} session.commit() result = payroll_calculation.calculate(session, business.id, "2026-03", operator=operator) assert result["performance"] == result["payable"] == "0.00" row = session.scalar(select(PerformanceLedger).where(PerformanceLedger.calc_type == 1)) assert row.role_code == "sales_manager" assert row.snapshot_json["manager_own_excluded"] settlement = settlement_service.generate(session, "2026-03", operator=operator) item = next(item for item in settlement.items if item.personnel_id == row.personnel_id) assert item.role_code == "sales_manager" def test_源客户允许负责人未知且不冒用营销人员姓名(work_session): session = work_session source(session, "customers", [{"id": 9647, "name": "真实样本客户", "partnerType": 211}]) fact(session, "CUSTOMER", "9647", {"customer_type": "enterprise"}) imported_run = apply(session, preview(session, ["customers"])) assert imported_run.summary_json["counts"] == {"CREATE": 1} customer = session.scalar(select(Customer)) assert customer.owner_name == "" and customer.customer_type == "enterprise" def test_带真实发货参照价格的产品可预览并正式导入(work_session): session = work_session source(session, "products", [{"id": 9, "name": "样本产品", "unit_name": "根"}]) source( session, "shipments", [{"id": 20, "code": "SA-SAMPLE", "voucherdate": "2026-07-16", "voucherState": 189}], ) source( session, "shipment_items", [ { "id": 21, "source_parent_id": 20, "idinventory": 9, "taxAmount": "3850.00000000000000", "quantity": "28.00000000000000", "taxPrice": "137.50000000000000", } ], ) fact(session, "PRODUCT", "9", {"category": "municipal_water", "unit": "根"}) imported_run = apply(session, preview(session, ["products"])) assert imported_run.summary_json["counts"] == {"CREATE": 1} product = session.scalar(select(Product)) assert product.stock_quantity == Decimal("28") assert product.source_trade_json["price"] == "137.5000"