Skip to content

OMS OpenAPI接口架构和使用指南

你是 OMS 系统OpenAPI接口架构专家,熟悉OpenAPI的整体架构、请求流程、签名算法、响应格式、错误处理机制和调用方法。

核心概念

OMS系统提供了丰富的开放API接口,供外部系统进行数据交互。所有API接口采用统一的架构设计,包括系统级参数、签名验证、权限控制和响应格式。

系统架构

请求流程

OpenAPI接口的请求处理流程如下:

  1. 参数接收:接收POST请求参数,包括系统级参数和应用级参数
  2. 参数解析:解析method参数,提取class和method名称
  3. 系统参数检查:验证系统级参数(ver, charset, type, method, flag, timestamp, sign)
  4. 签名验证:验证请求签名是否正确
  5. 时间戳验证:检查时间戳是否在有效范围内(±3600秒)
  6. 防重复验证:检查签名是否已存在于缓存中(防重复提交)
  7. 接口存在性检查:验证接口类和方法是否存在
  8. 权限检查:验证调用方是否有权限访问该接口
  9. 参数验证:验证应用级参数是否符合要求
  10. 接口调用:执行接口方法,获取原始数据
  11. 数据格式化:按照模板格式化输出数据
  12. 响应返回:返回成功或错误响应

核心类说明

  • openapi_entrance:入口类,负责参数解析、签名验证、权限检查
  • openapi_object:接口对象类,负责接口实例化、参数验证、接口调用
  • openapi_response:响应类,负责响应格式化、错误处理
  • openapi_privilege:权限类,负责权限验证
  • openapi_setting:配置类,负责配置管理
  • openapi_errorcode:错误码类,负责错误码定义

请求方式

请求URL

http(s)://[域名]/index.php/openapi/rpc/service/

请求方法

所有API接口均支持POST方式请求。

系统级参数

所有API请求必须包含以下系统级参数:

参数名类型必选描述
vernumber接口版本号,默认值:1
charsetstring字符编码,支持:utf-8,默认值:utf-8
typestring返回数据格式,支持:json,默认值:json
methodstring接口方法名,格式:class.method
flagstring来源标识,对应系统中配置的接入方标识
timestampstring时间戳,单位:秒,必须在服务器时间±3600秒范围内
signstring签名,详见签名算法章节

method参数格式

method参数格式为:{class}.{method}

例如:

  • orders.getList - 订单列表接口
  • sales.getList - 销售单列表接口
  • stock.getAll - 库存查询接口

签名算法

签名生成步骤

  1. 收集所有请求参数(不包括sign本身)
  2. 按照参数名的ASCII码顺序进行排序(ksort)
  3. 递归拼接参数名和参数值(对于嵌套数组,递归处理)
  4. 对拼接后的字符串进行MD5加密,再转大写
  5. 将上一步的结果与token(接口密钥)拼接
  6. 再次进行MD5加密并转大写,得到最终签名

签名算法代码示例(PHP)

php
// 签名生成函数
function gen_sign($params, $token)
{
    // 参数排序
    ksort($params, SORT_STRING);
    
    // 拼接字符串
    $assemble_str = '';
    foreach($params AS $key=>$val){
        if(is_null($val)) continue;
        if(is_bool($val)) $val = ($val) ? 1 : 0;
        $assemble_str .= $key . (is_array($val) ? assemble($val) : $val);
    }
    
    // 生成签名
    return strtoupper(md5(strtoupper(md5($assemble_str)).$token));
}

// 递归拼接数组参数
function assemble($params)
{
    if(!is_array($params)) return null;
    
    ksort($params, SORT_STRING);
    
    $sign = '';
    foreach($params AS $key=>$val){
        if(is_null($val)) continue;
        if(is_bool($val)) $val = ($val) ? 1 : 0;
        $sign .= $key . (is_array($val) ? assemble($val) : $val);
    }
    
    return $sign;
}

签名防重复机制

  • 系统会缓存生成的签名1小时(3600秒)
  • 相同签名的重复请求将被拒绝,返回错误码:e000009

响应格式

成功响应

json
{
  "response": {
    // 具体接口返回数据
  }
}

错误响应

json
{
  "error_response": {
    "code": "错误码",
    "msg": "错误信息",
    "sub_msg": "详细错误信息(可选)"
  }
}

系统级错误码

错误码描述可能原因
e000001system params lost or error系统级参数缺失或错误
e000002sign error签名错误,请检查签名算法和参数
e000003class or method not exist接口类或方法不存在
e000004no permissions to access没有权限访问该接口
e000005init interface fail初始化接口失败
e000006application params error应用级参数错误
e000007init template fail初始化模板失败
e000008refer server time invalid时间戳无效,与服务器时间偏差过大
e000009repeat request invalid重复请求,签名已存在于缓存中

调用示例

PHP示例

php
<?php
// 应用标识(需要替换为实际的flag)
$flag = 'your_oms_flag';

// 私钥(需要替换为实际的token)
$token = 'your_interface_key';

// 接口方法(例如,查询订单列表:orders.getList)
$method = 'orders.getList';

// 系统级参数
$systemParams = array(
    'flag' => $flag, // 应用标识
    'method' => $method, // 接口方法
    'ver' => 1,
    'charset' => 'utf-8',
    'type' => 'json',
    'timestamp' => time(),
);

// 应用级参数
$ApiParams = array(
    'start_time' => '2025-10-01 00:00:00',
    'end_time' => '2025-11-01 00:00:00',
    'page_no' => 1,
    'page_size' => 50
);

// 组装接口参数
$params = array_merge($systemParams, $ApiParams);

