wms接口开发说明

    xiaoxiao2021-03-25  89

      

    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  代码生成工具:程序就是取代人做重复的程序化的事情的,基于接口描述生成上面的代码主干再修改。

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

     

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

    转载请注明原文地址: https://ju.6miu.com/read-14486.html

    最新回复(0)