<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Ozon平台 on 牛逼财税</title>
        <link>https://nbcaishui.com/tags/ozon%E5%B9%B3%E5%8F%B0/</link>
        <description>Recent content in Ozon平台 on 牛逼财税</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Fri, 24 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://nbcaishui.com/tags/ozon%E5%B9%B3%E5%8F%B0/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>从&#34;每天打开后台截图&#34;到&#34;一键生成日报&#34;：我如何用 OZON API 重构跨境电商的数据获取流程</title>
        <link>https://nbcaishui.com/p/%E4%BB%8E%E6%AF%8F%E5%A4%A9%E6%89%93%E5%BC%80%E5%90%8E%E5%8F%B0%E6%88%AA%E5%9B%BE%E5%88%B0%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E6%97%A5%E6%8A%A5%E6%88%91%E5%A6%82%E4%BD%95%E7%94%A8-ozon-api-%E9%87%8D%E6%9E%84%E8%B7%A8%E5%A2%83%E7%94%B5%E5%95%86%E7%9A%84%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96%E6%B5%81%E7%A8%8B/</link>
        <pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate>
        
        <guid>https://nbcaishui.com/p/%E4%BB%8E%E6%AF%8F%E5%A4%A9%E6%89%93%E5%BC%80%E5%90%8E%E5%8F%B0%E6%88%AA%E5%9B%BE%E5%88%B0%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E6%97%A5%E6%8A%A5%E6%88%91%E5%A6%82%E4%BD%95%E7%94%A8-ozon-api-%E9%87%8D%E6%9E%84%E8%B7%A8%E5%A2%83%E7%94%B5%E5%95%86%E7%9A%84%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96%E6%B5%81%E7%A8%8B/</guid>
        <description>&lt;blockquote&gt;
&lt;p&gt;做跨境电商的人都懂：每天早上第一件事，就是登录 OZON 后台，一个店铺一个店铺地看昨天的数据——销售额、退款、广告费、有效订单、取消订单……几家店铺切换下来，半小时过去了，Excel 上还没写一个字。&lt;/p&gt;
&lt;p&gt;于是我花了一点时间，把这件事彻底自动化了。本文记录整个过程，既是技术复盘，也是对&amp;quot;数据获取&amp;quot;这件事本身的一些思考。&lt;/p&gt;&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一问题的起点后台数据到底有多散&#34;&gt;一、问题的起点：后台数据到底有多&amp;quot;散&amp;quot;
&lt;/h2&gt;&lt;p&gt;在 OZON 卖家后台，看一天的经营数据，要跳转至少 4 个不同的页面：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;需要的数据&lt;/th&gt;
          &lt;th&gt;后台路径&lt;/th&gt;
          &lt;th&gt;痛点&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;订单金额、订单量&lt;/td&gt;
          &lt;td&gt;订单管理 → 分别看 FBO 和 FBS&lt;/td&gt;
          &lt;td&gt;FBO（OZON仓发货）、FBS（自发货）是两套独立列表&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;取消订单&lt;/td&gt;
          &lt;td&gt;同上，需筛选状态&lt;/td&gt;
          &lt;td&gt;要手动勾选&amp;quot;已取消&amp;quot;才能看到&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;退款金额&lt;/td&gt;
          &lt;td&gt;财务 → 经营状况 → 退款&lt;/td&gt;
          &lt;td&gt;和订单是完全独立的口径&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;广告花费&lt;/td&gt;
          &lt;td&gt;广告后台（独立系统，独立登录）&lt;/td&gt;
          &lt;td&gt;账号体系都和卖家后台分开&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;产品销售明细&lt;/td&gt;
          &lt;td&gt;分析 → 按 SKU 看&lt;/td&gt;
          &lt;td&gt;还要自己导出、筛掉销售额为 0 的&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键认知&lt;/strong&gt;：OZON 的销售数据和广告数据，是&lt;strong&gt;两套完全独立的 API 体系&lt;/strong&gt;，连鉴权方式都不一样。这是整个事情第一个需要跨过的门槛。&lt;/p&gt;
