- 后端
- 企业应用
【免费下载链接】erpnext
Free and Open Source Enterprise Resource Planning (ERP)
导读
Sales Partner(销售合作伙伴)是 ERPNext 中用于管理"卖货但不直接归属为员工"的外部销售力量的核心主数据,涵盖经销商(dealer)、代理商(distributor)、佣金代理(commission agent)、联属推广(affiliate)与转售商(reseller)等角色。本文以 erpnext/setup/doctype/sales_partner/README.md 为骨架,结合仓库源码与配置,完整讲解 Sales Partner 的字段模型、佣金计算底层逻辑、目标(Target)设定、网页门户(Website)展示、推荐码(Referral Code)追踪以及配套报表的使用方法,帮助你搭建一套可落地的渠道销售管理方案。
一、Sales Partner 是什么
官方 DocType 定义(见 sales_partner.json):
A third party distributor / dealer / commission agent / affiliate / reseller who sells the companies products for a commission.
即:Sales Partner 是"第三方分销商/经销商/佣金代理/联属推广/转售商,按佣金销售公司产品"的主体。与 Sales Person(销售员,属于内部员工)不同,Sales Partner 是独立于组织之外的合作伙伴,公司通过设定佣金率与其结算。
README 原文仅一句话:"Partner / dealer / distributor who sells products (maybe for commission) and for whom targets can be set."——但背后的实现远比这句话丰富,下面逐层展开。
1.1 使用场景
- 经销商(Dealer)/ 代理商(Distributor)按区域(Territory)代理销售产品,公司按固定佣金率结算;
- 佣金代理(Commission Agent)按单笔订单的净额抽佣;
- 联属推广(Affiliate)/ 转售商(Reseller)通过推荐码(Referral Code)追踪引流成交;
- 针对不同 Item Group、不同 Fiscal Year 为合作伙伴设定销售目标(Target),并按目标达成情况考核。
二、Sales Partner DocType 字段模型
字段定义位于 sales_partner.json 的fields数组,字段顺序即表单布局(field_order)。核心字段归纳如下:
| 字段 | Fieldtype | 必填/特性 | 说明 |
|---|---|---|---|
partner_name | Data | 必填、唯一、autoname 来源 | 合作伙伴名称,作为文档自动命名(autoname: field:partner_name),表单内不可重复 |
partner_type | Link → Sales Partner Type | 列表/筛选可见 | 合作伙伴类型(经销商/代理/联属等),选项来自 Sales Partner Type |
territory | Link → Territory | 必填 | 负责的销售区域,用于渠道与区域管理 |
commission_rate | Float | 必填 | 佣金率(百分比),参与订单佣金自动计算 |
targets | Table → Target Detail | — | 销售目标明细表,按 Item Group + Fiscal Year 设定 |
show_in_website | Check | 默认 0 | 是否在公司门户网站公开该合作伙伴主页 |
referral_code | Data | 唯一、长度 8 | 推荐码,用于追踪引荐/联盟成交 |
route | Data | 唯一、依赖 show_in_website | 门户网站公开页面的 URL 路径 |
logo | Attach | — | 合作伙伴 Logo(网站展示用) |
partner_website | Data | — | 合作伙伴外部官网(保存时自动规范化 https) |
introduction | Text | 依赖 show_in_website | 网站主页简介 |
description | Text Editor | — | 富文本详细介绍,门户页面展示 |
权限:Sales Master Manager拥有创建/读写/分享权限,Sales Manager与Sales User可读、可邮件、可打印、可出报表;其余财务、采购、库存、维护、交付、网站等角色仅有只读(select)权限(见 sales_partner.json)。
2.1 字段背后的源码逻辑
sales_partner.py 中validate()做了三件事:
- 自动生成 route:若未手动填写
route,自动生成为"partners/" + self.scrub(self.partner_name)(scrub 将名称转为 slug),保证门户 URL 唯一; - 规范化 partner_website:利用
urlsplit/urlunsplit把缺省协议或http://的网址统一改写为https://,例如填写example.com会被规范为https://example.com; - 调用 WebsiteGenerator 的校验逻辑(
super().validate()),因为 Sales Partner 继承自WebsiteGenerator(sales_partner.py),天然具备门户页生成能力。
地址与联系人自动加载:onload()调用load_address_and_contact(self),在表单加载时把与合作伙伴关联的 Address / Contact 数据注入__onload;前端 sales_partner.js 在refresh事件中:新文档(__islocal)隐藏地址联系人区块并清空缓存,已保存文档则调用frappe.contacts.render_address_and_contact(frm)渲染地址联系人卡片。
推荐码自动大写:sales_partner.js 在referral_code字段变更时自动转为大写,保证追踪码的一致性(长度上限 8,见 sales_partner.json)。
三、佣金计算:从订单到报表的完整链路
3.1 订单/发票中的佣金字段
在 Sales Order、Sales Invoice、Delivery Note、POS Invoice 等销售单据上都有sales_partner、commission_rate、amount_eligible_for_commission、total_commission字段(例如 sales_order.json、customer.py 中的default_sales_partner可预填默认合作伙伴)。
佣金计算统一实现在 selling_controller.py 的calculate_commission():
def calculate_commission(self): if not self.meta.get_field("commission_rate"): return self.round_floats_in(self, ("amount_eligible_for_commission", "commission_rate")) if not (0 <= self.commission_rate <= 100.0): throw(..., _("must be between 0 and 100")) self.amount_eligible_for_commission = sum( item.base_net_amount for item in self.items if item.grant_commission ) self.total_commission = flt( self.amount_eligible_for_commission * self.commission_rate / 100.0, self.precision("total_commission"), )关键点:
- 校验:
commission_rate必须在 0~100 之间,否则单据保存会抛错; - 计佣基数:
amount_eligible_for_commission只累加"行项目上勾选了grant_commission"的base_net_amount(基础净额),允许对特定产品行豁免佣金; - 总额:
total_commission = 可计佣净额 × 佣金率 / 100,并按单据字段精度四舍五入。
从源码结构可以推断:
calculate_commission在单据提交/保存流程中被销售控制器调用,因此佣金金额会随订单/发票的净额变化自动重算,无需手工维护。
3.2 佣金汇总报表
sales_partner_commission_summary.py 实现了Sales Partner Commission Summary报表,其基类SalesPartnerSummaryReport的核心查询逻辑:
self.query = ( frappe.qb.from_(self.dt) .select( self.dt.name, self.dt.customer, self.dt.territory, Field(self.date_field, "posting_date", table=self.dt), self.dt.sales_partner, self.dt.commission_rate, ConstantColumn(company_currency).as_("currency"), ) .where( (self.dt.docstatus == 1) & (self.dt.sales_partner.notnull()) & (self.dt.sales_partner != "") ) ... )- 支持 Sales Order / Sales Invoice / Delivery Note / POS Invoice 四种单据(
SALES_TRANSACTION_DOCTYPES); - 只统计已提交(
docstatus == 1)且填写了sales_partner的单据; - 报表列包括:单据号、客户、币种、区域、日期、金额(
base_net_total)、销售合作伙伴、佣金率、总佣金(total_commission); - 提供公司、客户、区域、合作伙伴、起止日期等筛选(
_apply_common_filters); - 日期字段自动适配:Sales Order 用
transaction_date(下单日期),其余单据用posting_date(过账日期)。
Sales Partner Transaction Summary(sales_partner_transaction_summary.py)在此基础上 JOIN 子表{DocType} Item,把明细行(Item Code、Item Group、Brand、Qty、Rate、Amount)也纳入报表,用于逐产品行的佣金核算。两者均继承同一基类,复用查询框架。
四、目标设定:Target Detail 子表与考核
README 中"for whom targets can be set"对应 Sales Partner 表单中的Sales Partner Target区块(targets子表),选项为 Target Detail(istable 子表 DocType),字段:
| 字段 | Fieldtype | 必填 | 说明 |
|---|---|---|---|
item_group | Link → Item Group | — | 目标适用的商品组(留空表示不限) |
fiscal_year | Link → Fiscal Year | 是 | 目标所属财年 |
target_qty | Float | — | 目标数量 |
target_amount | Float | — | 目标金额 |
distribution_id | Link → Monthly Distribution | 是 | 月度分配方案,把年度目标摊到各月 |
前端联动(sales_partner.js):填写fiscal_year后,distribution_id的候选列表会被过滤为同财年的 Monthly Distribution,防止选错跨财年的分配方案。
4.1 目标达成考核报表
仓库提供了基于 Item Group 的目标差异报表(sales_partner_target_variance_based_on_item_group.py)以及配套测试(test_sales_partner_target_variance_based_on_item_group.py),将"设定的目标"与"实际成交"进行差异对比,用于季度/年度渠道考核。
五、门户网站展示:把合作伙伴做成公开页面
勾选show_in_website后,Sales Partner 会作为门户页面公开。website配置在 sales_partner.py:
website = frappe._dict( page_title_field="partner_name", condition_field="show_in_website", template="templates/generators/sales_partner.html", )- 页面标题取
partner_name; - 仅当
show_in_website = 1时生成页面(condition_field); - 渲染模板为 templates/generators/sales_partner.html,该模板在页面上输出:Logo(
itemprop="brand")、地址/电话/邮箱(itemprop="address"/"telephone"/"email",符合 schema.org Organization 微格式)、以及description富文本介绍。
模板中的地址数据来自get_context()(sales_partner.py):通过Dynamic Link反查关联的 Address 文档,汇总address_line1/address_line2/city/state/pincode/country为多行地址,并取出邮箱与电话(支持多号码用<br>分隔)。
六、推荐码(Referral Code)与联动业务
referral_code在字段定义中的 description 为"To Track inbound purchase"(用于追踪引荐/入站成交),长度 8、唯一、输入自动转大写(sales_partner.js)。它把 Sales Partner 与联属推广场景打通:合作伙伴可通过唯一推荐码标识自己带来的客户与订单,配合上述佣金报表即可核算每笔引荐成交的佣金。
从源码结构看,sales_partner字段在 customer、quotation、sales_order 等 DocType 中均有引用,Customer 上还有default_sales_partner用于建立"客户—合作伙伴"默认归属关系,下单时自动带入佣金率。
七、Sales Partner Type:类型维度
partner_type链接到 Sales Partner Type,这是独立的 Setup DocType,用于维护"经销商 / 代理商 / 联属 / 分销"等分类。先创建类型,再在 Sales Partner 表单中引用,即可按类型过滤列表、筛选报表。
八、从创建到使用的完整操作步骤
- 维护基础资料:在 Setup → Sales Partner Type 中创建类型(如"经销商"),在 CRM/Selling 模块准备 Territory、Fiscal Year、Monthly Distribution、Item Group 等关联主数据;
- 创建 Sales Partner(Setup → Sales Partner):
- 填写
partner_name(必填、唯一,自动作为文档名); - 选择
partner_type与territory(必填); - 填写
commission_rate(必填,0~100); - 保存后自动关联地址/联系人(也可手动添加 Address / Contact 并链接到本合作伙伴);
- 填写
- 设定目标:在 Sales Partner Target 子表中按
item_group + fiscal_year添加行,填写target_qty/target_amount并选择同财年的distribution_id(月度分配); - (可选)门户展示:勾选
show_in_website,填写introduction、description、logo、partner_website,route留空会自动生成为partners/<slug>; - (可选)推荐码:填写
referral_code(≤8 位,自动大写),用于追踪引荐成交; - 下单结算:在 Sales Order / Sales Invoice 中关联该
sales_partner,系统自动计算total_commission(calculate_commission逻辑见上文);也可在 Customer 上预填default_sales_partner自动带入; - 报表考核:运行 Sales Partner Commission Summary / Sales Partner Transaction Summary 查看佣金明细,运行 Sales Partner Target Variance(按 Item Group)对比目标与实际,完成渠道考核与佣金结算。
九、小结
Sales Partner 是 ERPNext 渠道销售体系的枢纽主数据:以"合作伙伴 + 佣金率"驱动订单级自动佣金计算(selling_controller.py),以targets子表承载目标管理,以show_in_website开启公开门户页(sales_partner.html),以referral_code支撑联属追踪,再配合三张专项报表(佣金汇总、交易明细、目标差异)完成从渠道录入、成交结算到绩效考核的闭环。对渠道型企业而言,这套组合可以直接替换或补充原有的手工对账流程。
- 后端
- 企业应用
【免费下载链接】erpnext
Free and Open Source Enterprise Resource Planning (ERP)
相关推荐
laravel-crm销售佣金:销售提成计算与发放管理
laravel crm销售佣金:销售提成计算与发放管理 痛点:销售激励体系缺失的困境 你是否还在为销售团队的激励问题而烦恼?传统的Excel表格手动计算佣金不仅
后端前端企业应用为什么选择ner-bertje-tagdetekst?3大核心优势助力历史文本实体识别
为什么选择ner bertje tagdetekst?3大核心优势助力历史文本实体识别 ner bertje tagdetekst是一款专为荷兰语历史文本设计的
OpenViking 销售商机商单 Builder 实战指南:双 APIKey 体系下的个人销售知识库搭建与跟进工作流
OpenViking 销售商机商单 Builder 实战指南:双 APIKey 体系下的个人销售知识库搭建与跟进工作流 导读 本文基于 OpenViking 仓
人工智能AI AgentAgent 记忆RAG后端数据库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考