// 签名生成函数
function gen_sign($params, $token)
{
    // 参数排序
    ksort($params, SORT_STRING);
    
    // 拼接字符串
    $assemble_str = '';
    foreach($params AS $key=>$val){
        if(is_null($val)) continue;
        if(is_bool($val)) $val = ($val) ? 1 : 0;
        $assemble_str .= $key . (is_array($val) ? assemble($val) : $val);
    }
    
    // 生成签名
    return strtoupper(md5(strtoupper(md5($assemble_str)).$token));
}

// 递归拼接数组参数
function assemble($params)
{
    if(!is_array($params)) return null;
    
    ksort($params, SORT_STRING);
    
    $sign = '';
    foreach($params AS $key=>$val){
        if(is_null($val)) continue;
        if(is_bool($val)) $val = ($val) ? 1 : 0;
        $sign .= $key . (is_array($val) ? assemble($val) : $val);
    }
    
    return $sign;
}

// 生成签名
$params['sign'] = gen_sign($params, $token);

// curl发送请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http(s)://www.***.com/index.php/openapi/rpc/service/');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

// 处理响应
$result = json_decode($response, true);

// 测试Api接口返回的结果
echo('<pre>Response:<br>');
print_r($response);
echo('<br><br>Result:<br>');
print_r($result);
exit;

Java示例(使用HttpClient)

java
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;

import java.security.MessageDigest;
import java.util.*;

public class OpenApiClient {
    
    public static void main(String[] args) throws Exception {
        // 接口URL
        String url = "http://your-domain.com/index.php/openapi/rpc/service/";
        
        // 接口参数
        Map<String, String> params = new TreeMap<>(); // TreeMap自动按键排序
        params.put("ver", "1");
        params.put("charset", "utf-8");
        params.put("type", "json");
        params.put("method", "orders.getList");
        params.put("flag", "test_flag");
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("start_time", "2024-01-01 00:00:00");
        params.put("end_time", "2024-01-31 23:59:59");
        params.put("page", "1");
        params.put("page_size", "20");
        
        // 生成签名
        String token = "your_interface_key";
        String assembleStr = assemble(params);
        String sign = md5(md5(assembleStr).toUpperCase() + token).toUpperCase();
        params.put("sign", sign);
        
        // 发送请求
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httppost = new HttpPost(url);
        
        List<NameValuePair> nvps = new ArrayList<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        httppost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        
        CloseableHttpResponse response = httpclient.execute(httppost);
        try {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                System.out.println(EntityUtils.toString(entity));
            }
        } finally {
            response.close();
        }
    }
    
    // 拼接参数
    private static String assemble(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            sb.append(entry.getKey()).append(entry.getValue());
        }
        return sb.toString();
    }
    
    // MD5加密
    private static String md5(String str) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str.getBytes("UTF-8"));
        byte[] digest = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}

支持的API模块

系统支持以下API模块:

模块名描述主要方法
orders订单getList, getCouponList, getPmtList
sales销售单getList, getSalesAmount, getDeliveryList
aftersales售后单getList
refunds退款单getList, getDetailList
delivery发货单getList
po采购单add, getList, cancel
purchasereturn采购退货单getList, add, cancel
transfer出入库单add, getList, getIsoList
stock库存查询getAll, getDetailList, getBarcodeStock, getBnStock
inventory库存管理getList, getDetail, getApplyDetail, getApplyList
stockdump转储单getList
workorder加工单getList
appropriation调拨单getList, add
warehouse仓库转仓单getList, add
basicmaterial基础物料getList, add, edit
salesmaterial销售物料getList, add, edit
branch仓库getList
brand品牌getList
shop店铺getList, add
supplier供应商add, edit
member会员add, edit
finance财务getList, getJZT, getJDbill, getReportItems
ar应收账款getList
invoice发票操作getList, update, getResultList
iostock出入库明细getList

权限控制

OpenAPI接口采用基于配置的权限控制机制:

  1. 配置管理:每个接入方(flag)在系统中配置允许访问的接口列表
  2. 权限验证:系统在接口调用前验证调用方是否有权限访问该接口
  3. 配置格式config[class][method] 格式,例如:config[orders][getList]
  4. 权限检查:如果调用方没有权限,返回错误码:e000004

数据脱敏

部分敏感数据(如客户信息、联系方式等)在API返回时可能会进行脱敏处理。脱敏配置在接入方配置中设置(is_data_mask字段)。

注意事项

  1. 密钥管理:请妥善保管接口密钥(token),避免泄露
  2. 时间戳同步:时间戳必须与服务器时间保持同步,误差不超过3600秒
  3. 防重复提交:每个请求必须生成唯一的签名,避免重复提交
  4. 参数选择:请根据实际业务需求选择合适的API接口和参数
  5. 分页控制:对于大数据量查询,请使用分页参数控制返回结果数量
  6. 签名检查:如遇签名错误,请仔细检查参数拼写、排序及token是否正确
  7. 调用频率:为保证系统稳定性,API调用可能存在频率限制,具体限制规则请联系系统管理员获取

参考文档

  • 订单API:oms-openapi-orders.md
  • 销售单API:oms-openapi-sales.md
  • 库存查询API:oms-openapi-stock.md
  • 其他业务接口Skills:oms-openapi-{api-name}.md

Guidelines

  1. 签名算法:严格按照签名算法步骤生成签名,注意参数排序和递归处理
  2. 错误处理:根据错误码判断错误类型,e000002通常是签名错误,e000004是权限错误
  3. 时间戳:使用当前时间的Unix时间戳(秒),确保与服务器时间同步
  4. 参数验证:在调用接口前,确保所有必填参数都已提供
  5. 响应处理:检查响应中的error_response字段,判断请求是否成功
  6. 日志记录:系统会自动记录所有API调用日志,便于问题排查