wms接口开发说明

  

1   概述

zdb平台与第三方平台对接的一个范例。

基于sealink wms定义的接口实现。

接口技术要求简述如下:

l  http协议

l  消息body采用json格式

l  通过url传递系统参数

 

zdb端实现上行部分的接口(WTE),2个平台之间彼此调用,实现业务流程的衔接。

 

本文用采购进货和验收确认为例描述具体的代码实现。

 

2   接口

作为开发示例的2个接口定义如下。

2.1    进货通知(ETW_PURCHASE)

zdb在采购订单审核后调用。

 

请求参数

名称

类型

是否必须

示例值

更多限制

描述

sheetid

String

 

 

 

warehouse_no

String

 

 

仓库编码

owner_no

String

123

 

货主编码

org_no

String

 

 

机构代码

venderid

String

 

 

进货供货商编码

purchase_no

String

 

 

采购单号

sdate

Date

 

 

采购单审核日期

checker

String

 

 

制单员姓名

class_type

String

 

 

类型

purdate

Date

 

 

送货日期

validdate

Date

 

 

有效日期

notes

String

 

 

订单说明

orderlist

Purchase[]

 

 

 

serialid

Number

 

 

单内序号

owner_article_no

String

 

 

商品编码

pkcount

Number

 

 

订货规格

qty

Number

 

 

进货总量

owner_cust_no

String

 

 

客户代码

cust_qty

Number

 

 

客户要货量

cust_po_no

String

 

 

客户订单号

cust_note

String

 

 

客户备注

 

响应参数

名称

类型

示例值

描述

flag

String

success

 

code

String

000

返回状态码

message

String

 

返回状态描述

 

 

2.2    验收确认(WTE_IM_CHECK)

wms调用。

请求参数

名称

类型

是否必须

示例值

更多限制

描述

sheetid

String

 

 

传单单据编号

warehouse_no

String

 

 

仓库编码

owner_no

String

123

 

货主编码

po_no

String

 

 

进货通知单号

checkno

String

 

 

验收单号

supplier_no

String

 

 

供货商编码

sdate

Date

 

 

验收时间

orderlist

Purchase[]

 

 

 

serialid

Number

 

 

单内序号

owner_article_no

String

 

 

商品编码

prodate

Date

 

 

生产日期

qty

Number

 

 

验收总量

 

响应参数

名称

类型

示例值

描述

flag

String

success

 

code

String

000

返回状态码

message

String

 

返回状态描述

 

3   实现

ETW接口实现在client,WTE接口实现在server模块中。

3.1    进货通知(ETW_PURCHASE)

3.1.1    请求定义

根据接口定义文档定义请求业务对象和请求传输请求体对象。

 

请求业务对象类型:

///< 进货通知单

struct CPurchase {

       string sheetid_;/// 传单单据编号   

       string warehouse_no_;/// 仓库编码

       string owner_no_;/// 货主编码     

       string org_no_; /// 机构代码

       string venderid_; /// 进货供货商编码

       string purchase_no_;/// 采购单号 

       string sdate_; /// 采购单审核日期 

       string checker_;/// 制单员姓名     

       string class_type_;/// 类型    

       string purdate_; /// 送货日期

       string validdate_;///有效日期

       string notes_;/// 订单说明    

       struct CItem { ///< 商品明细

              int serialid_;///单内序号

              string owner_article_no_;

             int pkcount_; ///< 订货规格

              double qty_; ///     进货总量

              string owner_cust_no_;/// 客户代码     

              double cust_qty_;///客户要货量    

              string cust_po_no_;/// 客户订单号

              string cust_note_; /// 客户备注    

              CItem():serialid_(0),qty_(0),cust_qty_(0),pkcount_(1) {

              }

              MEMBER_DEFINE(CItem);

              int Load(mpm_ns::CPurchase::CPurchaseDetail &item);

       };

       CAutoVector<CItem*> items_; ///< 商品明细

 

       CPurchase() {

              org_no_ = ORG_NO;

              class_type_ = "0";

       }

 

       MEMBER_DEFINE(CPurchase);

       int Load(mpm_ns::CPurchase &purchase);

};

 

请求体类型:

///< 进货通知单请求体

struct CPurchaseRequestBody : public CMasterSlaveRequestBody<CPurchase,CPurchase::CItem> {

       MEMBER_DEFINE(CPurchaseRequestBody);

 