&lt;p&gt;如果店铺数量是 5 个，上面的动作要重复 5 次。如果还要汇总&amp;quot;近 7 天&amp;quot;做趋势分析——那基本上一上午就废了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二网页后台-vs-api同样的数据两种获取方式&#34;&gt;二、网页后台 vs API：同样的数据，两种获取方式
&lt;/h2&gt;&lt;p&gt;这是全文的核心对比。我把整个数据获取流程拆成 4 块，逐块对比。&lt;/p&gt;
&lt;h3 id=&#34;对比-1销售订单金额&#34;&gt;对比 1：销售订单金额
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;网页后台做法&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录卖家后台&lt;/li&gt;
&lt;li&gt;进入&amp;quot;订单 → FBO&amp;quot;，筛选昨天的下单时间，记录订单金额&lt;/li&gt;
&lt;li&gt;进入&amp;quot;订单 → FBS&amp;quot;，同样筛选昨天，记录订单金额&lt;/li&gt;
&lt;li&gt;把状态为&amp;quot;已取消&amp;quot;的单子手动剔除&lt;/li&gt;
&lt;li&gt;把上面两块加起来&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;API 做法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;FBO 和 FBS 是两个独立的接口，但参数结构几乎一样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 拉取 FBS 订单，按莫斯科时区过滤，自动翻页&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_fetch_fbs_orders&lt;/span&gt;(store, day):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result, offset &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [], &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        resp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;post(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api-seller.ozon.ru/v3/posting/fbs/list&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            headers&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;seller_headers(store),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            json&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dir&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;asc&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;since&amp;#34;&lt;/span&gt;: day &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;T00:00:00+03:00&amp;#34;&lt;/span&gt;,  &lt;span style=&#34;color:#75715e&#34;&gt;# 莫斯科时间 +03:00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;to&amp;#34;&lt;/span&gt;:    day &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;T23:59:59+03:00&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;limit&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;offset&amp;#34;&lt;/span&gt;: offset,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }, timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        postings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;json()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;, {})&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;postings&amp;#34;&lt;/span&gt;, [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; postings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; len(postings) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;:   &lt;span style=&#34;color:#75715e&#34;&gt;# 不足一页，说明拉完了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        offset &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;拿到数据后，用状态码筛掉取消的订单，剩下的累加金额就是&amp;quot;有效订单金额&amp;quot;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CANCELLED &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cancelled&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cancelled_employer&amp;#34;&lt;/span&gt;}  &lt;span style=&#34;color:#75715e&#34;&gt;# 两种取消状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;valid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [p &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; p &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; all_orders &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; p&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; CANCELLED]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result_a &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sum(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    float(item[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;price&amp;#34;&lt;/span&gt;]) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; int(item[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;quantity&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; p &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; valid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; item &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; p&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;products&amp;#34;&lt;/span&gt;, [])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;几个非写不可的注释&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;时间必须用莫斯科时间&lt;/strong&gt;（UTC+3），否则跨零点的订单会错位到另一天。OZON 后台显示的就是莫斯科时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FBS 和 FBO 是两套接口&lt;/strong&gt;：&lt;code&gt;/v3/posting/fbs/list&lt;/code&gt; 和 &lt;code&gt;/v2/posting/fbo/list&lt;/code&gt;，连 API 版本号都不一样。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分页用 offset 推进&lt;/strong&gt;，每页最多 50 条，直到返回不足 50 条才算拉完。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;对比-2退款金额&#34;&gt;对比 2：退款金额
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;网页后台做法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;进入&amp;quot;财务 → 经营状况 → 退款&amp;quot;，记录昨天的退款金额。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API 做法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;退款这里有个坑：&lt;strong&gt;它不在订单接口里，而在财务流水接口里&lt;/strong&gt;，而且需要按 &lt;code&gt;transaction_type: &amp;quot;returns&amp;quot;&lt;/code&gt; 过滤：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_fetch_returns_amount&lt;/span&gt;(store, day):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    total, page &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        resp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;post(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api-seller.ozon.ru/v3/finance/transaction/list&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            headers&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;seller_headers(store),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            json&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;filter&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;from&amp;#34;&lt;/span&gt;: day &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;T00:00:00.000Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;to&amp;#34;&lt;/span&gt;:   day &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;T23:59:59.000Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;operation_type&amp;#34;&lt;/span&gt;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;transaction_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;returns&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# 关键：只要退款&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;page&amp;#34;&lt;/span&gt;: page, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;page_size&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }, timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; resp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;json()&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;, {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; op &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; result&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;operations&amp;#34;&lt;/span&gt;, []):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            total &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; op&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;accruals_for_sale&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; page &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; result&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;page_count&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        page &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; abs(round(total, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;))  &lt;span style=&#34;color:#75715e&#34;&gt;# 退款是负数，取绝对值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;几个非写不可的注释&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;退款金额字段是 &lt;code&gt;accruals_for_sale&lt;/code&gt;，返回的是&lt;strong&gt;负数&lt;/strong&gt;（账上扣减），所以最后要 &lt;code&gt;abs()&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;这个接口的时间用的是 &lt;strong&gt;UTC 格式&lt;/strong&gt;（&lt;code&gt;.000Z&lt;/code&gt;），和订单接口的莫斯科时间格式不同。&lt;strong&gt;同一个 API 家族，不同接口的时间格式居然不一致&lt;/strong&gt;，这是 OZON API 最反直觉的地方之一。&lt;/li&gt;
&lt;li&gt;分页用 &lt;code&gt;page&lt;/code&gt; 和 &lt;code&gt;page_size&lt;/code&gt;，和订单接口的 &lt;code&gt;offset/limit&lt;/code&gt; 也不一样。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;对比-3广告数据&#34;&gt;对比 3：广告数据
&lt;/h3&gt;&lt;p&gt;这块最复杂，因为&lt;strong&gt;广告是另一套完全独立的 API&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;维度&lt;/th&gt;
          &lt;th&gt;销售 API&lt;/th&gt;
          &lt;th&gt;广告 API&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;域名&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;api-seller.ozon.ru&lt;/code&gt;&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;api-performance.ozon.ru&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;鉴权方式&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;Client-Id&lt;/code&gt; + &lt;code&gt;Api-Key&lt;/code&gt; 直接塞 header&lt;/td&gt;
          &lt;td&gt;OAuth2，先拿 token 再请求&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;数据格式&lt;/td&gt;
          &lt;td&gt;JSON&lt;/td&gt;
          &lt;td&gt;&lt;strong&gt;CSV&lt;/strong&gt;（分号分隔，逗号做小数点）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;账号体系&lt;/td&gt;
          &lt;td&gt;卖家账号&lt;/td&gt;
          &lt;td&gt;广告主账号（独立申请）&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;网页后台做法&lt;/strong&gt;：登录广告后台（另一套登录态），进入&amp;quot;推广 → 推广分析→选择日期&amp;quot;，直接记录当天的广告消费或者导出 CSV，手动整理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API 做法&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 第一步：拿 access_token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_perf_token&lt;/span&gt;(store):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    resp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;post(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api-performance.ozon.ru/api/client/token&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        json&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;client_id&amp;#34;&lt;/span&gt;:     store[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;perf_id&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;client_secret&amp;#34;&lt;/span&gt;: store[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;perf_secret&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;grant_type&amp;#34;&lt;/span&gt;:    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;client_credentials&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; resp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;json()[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;access_token&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 第二步：用 token 拿数据，注意返回的是 CSV&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_fetch_ad_detail&lt;/span&gt;(store, date_from, date_to):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    token &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; get_perf_token(store)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    resp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api-performance.ozon.ru/api/client/statistics/daily&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        headers&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bearer &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;{&lt;/span&gt;token&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        params&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dateFrom&amp;#34;&lt;/span&gt;: date_from, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dateTo&amp;#34;&lt;/span&gt;: date_to}, timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# CSV 用分号分隔，小数点是逗号（俄欧习惯）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    df &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pd&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;read_csv(StringIO(resp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;text&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strip()),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     sep&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;;&amp;#34;&lt;/span&gt;, decimal&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;, encoding&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    df&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;columns &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;活动ID&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;活动名称&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;日期&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;展示量&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;点击量&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广告费(RUB)&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广告订单量&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广告销售额(RUB)&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 关键：OZON 会在 CSV 末尾自动附加一行&amp;#34;合计行&amp;#34;，活动ID 为空&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 如果不过滤掉，所有金额都会被重复计算一遍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    df &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; df[df[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;活动ID&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;notna() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; (df[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;活动ID&amp;#34;&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;astype(str)&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;str&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;strip() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; df
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;几个踩过的坑&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;俄语区 CSV 用分号做分隔符、逗号做小数点&lt;/strong&gt;，所以 &lt;code&gt;pd.read_csv&lt;/code&gt; 必须同时传 &lt;code&gt;sep=&amp;quot;;&amp;quot;&lt;/code&gt; 和 &lt;code&gt;decimal=&amp;quot;,&amp;quot;&lt;/code&gt;，否则数字全错。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSV 末尾会自动附加一行合计行&lt;/strong&gt;（活动 ID 为空），第一次没注意，广告费直接翻倍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;归因机制&lt;/strong&gt;：用户先点击了广告 A，又点击了广告 B，最后下单了——OZON 会把这笔销售额&lt;strong&gt;同时计入 A 和 B&lt;/strong&gt;。所以广告销售额加总可能大于实际订单额，这不是 bug，是平台的归因策略。&lt;/li&gt;
&lt;li&gt;通过 API 拿到的广告费，和网页端看到的可能会差几卢布，是尾数精度差异造成的，对经营决策没有影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;对比-4产品级销售明细&#34;&gt;对比 4：产品级销售明细
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;网页后台做法&lt;/strong&gt;：进入&amp;quot;分析 → 我的商品销售&amp;quot;，选日期，导出 Excel，手动剔除销售额为 0 的行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;API 做法&lt;/strong&gt;：走 &lt;code&gt;/v1/analytics/data&lt;/code&gt;，这是一个很通用的 OLAP 风格接口，可以指定维度（&lt;code&gt;dimension&lt;/code&gt;）和指标（&lt;code&gt;metrics&lt;/code&gt;）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;resp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; requests&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;post(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://api-seller.ozon.ru/v1/analytics/data&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    headers&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;seller_headers(store),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    json&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_from&amp;#34;&lt;/span&gt;: day, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_to&amp;#34;&lt;/span&gt;: day,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;metrics&amp;#34;&lt;/span&gt;:   [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;revenue&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ordered_units&amp;#34;&lt;/span&gt;],  &lt;span style=&#34;color:#75715e&#34;&gt;# 想要什么指标&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dimension&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sku&amp;#34;&lt;/span&gt;],                        &lt;span style=&#34;color:#75715e&#34;&gt;# 按什么维度切&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;limit&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, timeout&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个接口设计得最好——&lt;strong&gt;一个接口搞定所有维度组合&lt;/strong&gt;，想按 SKU 切就按 SKU，想按类目切就按类目。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三最难的一个问题1-号下单2-号取消怎么办&#34;&gt;三、最难的一个问题：1 号下单、2 号取消怎么办？
&lt;/h2&gt;&lt;p&gt;这是整个项目里&lt;strong&gt;最容易被忽略、也最容易让数据失真&lt;/strong&gt;的一个问题。&lt;/p&gt;
&lt;p&gt;想象这个场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;11 月 1 日&lt;/strong&gt; 客户下单，金额 1000 卢布&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;11 月 2 日&lt;/strong&gt; 客户取消订单&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果每天跑日报，只拉&amp;quot;当天下单的订单&amp;quot;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;11 月 1 日的日报：1000 卢布订单 ✅ 没问题&lt;/li&gt;
&lt;li&gt;11 月 2 日的日报：0 单（这天没人下单）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可是 1 号那条数据&lt;/strong&gt;永远是&amp;quot;有效订单&amp;quot;，永远不会更新成&amp;quot;已取消&amp;quot; ❌&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;换句话说，&lt;strong&gt;按下单日拉数据 + 当天下单当天判定状态 = 永远捕捉不到跨天取消&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;解决方案每周一次重新统计--用实时状态&#34;&gt;解决方案：每周一次重新统计 + 用实时状态
&lt;/h3&gt;&lt;p&gt;我写了两个脚本：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ozon_day.py&lt;/code&gt;（日报）&lt;/strong&gt;：每天早上跑一次，生成昨天的日报。这是快报，用来快速感知。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ozon_week.py&lt;/code&gt;（周报）&lt;/strong&gt;：拉取最近 7 天的&lt;strong&gt;所有订单&lt;/strong&gt;，但判定状态时用的是&lt;strong&gt;API 返回的当前状态&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;关键代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 一次拉取 7 天窗口内的订单&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fbs_orders &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _fetch_fbs(store, date_from, date_to)  &lt;span style=&#34;color:#75715e&#34;&gt;# date_from=7天前, date_to=昨天&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fbo_orders &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _fetch_fbo(store, date_from, date_to)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 按下单日分桶，但用&amp;#34;当前状态&amp;#34;判定是否取消&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; p &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; all_orders:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; _order_day(p)  &lt;span style=&#34;color:#75715e&#34;&gt;# 下单日期（莫斯科时间）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; p&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; CANCELLED:  &lt;span style=&#34;color:#75715e&#34;&gt;# 这里是实时状态，不是历史快照&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cancel_cnt[d] &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        valid_amt[d] &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; _posting_amount(p)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样一来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;11 月 1 日下单、11 月 2 日取消的那条订单，&lt;strong&gt;在 11 月 2 日跑周报时&lt;/strong&gt;，会被归到&amp;quot;11 月 1 日 → 已取消&amp;quot;。&lt;/li&gt;
&lt;li&gt;1 号的&amp;quot;有效订单金额&amp;quot;会被正确地&lt;strong&gt;向下修正&lt;/strong&gt; 1000 卢布。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;这是网页后台也做不到的事情&lt;/strong&gt;——后台要么给你看&amp;quot;按下单日的静态数据&amp;quot;，要么给你看&amp;quot;按处理日的流水&amp;quot;，没有&amp;quot;按下单日 + 最新状态&amp;quot;这个视角。&lt;/p&gt;
&lt;p&gt;当然也还是有边界——如果订单是 8 天前下的、今天才取消，周报就覆盖不到了。但对实际经营来说，一周窗口已经足够。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四两种方式的数据差异&#34;&gt;四、两种方式的数据差异：
&lt;/h2&gt;&lt;p&gt;这是全文最该被收藏的部分。&lt;strong&gt;同样的&amp;quot;昨天销售额&amp;quot;，后台看到的和 API 拿到的，可能对不上&lt;/strong&gt;。原因：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;差异点&lt;/th&gt;
          &lt;th&gt;说明&lt;/th&gt;
          &lt;th&gt;影响&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;时间口径&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;FBS 看 &lt;code&gt;in_process_at&lt;/code&gt;，FBO 看 &lt;code&gt;created_at&lt;/code&gt;；财务流水用 UTC&lt;/td&gt;
          &lt;td&gt;跨零点的订单可能归属不同日期&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;广告费尾数&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;API 返回的数值精度和网页端显示的截断方式不同&lt;/td&gt;
          &lt;td&gt;差几卢布，不影响决策&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;广告归因&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;一单可能被多个广告计入销售额&lt;/td&gt;
          &lt;td&gt;广告销售额之和 &amp;gt; 实际销售额（正常现象）&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;退款归属&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;退款按【财务模块-店铺经营状况】&amp;ldquo;扣款日&amp;quot;归属，不是按&amp;quot;原订单日&amp;rdquo;&lt;/td&gt;
          &lt;td&gt;和订单金额不是严格同一批单子的&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;取消订单&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;日报只能看到&amp;quot;当天下单当天取消&amp;quot;，周报能看&amp;quot;当天下单 N 天内取消&amp;quot;&lt;/td&gt;
          &lt;td&gt;日报的取消数会偏低，周报更准&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;strong&gt;导出明细&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;OZON 导出的销售明细 CSV &lt;strong&gt;默认包含已取消订单&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;如果直接求和，会虚高，需要筛选掉已取消订单&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;：API 能拿到比后台&lt;strong&gt;更完整、更灵活&lt;/strong&gt;的数据，但代价是你要自己搞清楚每个字段的口径。后台看似简单，其实平台替你做了很多隐式的口径选择——而这些选择并不总是符合你的经营视角。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五产出两个-excel&#34;&gt;五、产出：两个 Excel
&lt;/h2&gt;&lt;p&gt;日报脚本跑完后，生成一个 Excel 文件，包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;汇总&lt;/strong&gt;：每个店铺一行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;销售明细&lt;/strong&gt;：店铺 × 日期× SKU&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;广告明细&lt;/strong&gt;：按广告活动拆分，带 ROI 和广告费占比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;周报脚本跑完后，生成一个 Excel 文件，包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;汇总&lt;/strong&gt;：每个店铺一行，近 7 天合计&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每日明细&lt;/strong&gt;：店铺 × 日期，每天一行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;销售明细&lt;/strong&gt;：按 SKU 拆分&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;广告明细&lt;/strong&gt;：按广告活动拆分，带 ROI 和广告费占比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每天早上我只需要&lt;strong&gt;双击一下 py 文件&lt;/strong&gt;，几分钟后打开 Excel 就能看到所有店铺的完整经营情况。&lt;/p&gt;
&lt;p&gt;原来需要2小时的手工操作，现在变成了 5-10 分钟。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六写在最后为什么这件事值得做&#34;&gt;六、写在最后：为什么这件事值得做
&lt;/h2&gt;&lt;p&gt;网页后台是平台帮你做好的&amp;quot;一个视角&amp;quot;，它足够好，但不一定是&lt;strong&gt;你最需要的那个视角&lt;/strong&gt;。 API 是原材料，你可以按自己的口径重新组装数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;后台不会帮你自动合并20个店铺的数据，API 会。&lt;/li&gt;
&lt;li&gt;后台不会帮你做&amp;quot;按下单日 + 最新状态&amp;quot;的口径，API 会。&lt;/li&gt;
&lt;li&gt;后台不会帮你把销售和广告并列对比算 ROI，API 会。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这也是我之后会继续挖的方向——不是把脚本写得多花哨，而是把每一个&amp;quot;重复动作&amp;quot;还原成它背后的数据问题，然后用最直接的方式解决它。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;本文涉及的接口包括：OZON 卖家 API（订单、财务、分析）和 OZON 广告 API（统计）。 所有接口的鉴权信息、店铺配置被抽离到独立的 &lt;code&gt;ozon_config.py&lt;/code&gt;，主脚本只负责逻辑。&lt;/p&gt;&lt;/blockquote&gt;
</description>
        </item>
        
    </channel>
</rss>
