<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>物流对账 on 牛逼财税</title>
        <link>https://nbcaishui.com/categories/%E7%89%A9%E6%B5%81%E5%AF%B9%E8%B4%A6/</link>
        <description>Recent content in 物流对账 on 牛逼财税</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Sat, 02 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://nbcaishui.com/categories/%E7%89%A9%E6%B5%81%E5%AF%B9%E8%B4%A6/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>物流对账单源码</title>
        <link>https://nbcaishui.com/p/%E7%89%A9%E6%B5%81%E5%AF%B9%E8%B4%A6%E5%8D%95%E6%BA%90%E7%A0%81/</link>
        <pubDate>Sat, 02 May 2026 00:00:00 +0000</pubDate>
        
        <guid>https://nbcaishui.com/p/%E7%89%A9%E6%B5%81%E5%AF%B9%E8%B4%A6%E5%8D%95%E6%BA%90%E7%A0%81/</guid>
        <description>&lt;p&gt;源码仅供学习参考用，请勿用于其他用途&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import pandas as pd
import numpy as np
import math

# ================= 1. 读取与合并 =================
df_sz = pd.read_excel(&amp;#39;对账单.xlsx&amp;#39;, sheet_name=&amp;#39;深圳&amp;#39;, skiprows=4, keep_default_na=False, dtype=str)
df_sz[&amp;#39;发货地&amp;#39;] = &amp;#39;深圳&amp;#39;

df_sh = pd.read_excel(&amp;#39;对账单.xlsx&amp;#39;, sheet_name=&amp;#39;上海&amp;#39;, skiprows=4, keep_default_na=False, dtype=str)
df_sh[&amp;#39;发货地&amp;#39;] = &amp;#39;上海&amp;#39;

df_all = pd.concat([df_sz, df_sh], ignore_index=True)
df_all = df_all[df_all[&amp;#39;原单号&amp;#39;] != &amp;#39;&amp;#39;]

# ================= 2. 数据类型提前统一清洗 =================
# 将所有参与计算的列一次性转化为浮点数，无法转换的直接变 0，省去后续无尽的报错检查
num_cols =[&amp;#39;称重&amp;#39;, &amp;#39;抛重&amp;#39;, &amp;#39;长宽高之和&amp;#39;, &amp;#39;计费重量&amp;#39;, &amp;#39;欠费总金额&amp;#39;]
for col in num_cols:
    df_all[col] = pd.to_numeric(df_all[col], errors=&amp;#39;coerce&amp;#39;).fillna(0)

# ================= 3. 渠道清洗与标准化 =================
df_map = pd.read_excel(&amp;#39;映射表.xlsx&amp;#39;)
channel_map = dict(zip(df_map[&amp;#39;账单中的渠道字段&amp;#39;], df_map[&amp;#39;清洗后&amp;#39;]))
df_all[&amp;#39;渠道_清洗&amp;#39;] = df_all[&amp;#39;渠道&amp;#39;].map(channel_map).fillna(df_all[&amp;#39;渠道&amp;#39;])

conditions = [
    df_all[&amp;#39;渠道_清洗&amp;#39;].str.contains(&amp;#39;佐川&amp;#39;, na=False),
    df_all[&amp;#39;渠道_清洗&amp;#39;].str.contains(&amp;#39;黑猫&amp;#39;, na=False)
]
choices = [df_all[&amp;#39;发货地&amp;#39;] + df_all[&amp;#39;渠道_清洗&amp;#39;], &amp;#39;黑猫投函&amp;#39;]
df_all[&amp;#39;标准渠道名称&amp;#39;] = np.select(conditions, choices, default=df_all[&amp;#39;渠道_清洗&amp;#39;])

# ================= 4. 处理计费重量 (5%免抛逻辑) =================
df_all[&amp;#39;系统计费重量&amp;#39;] = 0.0
total_tickets = len(df_all)
max_exemptions = int(total_tickets * 0.05) 
count_over_120 = len(df_all[df_all[&amp;#39;长宽高之和&amp;#39;] &amp;gt;= 120])

mask_under_120 = df_all[&amp;#39;长宽高之和&amp;#39;] &amp;lt; 120
mask_120_140 = (df_all[&amp;#39;长宽高之和&amp;#39;] &amp;gt;= 120) &amp;amp; (df_all[&amp;#39;长宽高之和&amp;#39;] &amp;lt; 140)
mask_over_140 = df_all[&amp;#39;长宽高之和&amp;#39;] &amp;gt;= 140

# 规则1 &amp;amp; 规则3 (利用 Numpy 向量化取最大值)
df_all.loc[mask_under_120, &amp;#39;系统计费重量&amp;#39;] = df_all.loc[mask_under_120, &amp;#39;称重&amp;#39;]
df_all.loc[mask_over_140, &amp;#39;系统计费重量&amp;#39;] = df_all.loc[mask_over_140, [&amp;#39;称重&amp;#39;, &amp;#39;抛重&amp;#39;]].max(axis=1)

# 规则2
idx_120_140 = df_all[mask_120_140].index.tolist()
if count_over_120 &amp;lt;= max_exemptions:
    df_all.loc[idx_120_140, &amp;#39;系统计费重量&amp;#39;] = df_all.loc[idx_120_140, &amp;#39;称重&amp;#39;]
else:
    excess_count = count_over_120 - max_exemptions
    if excess_count &amp;gt;= len(idx_120_140):
        df_all.loc[idx_120_140, &amp;#39;系统计费重量&amp;#39;] = df_all.loc[idx_120_140,[&amp;#39;称重&amp;#39;, &amp;#39;抛重&amp;#39;]].max(axis=1)
    else:
        exempt_idx = idx_120_140[:(len(idx_120_140) - excess_count)]
        throw_idx = idx_120_140[(len(idx_120_140) - excess_count):]
        df_all.loc[exempt_idx, &amp;#39;系统计费重量&amp;#39;] = df_all.loc[exempt_idx, &amp;#39;称重&amp;#39;]
        df_all.loc[throw_idx, &amp;#39;系统计费重量&amp;#39;] = df_all.loc[throw_idx, [&amp;#39;称重&amp;#39;, &amp;#39;抛重&amp;#39;]].max(axis=1)

df_all[&amp;#39;重量&amp;#39;] = df_all[&amp;#39;系统计费重量&amp;#39;]
df_all = df_all[df_all[&amp;#39;重量&amp;#39;] &amp;gt; 0]

# ================= 5. 计算基础运费 (提速优化) =================
df_rule = pd.read_excel(&amp;#39;规则表.xlsx&amp;#39;)
# 【优化】：按渠道名称将规则分组缓存为字典，避免 apply 循环中重复检索 DataFrame，提速极其明显！
rules_dict = {channel: group for channel, group in df_rule.groupby(&amp;#39;渠道名称&amp;#39;)}

def compute_fee_fast(row):
    channel = row[&amp;#39;标准渠道名称&amp;#39;]
    weight = row[&amp;#39;重量&amp;#39;]
    sum_cm = row[&amp;#39;长宽高之和&amp;#39;]  # 前面已经转为float了，这里直接用
    
    if channel not in rules_dict:
        return 0.0
        
    lookup_weight = max(weight, 10.01) if sum_cm &amp;gt;= 120 else weight
    sub = rules_dict[channel] # 直接从字典取规则，瞬间完成
    
    matched = sub[(sub[&amp;#39;重量下限 (含)&amp;#39;] &amp;lt;= lookup_weight) &amp;amp; (lookup_weight &amp;lt; sub[&amp;#39;重量上限 (不含)&amp;#39;])]
    if matched.empty:
        return 0.0
        
    rule = matched.iloc[0]
    if weight &amp;lt;= rule[&amp;#39;首重 (kg)&amp;#39;]:
        return rule[&amp;#39;首重费&amp;#39;]
    else:
        extra_units = math.ceil(round((weight - rule[&amp;#39;首重 (kg)&amp;#39;]) / rule[&amp;#39;续重单位 (kg)&amp;#39;], 5))
        return rule[&amp;#39;首重费&amp;#39;] + extra_units * rule[&amp;#39;续重单价&amp;#39;]

df_all[&amp;#39;运费&amp;#39;] = df_all.apply(compute_fee_fast, axis=1)

# ================= 6. 其他附加费 (全面向量化优化) =================
df_all[&amp;#39;检品费&amp;#39;] = 2.0

# 6.1 偏远费优化：使用 np.select，告别逐行扫描
is_remote_addr = df_all[&amp;#39;收件地址&amp;#39;].str.contains(&amp;#39;北海道|沖縄&amp;#39;, na=False)
is_sagawa = df_all[&amp;#39;标准渠道名称&amp;#39;].str.contains(&amp;#39;佐川&amp;#39;, na=False)
is_jhs = df_all[&amp;#39;标准渠道名称&amp;#39;].str.contains(&amp;#39;聚划算&amp;#39;, na=False)

remote_conds =[
    (~is_remote_addr),                                     # 不偏远
    (is_remote_addr &amp;amp; is_sagawa &amp;amp; (df_all[&amp;#39;长宽高之和&amp;#39;] &amp;gt;= 120)), # 偏远+佐川+&amp;gt;=120
    (is_remote_addr &amp;amp; is_sagawa &amp;amp; (df_all[&amp;#39;长宽高之和&amp;#39;] &amp;lt; 120)),  # 偏远+佐川+&amp;lt;120
    (is_remote_addr &amp;amp; is_jhs)                               # 偏远+聚划算
]
remote_vals =[0, 70, 50, 20]
df_all[&amp;#39;计算偏远费&amp;#39;] = np.select(remote_conds, remote_vals, default=0)


# 6.2 超长费优化：使用 pd.cut 区间映射神器
# 因为 &amp;gt;=240 都是 300 元，所以最后一段直接写 240 到 无穷大(float(&amp;#39;inf&amp;#39;))
bins =[-1, 159.99, 180, 200, 220, 240, float(&amp;#39;inf&amp;#39;)]
labels =[0, 100, 120, 150, 200, 300]

# 直接映射
df_all[&amp;#39;计算超长费&amp;#39;] = pd.cut(df_all[&amp;#39;长宽高之和&amp;#39;], bins=bins, labels=labels).astype(float)
# ================= 7. 汇总与输出 =================
df_all[&amp;#39;运费&amp;#39;] = df_all[&amp;#39;运费&amp;#39;] + df_all[&amp;#39;检品费&amp;#39;] + df_all[&amp;#39;计算偏远费&amp;#39;] + df_all[&amp;#39;计算超长费&amp;#39;]

# 计算差异
df_all[&amp;#39;运费差异&amp;#39;] = df_all[&amp;#39;运费&amp;#39;] - df_all[&amp;#39;欠费总金额&amp;#39;]
df_all.to_excel(&amp;#39;对账单_运费计算结果.xlsx&amp;#39;, index=False)
print(&amp;#34;✅ 对账计算完成！已输出文件。&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;</description>
        </item>
        
    </channel>
</rss>