       CPurchaseRequestBody():CMasterSlaveRequestBody("orderlist") {

              method_ = "ETW_PURCHASE";

       }

};

 

CMasterSlaveRequestBody为主从结构类型的请求体,模板参数CPurchase为请求业务对象类型,CPurchase::CItem为明细类型。

orderlist为明细数组名称。

ETW_PURCHASE为方法名称。

 

3.1.2    请求与消息绑定

绑定建立json消息与对象成员之间的映射。

SET_MEMBER_BEGIN(CPurchase)

       SET_MEMBER2(CPurchase,sheetid_,"sheetid",false),

       SET_MEMBER2(CPurchase,warehouse_no_,"warehouse_no",false),

       SET_MEMBER2(CPurchase,owner_no_,"owner_no",false),

       SET_MEMBER2(CPurchase,org_no_,"org_no",false),

       SET_MEMBER2(CPurchase,venderid_,"venderid",false),

       SET_MEMBER2(CPurchase,purchase_no_,"purchase_no",false),

       SET_MEMBER2(CPurchase,sdate_,"sdate",false),

       SET_MEMBER2(CPurchase,checker_,"checker",true),

       SET_MEMBER2(CPurchase,class_type_,"class_type",false),

       SET_MEMBER2(CPurchase,purdate_,"purdate",false),

       SET_MEMBER2(CPurchase,validdate_,"validdate",true),

       SET_MEMBER2(CPurchase,notes_,"notes",true),

       SET_MEMBER2(CPurchase,purdate_,"purdate",false),

       SET_MEMBER2(CPurchase,validdate_,"validdate",true),

SET_MEMBER_END(CPurchase)

 

SET_MEMBER_BEGIN(CPurchase::CItem)

       SET_MEMBER2(CPurchase::CItem,serialid_,"serialid",false),

       SET_MEMBER2(CPurchase::CItem,owner_article_no_,"owner_article_no",false),

       SET_MEMBER2(CPurchase::CItem,pkcount_,"pkcount",true),

       SET_MEMBER2(CPurchase::CItem,qty_,"qty",false),

       SET_MEMBER2(CPurchase::CItem,owner_cust_no_,"owner_cust_no",true),

       SET_MEMBER2(CPurchase::CItem,cust_qty_,"cust_qty",true),

       SET_MEMBER2(CPurchase::CItem,cust_po_no_,"cust_po_no",true),

       SET_MEMBER2(CPurchase::CItem,cust_note_,"cust_note",true),

SET_MEMBER_END(CPurchase::CItem)

 

SET_MEMBER2的3个参数含义分别如下:成员变量名称,接口参数名称,是否允许空。

 

3.1.3    接口转换

接口转换把业务对象转换为请求对象。

本步骤基于业务相关设计人员对接口转换规则明确描述后进行。

业务对象是zdb系统内部描述业务的对象,请求对象为接口定义的用于接口之间的调用的对象。

本接口的业务对象类型为mpm_ns::CPurchase,转换为上面定义的CPurchase类型,包括明细类型转换。

下行转换方法为Load,上行转换方法为Output。

 

业务对象转换为请求对象

int CPurchase::Load(mpm_ns::CPurchase &purchase) {

       GET_SHARDINGID(purchase.eid_,_inner_env_->sharding_id_,-1);

       this->sheetid_ = GetSheetId();

       this->warehouse_no_ = LogMsg("%d",purchase.stock_id_);

       this->owner_no_ = LogMsg("%d",purchase.eid_);

       this->org_no_ = ORG_NO;

       this->venderid_ = LogMsg("%d",purchase.co_eid_);

       this->purchase_no_ = GET_UNIQUE_SHEETID(_inner_env_->sharding_id_,purchase.sheet_id_);

       this->sdate_ = purchase.check_date_;

       this->checker_ = purchase.checker_;

       this->class_type_ = "0";

       this->purdate_ = purchase.delivery_date_;

       this->notes_ = purchase.notes_;

 

       if (purchase.details_.size()==0)

              return 0;

       vector<CSheetDetail*>::iterator iter = purchase.details_[0]->begin();

       while(iter!=purchase.details_[0]->end()) {

              mpm_ns::CPurchase::CPurchaseDetail *detail = (mpm_ns::CPurchase::CPurchaseDetail*)*iter;

              CPurchase::CItem *item = new CPurchase::CItem;

              item->Load(*detail);

              this->items_.push_back(item);

              iter++;

       }

 

       return 0;

}

 

