Spree Admin Dashboard 企业客户管理与税务配置能力解析
Spree Admin Dashboard 企业客户管理与税务配置能力解析【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree导读本篇文章围绕 Spree 开源电商平台一个关键的 Dashboard 功能变更展开为spree/dashboard、spree/dashboard-core、spree/dashboard-ui与spree/admin-sdk四个包新增的企业客户Companies / Business Customers管理页面与税务配置Tax Rates / Tax Provider能力。变更由仓库根目录的 .changeset/dashboard-companies-and-tax-rates.md 声明完整落点覆盖企业组织树管理 → 税务标识符与免税证明 → 税率设置 → 市场级税务引擎选择整条 B2B 业务链路。读完本文你将掌握这些页面的数据模型、操作流程、权限控制、Admin SDK 端点以及在配置期发现税务引擎能力缺口这一设计思路的源码级实现。变更总览四个包协同演进该变更通过 Changesets 一次声明四个包的 minor 升级包版本级别变更角色spree/dashboardminor新增企业客户与税务配置页面路由、组件spree/dashboard-coreminor提供资源查询、权限与表单映射等基础设施支撑spree/dashboard-uiminor新增/复用的 UI 组件卡片、表格、Sheet、Alert 等spree/admin-sdkminor新增客户税务标识符端点、market 参数中的tax_provider值得注意的是发布机制根据 .changeset/README.mddashboard 三个包构成fixed group——它们共享同一版本号、一起发布保证脚手架生成的工程安装到的 trio 一定是成套发布的而spree/admin-sdk作为独立 API 客户端单独版本化。spree/sdk属于稳定的 1.x 发布线跟随 Spree 版本发布其余包走持续发布的 Developer Preview 线两者互不干扰。因此本次变更虽然涉及四个包实际对应两条发布流水线。企业客户Companies页面组织树的完整管理闭环列表页与详情页的路由结构从路由文件可以看出企业客户管理是独立的一级导航packages/dashboard/src/routes/_authenticated/$storeId/companies/index.tsx负责列表packages/dashboard/src/routes/_authenticated/$storeId/companies/$companyId.tsx负责详情页对应 Admin API 端点GET /api/v3/admin/companies/${company.id}。详情页由ResourceLayout组织主区域与侧栏分工明确。组织树Company 与 Division 两级模型企业客户不是扁平列表而是支持树形层级。useCompanyChildren通过parent_id_eq/parent_id_null参数查询某个节点的一级子节点顶层节点即根公司每个节点带kind字段company或division与members_count。详情页头部通过AncestorBreadcrumb渲染从根到当前节点的面包屑路径如 Acme / EMEA每一层都可点击跳转。节点类型决定了税务数据的归属这是本变更的核心语义之一Company法人实体税务标识符与免税证明直接挂在本节点上Division分支/分部不持有自己的税务登记详情页侧栏渲染DivisionTaxPointerCard通过company.ancestors根优先排列向上查找最近的kind company祖先用一个指向性链接告知操作者该分部的税务登记位于其法人实体页。在$companyId.tsx中这一逻辑体现为isDivision ? DivisionTaxPointerCard : CompanyTaxIdentifiersCard同时TaxExemptionCertificatesCard仅在非 division 节点渲染。分支机构SubUnits卡片详情页主区域的SubUnitsCard列出当前节点的一级子单位每行展示名称、CompanyKindBadgecompany/division 徽标与成员数支持分页canEdit时可通过AddSubUnitDialog在父节点下新建子单位表单含name与kind两个字段parent_id由当前节点注入。成员Members与邀请InvitationsMembersCard管理有权为该企业/分支采购的买家逐条展示成员邮箱并可跳转到客户详情页。加入成员走邮箱即身份的服务端语义通过adminClient.companies.memberships.create提交customer_email服务端自动判定——已注册客户直接建立成员关系未注册邮箱则生成一条邀请记录CompanyInvitation因此新增后同时刷新 memberships 与 invitations 两个查询。邀请列表以待处理Pending徽标单独展示支持撤销revoke撤销后邮件中的令牌即失效。移除成员只收回其挂靠关系客户账号本身不受影响。地址簿Address BookAddressBookCard为节点维护多地址簿每行支持编辑、删除并可把某一地址提升为该节点的默认账单/发货地址default_billing/default_shipping指针。从源码注释可以看出其实现思路节点按每种用途一个地址持有指针提升只是移动指针因此不存在降级操作。税务标识符Tax Identifiers企业侧栏的CompanyTaxIdentifiersCard负责登记出现在发票上的税务注册号如 VAT ID、税号核心操作由use-companies.ts暴露list/create/update/delete完整的 CRUDvalidate调用adminClient.companies.taxIdentifiers.validate(companyId, id)请求已注册的校验器向税务机构核对号码结论随记录回写面板通过重新读取数据而非本地状态来呈现结果。免税证明Exemption CertificatesTaxExemptionCertificatesCard见 packages/dashboard/src/components/spree/tax-exemption-certificates-card.tsx管理该企业的采购不被征税的证据文件支持上传证书FileUploadField、选择免税理由代码TAX_EXEMPTION_REASON_CODES、国家/州与生效/到期日期StoreDatePicker受理verify与撤回revoke是独立的决策动作而非编辑——一个已被受理的证书只会被撤回不会被删除到期日期按门店时区渲染避免有效期显示提前一天。客户档案上的税务登记面板变更的另一落点是把税务能力下沉到客户维度Admin SDK 新增customer tax-identifier 端点客户详情页获得与公司同构的税务登记面板。这与企业侧形成呼应——公司登记的是法人实体的税务身份客户登记的是个人采购者的税务身份二者在 B2B 与 B2C 混合场景中各司其职。相关的 SDK 类型与客户端定义可以在 packages/admin-sdk/src/admin-client.ts 与 packages/admin-sdk/src/params.ts 中找到。税务配置Tax Rates 设置页列表页与 CRUD 表单新税率设置页位于路由/settings/tax-ratespackages/dashboard/src/routes/_authenticated/$storeId/settings/tax-rates.tsx由ResourceTable驱动的列表 新建/编辑 Sheet 组成。表格列定义见 packages/dashboard/src/tables/tax-rates.tsx名称可搜索、可排序、税率金额、管辖区国家/州组合标签、价格是否含税、是否在标签中展示税率、所属税务分类。列表操作由 RBAC 控制——permissions.can(destroy, Subject.TaxRate)决定删除按钮是否可见新建按钮包裹在Can Icreate a{Subject.TaxRate}中。表单字段与单位换算表单 schemapackages/dashboard/src/schemas/tax-rate.ts定义了完整字段集字段类型说明namestring必填税率名称amount_percentagenumber 0–100商家按百分比输入如 20tax_category_idstring必填一条税率必须且只能归属一个税务分类country_code/state_codestring可选留空表示适用于所有地区included_in_priceboolean价格是否已含税show_rate_in_labelboolean是否在价格标签中显示税率关键实现细节在taxRateValuesToParams中单位换算商家输入百分比20API 存储小数0.2amount values.amount_percentage / 100空值语义管辖区字段清空时通过blankToNull显式发送null而非省略字段——因为清空国家必须把税率拓宽回全球适用而省略键在更新时不会产生该效果。市场级税务引擎选择在配置期暴露能力缺口本变更最具设计巧思的部分是让market市场可以命名用于定价的税务引擎并同时展示该引擎无法处理的能力清单。其组件为 packages/dashboard/src/components/spree/tax-provider-field.tsx 中的TaxProviderField数据来自adminClient.taxProviders.list()useTaxProviders将其staleTime设为POSITIVE_INFINITY因为引擎在代码中注册而非存储会话内不会变化。其工作流程为GET /tax_providers返回可用引擎列表每项含id、name、available、default与unsupported_capabilities{ key, label, description }[]下拉框中未选择的市场默认使用安装级默认引擎Use default 选项因此默认引擎的能力限制同样适用于未显式选择的市场选择某个引擎后组件读取其unsupported_capabilities以Alert variantwarning带TriangleAlertIcon逐条列出该引擎不能做什么。这正是 changeset 中让商家在配置时、而不是在收到税单时才知道引擎能力差距的落地实现——例如内置引擎没有本地税务数据面向美国各州销售的市场在配置期就会得到明确提示而不是事后收到错误的税单。不可用的引擎在下拉框中以禁用项展示。Admin SDK 扩展与扩展点SDK 能力清单本次变更在spree/admin-sdk中新增/补齐的调用面由use-companies.ts与use-tax-rates.ts完整使用adminClient.companies.get / list / create / update / deleteadminClient.companies.addresses.*list/create/update/deleteadminClient.companies.memberships.*list/create/deleteadminClient.companies.invitations.*list/delete 撤销adminClient.companies.taxIdentifiers.*list/create/update/delete/validateadminClient.companies.taxExemptionCertificates.*list/create/verify/revoke/deleteadminClient.taxRates.*get/list/create/update/deleteadminClient.taxProviders.list()market 参数新增tax_providerSlot 扩展点为企业能力留白企业详情页与成员表单预留了多个Slot挂载点供扩展如 Enterprise 角色、采购额度、审批设置注入内容company.form_main/company.form_sidebar详情页主区域与侧栏的扩展位company_membership.row_meta/company_membership.row_actions成员行内的元信息与操作菜单扩展位源码注释明确角色属于 Enterprise 能力OSS 中所有成员同权因此无扩展时不渲染角色company_membership.form_fields添加成员对话框内的角色选择器挂载点未安装插件时以EnterpriseUpsell兜底说明能力边界。新增成员时slot 写入的extraParams与customer_email合并后原样提交核心代码无需知道插件拥有哪些字段。源码导读若希望深入跟踪本次变更的实现细节推荐按以下路径阅读.changeset/dashboard-companies-and-tax-rates.md变更声明本身.changeset/README.mdfixed group 与发布线机制packages/dashboard/src/hooks/use-companies.ts公司、地址簿、成员、邀请、税务标识符、免税证明的全部数据层封装packages/dashboard/src/hooks/use-tax-rates.ts税率与税务引擎数据层packages/dashboard/src/routes/_authenticated/$storeId/companies/$companyId.tsx企业详情页完整组合packages/dashboard/src/routes/_authenticated/$storeId/settings/tax-rates.tsx 与 packages/dashboard/src/schemas/tax-rate.ts税率页面与表单/单位换算packages/dashboard/src/components/spree/tax-provider-field.tsx税务引擎选择与能力缺口提示packages/dashboard/src/components/spree/tax-exemption-certificates-card.tsx免税证明生命周期管理packages/admin-sdk/src/admin-client.tsAdmin SDK 客户端端点定义。小结本次变更为 Spree Dashboard 补齐了 B2B 场景下两块高频能力一是以法人实体 分支两级组织树为核心的企业客户管理将成员、邀请、地址簿、税务标识符校验与免税证明受理完整闭环到 Admin UI二是以税率设置页 市场级税务引擎选择为核心的税务配置并借助unsupported_capabilities将引擎能力边界前置到配置期。对开发者而言这一变更同时提供了清晰的 SDK 端点形态、RBAC 权限模型与 Slot 扩展范式可直接作为自定义企业税务流程的起点。【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考