sage-x3-graphql连接器
下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/sageas--sage-x3-graphql.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @sageas/sage-x3-graphql。通过 GraphQL API 连接 Sage X3 ERP。当用户需要配置或排查 Sage X3(V12+ / 2021 R2+)的 /xtrem/api GraphQL 连接、编写 C# GraphQL 客户端代码、针对 X3 实体(x3MasterData、x3Sales、x3Purchasing、x3Stock 等)构建查询与变更(query/mutation),或排查认证、token、4GL GEN 层错误时使用本技能。
适用于任何涉及 Sage X3 GraphQL 集成的 .NET / Python 任务。
阅读全文 (展开查看完整说明)
概述
Sage X3 GraphQL 集成
通过 Syracuse 平台暴露的 GraphQL API 连接 Sage X3 ERP。
凭据安全约定(强制):本技能不保存任何服务器地址、端口、用户名、密码或测试数据。所有连接信息必须由用户在运行时通过命令行参数、环境变量或项目本地配置提供,禁止写入本技能的任何文件。
前置条件
- 版本:Sage X3 2021 R2 (12.0.25) 或更高
- 组件:必须安装并配置
X3Services_NewADC - 凭据:有效的 Syracuse 用户(具备相应功能权限)
- 网络:客户端可访问 Syracuse 端口(默认
8124)
若出现 "ETNA or XTreeM service URL must be configured",先安装 X3Services_NewADC 组件。
端点结构
| 服务 | URL 模式 |
|---|---|
| GraphQL API | http(s)://{server}:{port}/xtrem/api |
| GraphiQL IDE(浏览器) | http(s)://{server}:{port}/xtrem/explorer/ |
| REST API(旧版) | http(s)://{server}:{port}/api1/... |
关键:GraphiQL 地址必须带尾部斜杠 /explorer/,否则浏览器会重定向到站点根目录。
Syracuse 默认端口通常为 8124。
连接配置
凭据传递方式(按推荐顺序)
- 环境变量(最安全,避免密码进入命令行历史与脚本)
export X3_SERVER=<服务器地址>
export X3_PORT=8124
export X3_USERNAME=<用户名>
export X3_PASSWORD=<密码>- 命令行参数(
test_connection.py已支持,并回退读取环境变量)
python scripts/test_connection.py --server $X3_SERVER --port 8124
--username $X3_USERNAME --password "$X3_PASSWORD" [--ssl]- Python 脚本内部:从环境变量读取,不要硬编码
import os
SERVER = os.environ["X3_SERVER"]
PORT = int(os.environ.get("X3_PORT", "8124"))
USERNAME = os.environ["X3_USERNAME"]
PASSWORD = os.environ["X3_PASSWORD"]- C# 客户端:通过
IConfiguration/ User Secrets / 环境变量注入
var client = new SageX3GraphQLClient(
server: config["SageX3:Server"],
port: int.Parse(config["SageX3:Port"] ?? "8124"),
username: config["SageX3:Username"],
password: config["SageX3:Password"]
);连接排查清单
按以下顺序逐项检查:
- 网络可达性:
ping {server}或Test-NetConnection {server} -Port {port},确认主机与端口开放 - HTTP 401 Unauthorized:凭据错误或 Basic Auth 头编码有误,需向用户核实凭据
- 账户锁定:
"Your account has been locked after too many failed attempts (N)"—— Syracuse 约 10 次失败登录后锁定账户。严禁暴力尝试凭据组合,须先向用户索要正确凭据;解锁需通过 Syracuse 管理控制台或直接操作 MongoDB - HTTP 404 on
/xtrem/api:X3 版本低于 2021 R2,或X3Services_NewADC未安装 - 仅返回
{"initialized": true}:Syracuse 已运行,但 X3 端点未完整配置 - Connection refused:端口未开放或防火墙拦截(默认
8124) - TLS/SSL 错误:先试
http://;若必须使用 HTTPS,导入服务器证书
强制约束:任何情况下都不得对 Sage X3 服务器连续尝试多组凭据。账户锁定需管理员介入,代价高昂。凭据缺失时向用户索取,不要猜测。
新服务器接入流程
首次连接一台新的 Sage X3 服务器时,按此顺序验证:
- 用
test_connection.py验证连通性与凭据 - 执行 introspection 查询,确认 schema 兼容性:
{ __schema { queryType { name } mutationType { name } } }- 查询
product/supplier/site等基础实体,识别 SEED 数据变体(法语 / 中文 / 客户自定义),确认编码前缀规则 - 用一个简单变更(例如
miscellaneousReceipt)验证 4GL GEN 处理层是否可用 - 将服务器信息记录在项目本地的
.workbuddy/memory/或项目配置文件中,不要写入本技能
认证方式
方式 1:Basic Authentication(最简单)
以 Syracuse 用户名/密码作为 Basic Auth 凭据,发往 /xtrem/api 的所有请求均需携带:
Authorization: Basic base64(username:password)方式 2:Token 方式(Connected Applications)
- 在 Syracuse 中注册 Connected Application
- 配置 token 有效期(例如 60 秒)
- 从授权端点获取 bearer token
- 请求头携带
Authorization: Bearer {token}
方式 3:会话 Cookie(浏览器场景)
登录 Syracuse 后,GraphiQL 会自动使用会话 Cookie。
C# 客户端
NuGet 包
<PackageReference Include="GraphQL.Client" Version="6.*" />
<PackageReference Include="GraphQL.Client.Serializer.SystemTextJson" Version="6.*" />客户端封装
可复用的 SageX3GraphQLClient 完整实现见 assets/SageX3GraphQLClient.cs,要点:
- 构造函数接收 server / port / username / password / useSsl
- 自动组装 Basic Auth 头
- 提供泛型的
QueryAsync<T>与MutationAsync<T> - 通过 introspection 查询提供健康检查
查询示例
var request = new GraphQLRequest
{
Query = @"
{
x3MasterData {
product {
query(first: 50) {
edges {
node {
_id
code
localizedDescription1
productCategory
productStatus
stockUnit
isPurchased
isManufactured
isSold
}
}
}
}
}
}"
};
var response = await client.SendQueryAsync<ProductResult>(request);Schema 域
Sage X3 使用 camelCase 实体名(非旧版 X3 大写代码)。
| 业务域 | 根字段 | 常用实体 |
|---|---|---|
| 主数据 | x3MasterData | product、customer、supplier |
| 销售 | x3Sales | salesDelivery、salesInvoice、salesDeliveryLine |
| 采购 | x3Purchasing | purchaseOrder |
| 制造 | x3Manufacturing | workOrder、routing、routingOperation、routingVersion |
| 库存 | x3Stock | allocation、intersiteTransfer、pickTicket、stockChange、miscellaneousIssue、miscellaneousReceipt |
| 财务 | x3Finance | journalEntry、journalEntryLine、balance、supplierInvoice、prepaymentInvoice |
| 固定资产 | x3FixedAssets | — |
| 项目管理 | x3ProjectManagement | — |
| 系统工具 | xtremX3SystemUtils | — |
| 元数据 | xtremMetadata / xtremAppMetadata | — |
各域完整实体清单见 references/schema_reference.md。
查询模式
分页列表查询
{
x3MasterData {
product {
query(first: 50, after: "cursor_string") {
totalCount
edges {
node {
_id
code
localizedDescription1
productCategory
productStatus
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}按 ID 查询单个实体
{
x3MasterData {
product(id: "<产品代码>") {
_id
code
localizedDescription1
localizedDescription2
stockUnit
purchaseUnit
salesUnit
isPurchased
isManufactured
isSold
}
}
}过滤查询(两种格式,取决于服务器版本/补丁)
Sage X3 不同版本对 filter 参数的语法要求不同,按服务器表现选择。
格式 A —— GraphQL 对象(较新版本)
{
x3MasterData {
product {
query(filter: { code: { eq: "<产品代码>" } }) {
edges { node { code localizedDescription1 productStatus } }
}
}
}
}格式 B —— JSON 字符串(较旧版本)
若格式 A 返回 "String cannot represent a non string value",改用 JSON 编码字符串:
{
x3MasterData {
product {
query(filter: "{"code":"<产品代码>"}") {
edges { node { code localizedDescription1 isPurchased } }
}
}
}
}注意事项
contains/like并非所有字段都支持。服务器拒绝过滤操作符时,降级为分页拉取全量后在客户端过滤- 分页游标
after可能包含",[,]等字符,程序化拼接查询串时必须转义"、与换行
变更(Mutation)
Sage X3 变更使用 create(_id: ID, data: {...}) 模式。_id 为实体主键(通常为代码),data 中为 Product_Input / Customer_Input 等输入类型字段。
类型规则(关键)
| 类型 | 传值方式 | 示例 |
|---|---|---|
| ExternalReference | 纯字符串,不是 { code: "..." } 对象 | customerCategory: "CN" |
| Enum | 不加引号的枚举值 | customerType: normal |
| 嵌套集合 | 数组/对象,每项带 _action | addresses: { _action: create, ... } |
| _etag | 仅放在 data 中(非变更参数) | update 前先读取以获得 _etag |
产品创建
mutation {
x3MasterData {
product {
create(
_id: "<产品代码>",
data: {
code: "<产品代码>"
localizedDescription1: "<描述>"
productCategory: "<产品分类代码>"
isActive: true
}
) {
_id
code { code }
localizedDescription1
}
}
}
}最小必填字段:code、localizedDescription1、productCategory、isActive。
客户创建(含地址,模板)
mutation {
x3MasterData {
customer {
create(
_id: "<客户代码>",
data: {
code: "<客户代码>"
customerCategory: "<客户分类代码>"
companyName1: "<公司全称>"
shortCompanyName: "<简称>"
customerType: normal
currency: "CNY"
country: "CHN"
isActive: true
addresses: {
_action: create
code: "1"
description: "总部"
city: "<城市>"
country: "CHN"
isDefault: true
addressLines: {
_action: create
code: "1"
addressLine: "<详细地址>"
}
}
}
) {
_id
code { code }
companyName1
customerCategory { code }
addresses { edges { node { code description city } } }
}
}
}
}Customer_Input 约 130 个字段,要点:
- 必填:
code、customerCategory、companyName1、currency - 建议:
shortCompanyName、customerType、country、isActive - 嵌套:
addresses(含addressLines)、contacts、bankDetails _etag:仅用于update(乐观锁)
嵌套集合的 _action
嵌套集合(addresses、contacts、行项目)每一项必须带 _action:
_action: create—— 新增_action: update—— 修改(需匹配code)_action: delete—— 删除
杂项入库(miscellaneousReceipt)模板
mutation {
x3Stock {
miscellaneousReceipt {
create(data: {
stockSite: "<站点代码>"
effectiveDate: "<YYYY-MM-DD>"
documentDescription: "<描述>"
entryType: miscellaneousReceipt
miscellaneousReceiptLines: [{
_action: create, lineNumber: 10
product: "<产品代码>"
packingUnit: "<包装单位>"
quantityInPackingUnit: 10
stockUnit: "<库存单位>"
quantityInStockUnit: 10
packingUnitToStockUnitConversionFactor: 1
}]
}) { _id }
}
}
}变更可用性与 4GL GEN 层
演示/SEED 环境的 X3 4GL「生成处理」(GEN*)层可能只部分配置:部分实体可用,部分不可用。
| 错误信息 | 含义 |
|---|---|
"发生了一个错误。请联系您的管理员。支持ID:gen-XXX" | GEN 层已运行但触发运行时错误(主数据缺失、会计期已关闭、序列计数器异常等) |
"相应的生成处理不存在。" | 该实体类型的 GEN* 处理未安装/未部署 |
"字段 XXX : 必填字段" | 缺少必填字段,补齐后重试 |
实践结论
miscellaneousReceipt通常可用,可作为验证 GEN 层是否工作的探针purchaseOrder在部分演示环境因 POH GEN 处理问题失败(与字段组合无关,最小字段/带行项目均同样失败)x3MasterData部分实体可能返回「相应的生成处理不存在」- 变更失败时,先用
miscellaneousReceipt判断是 GEN 层整体不可用还是单实体问题 - 若
purchaseOrder变更不可用,可用miscellaneousReceipt直接入库替代。注意:这产生的是库存收货单,不触发采购流程(PO → 收货 → 发票)
采购订单(purchaseOrder)字段命名要点
输入字段名与直觉命名不同,务必核对:
| 语义 | 实际字段 |
|---|---|
| 供应商 | orderFromSupplier(不是 supplier) |
| 采购站点 | purchaseSite(不是 stockSite) |
| 行数量 | quantityInOrderUnitOrdered(不是 quantity) |
| 单价 | grossPrice(不是 purchaseUnitPrice) |
PurchaseOrder_Input 约 111 个字段、PurchaseOrderLine_Input 约 182 个字段(随版本变化)。完整字段列表用 introspection 获取:
{ __type(name: "PurchaseOrder_Input") { fields { name type { name kind ofType { name } } } } }返回字段选择(输出类型 ≠ 输入类型)
读取返回值时,字段类型为对象类型,需展开子查询:
| 字段 | 类型 | 查询写法 |
|---|---|---|
orderFromSupplier | Supplier(对象) | orderFromSupplier { code { code } } |
purchaseSite | Site(对象) | purchaseSite { code } |
receiptSite | Site(对象) | receiptSite { code } |
currency | Currency(对象) | currency { code } |
company | Company(对象) | company { code } |
purchaseOrderLines | PurchaseOrderLine_Collection | purchaseOrderLines { query(first: 50) { edges { node { ... } } } } |
关键陷阱:Supplier.code 的类型是 BusinessPartner(对象)而非标量,而 BusinessPartner.code 才是 String 标量。因此取供应商代码字符串需两层展开:orderFromSupplier { code { code } }。
PurchaseOrderLine_Collection 不支持 totalCount、nodes 或直接 edges,仅有 query、readAggregate、queryAggregate 三个字段:
purchaseOrderLines {
query(first: 50) {
edges {
node { lineNumber product { code } quantityInOrderUnitOrdered grossPrice }
}
}
}PurchaseOrderLine 输出类型约 187 个字段:lineNumber 为 Int 标量,product 为 Product 对象(用 product { code }),grossPrice / netPrice / quantityInOrderUnitOrdered 为 Decimal 标量。
HTTP 细节
- 方法:GraphQL 一律
POST(查询也是) - Content-Type:
application/json - Accept:
application/json - 请求体格式:
{
"query": "query { ... }",
"variables": null,
"operationName": null
}故障排查
| 现象 | 处理 |
|---|---|
"ETNA or XTreeM service URL must be configured" | 安装 X3Services_NewADC 组件 |
| HTTP 401 | 核实凭据;检查 Basic Auth 头编码;注意账户锁定风险 |
HTTP 404 on /xtrem/api | 确认 X3 ≥ 2021 R2 且组件已安装 |
"Must provide query string" | 请求体缺少有效的 query 字段 |
"Endpoint not found: application x3, contract erp, dataset X" | 核对端点配置中的 folder/dataset 名称 |
"String cannot represent a non string value" | filter 需改用 JSON 字符串格式(格式 B) |
"未找到记录:{...}" | 引用的主数据(站点/供应商/产品)在该环境不存在,先查询实际编码规则 |
| Connection refused | 检查端口(默认 8124)与防火墙 |
| TLS/SSL 错误 | 未配置 TLS 时使用 http://;否则导入服务器证书 |
参考资料
references/schema_reference.md—— 各域实体清单与 Product 字段分组references/csharp_patterns.md—— C# 进阶模式(DI 注册、Polly 重试、Repository、取消令牌、错误处理、凭据安全存储)
资产
assets/SageX3GraphQLClient.cs—— C# 客户端封装完整实现scripts/test_connection.py—— 连通性测试脚本(参数或环境变量传入凭据,不落盘)