此方法从业务对象(mpm_ns::CPurchase类型)生成对应的请求对象数据。

GET_UNIQUE_SHEETID用于生成唯一单据编号,由于单据编号在zdb各分区主站内唯一,但全局不唯一,因此由分区id和原始单据编号拼接而成,分区id占起始4个字符。

上行确认时需要反向操作,拆分出分区id和原始单据编号。

 

明细类型转换

int CPurchase::CItem::Load(mpm_ns::CPurchase::CPurchaseDetail &item) {

       this->serialid_ = item.line_num_;

       this->owner_article_no_ = LogMsg("%lu",item.goods_id_);

       this->pkcount_ = item.pack_unit_qty_;

       this->qty_ = item.bulk_qty_ + item.pack_qty_*item.pack_unit_qty_;

       this->cust_note_ = item.notes_;

 

       return 0;

}

 

3.1.4    增加事件处理函数

在插件头文件中声明采购订单审核事件函数,并实现。

int CSealinkWMS::OnNewPurchase(CEvent *e) {

       return HandleMasterSlave<mpm_ns::CPurchase,CPurchaseRequestBody>(e,"OnNewPurchase");

}

 

3.1.5    登记事件

在event_handle_map中增加事件响应函数项。

CEventHandleMapItem event_handle_map[] = {

       {EVENT_NEW_PURCHASE,(EventHandleFunc)&CSealinkWMS::OnNewPurchase},///<进货通知

};

 

EVENT_NEW_PURCHASE是在采购订单审核后由业务系统激发,由wms接口的事件代理捕获,执行上面注册的函数CSealinkWMS::OnNewPurchase。

 

3.2    验收确认(WTE_IM_CHECK)

3.2.1    请求定义

根据接口定义文档定义请求业务对象和请求传输请求体对象。

 

请求业务对象类型:

///< 验收(进货)确认单

struct CPurchaseAck : public CAckBase {

    string sheetid_;/// 传单单据编号 STRING(20) 不允许 

    string warehouse_no_;/// 仓库编码    STRING(3)  不允许 仓库编码

    string po_no_; /// 进货通知单号  STRING(20) 不允许 进货通知单号

    string checkno_; /// 验收单号    STRING(20) 不允许 WMS验收单单号)

    string supplier_no_; /// 供货商编码  STRING(10) 不允许 进货供货商编码

    string sdate_;/// 验收时间   date       日期格式:2008-10-11

 

    struct CItem {

        int serialid_;///单内序号    NUMBER 不允许 采购单内序号

        string owner_article_no_;/// 商品编码    STRING(20) 不允许 

        double qty_; /// 验收总量    Decimal(12,3)

        string prodate_;/// 生产日期 date   允许

        CItem():qty_(0),serialid_(1) {

        }

        MEMBER_DEFINE(CItem);

        int Output(gsm_ns::CStorage::CStorageDetail &item);

    };

 

    CAutoVector<CItem*> items_;

 

    CPurchaseAck() {

    }

    MEMBER_DEFINE(CPurchaseAck);

    int Output(gsm_ns::CStorage &storage);

};

 

这里只实现Output方法,把请求业务对象转换为系统业务对象。

 

请求体类型:

///< 进货确认单请求体

struct CPurchaseAckRequestBody : public CMasterSlaveRequestBody<CPurchaseAck,CPurchaseAck::CItem> {

    MEMBER_DEFINE(CPurchaseAckRequestBody);

 

    CPurchaseAckRequestBody():CMasterSlaveRequestBody("orderlist") {

        method_ = "WTE_IM_CHECK";

    }

};

CMasterSlaveRequestBody为主从结构类型的请求体,模板参数CPurchaseAck为请求业务对象类型,CPurchaseAck::CItem为明细类型。

orderlist为明细数组名称。

WTE_IM_CHECK为方法名称。

 

3.2.2    请求与消息绑定

绑定建立json消息与对象成员之间的映射。

SET_MEMBER_BEGIN(CPurchaseAck)

    SET_MEMBER2(CPurchaseAck,sheetid_,"sheetid",false),

    SET_MEMBER2(CPurchaseAck,warehouse_no_,"warehouse_no",false),

    SET_MEMBER2(CPurchaseAck,owner_no_,"owner_no",false),

    SET_MEMBER2(CPurchaseAck,po_no_,"po_no",false),

    SET_MEMBER2(CPurchaseAck,checkno_,"checkno",false),

    SET_MEMBER2(CPurchaseAck,supplier_no_,"supplier_no",false),

    SET_MEMBER2(CPurchaseAck,sdate_,"sdate",true),

SET_MEMBER_END(CPurchaseAck)

 

SET_MEMBER_BEGIN(CPurchaseAck::CItem)

    SET_MEMBER2(CPurchaseAck::CItem,owner_article_no_,"owner_article_no",false),

    SET_MEMBER2(CPurchaseAck::CItem,prodate_,"prodate_",true),

    SET_MEMBER2(CPurchaseAck::CItem,qty_,"qty",false),

    SET_MEMBER2(CPurchaseAck::CItem,serialid_,"serialid",false),

SET_MEMBER_END(CPurchaseAck::CItem)

 

3.2.3    接口转换

把请求对象转换为业务对象。

int CPurchaseAck::Output(gsm_ns::CStorage &storage) {

    storage.eid_ = atoi(this->owner_no_.c_str());

    string dbc_name;

    if (PinDB(dbc_name))

        return -1;

    storage.dbc_name_ = dbc_name;

 

    storage.stock_id_ = atoi(this->warehouse_no_.c_str());

    SEPARATE_SHEETID(this->po_no_,storage.ref_sheet_id_,-1);

    storage.co_eid_ = atoi(this->supplier_no_.c_str());

    storage.check_date_ = this->sdate_;

    storage.notes_ = ACK_NOTES_TEXT;

    storage.creator_ = ACK_USER;

    storage.oper_date_ = CDateTime::Now().GetDateTime();

 

    if (this->items_.size()==0)

        return 0;

 

    vector<CPurchaseAck::CItem*>::iterator iter = items_.begin();

    while(iter!=items_.end()) {

        CPurchaseAck::CItem *item = *iter;

        gsm_ns::CStorage::CStorageDetail *detail =  new gsm_ns::CStorage::CStorageDetail;

        if (item->Output(*detail))

            return -1;

        storage.details_[0]->push_back(detail);

        iter++;

    }

 

    return 0;

}

 

PinDB根据请求对象内容的货主,确定数据库分区并存储在TLS中,获取数据库连接名。

SEPARATE_SHEETID从请求对象的单据编号,分离出原始单据编号。

3.2.4    增加响应函数

int CSealinkWMS::OnPurchaseAck(string &request,CResponseBodyBase **response) {

       CPurchaseAckRequestBody req;

       return req.Handle<gsm_ns::CStorage >(request, SDT_PURCHASE,6049);

}

 

request为请求的消息体(json)内容.

这里Handle调用的含义是对采购确认生成入库单(gsm_ns::CStorage类型),SDT_PURCHASE为入库类型,入库后自动审核,审核采用6049协议。

 

3.2.5    登记接口

在GetHandleFunc函数的func_maps中增加响应函数入口项:

HandleRequestFuncPtr GetHandleFunc(string &method) {

       static struct CFuncMap {

              string method_;

              HandleRequestFuncPtr func_ptr_;

       } func_maps[] = {

              {"WTE_IM_CHECK",&CSealinkWMS::OnPurchaseAck},///<验收(进货)确认

       };

       for (unsignedint i=0;i<sizeof(func_maps)/sizeof(func_maps[0]);i++) {

              CFuncMap &item = func_maps[i];

              if (stricmp(item.method_.c_str(),method.c_str())==0)

                     return item.func_ptr_;

       }

       return 0;

}

 

 

 

4   后记

基于一份有映射关系的接口文档开发,根据接口文档声明类型;根据业务数据映射规则进行成员赋值。

 

所采用的实现已经尽可能简化了。

基于此方法开发,工作量容易评估,bug率及重复率低,维护扩展容易。

如增加一参数,基本就增加一个变量,绑定一下,映射一下,共3行代码就可以解决。

若接口支持xml,这些代码无需任何变动。

 

理论上,再简化还有2个方向:

l  应用无关:不涉及业务对象,这是不同的抽象级别,完全是另一种实现

l  代码生成工具:程序就是取代人做重复的程序化的事情的,基于接口描述生成上面的代码主干再修改。

工具的价值取决于重复使用量,低价值的工具不值得开发。

 

本文就如何进行此类开发进行演示说明,背后的支撑是广泛的,不在此赘言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值