zhangzengfei
2023-07-13 89ce2bc6b71ea331c219c295074a289d09c808af
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package kingdee
 
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "mime/multipart"
    "net/http"
    "strconv"
    "time"
 
    "kingdee-dbapi/config"
    "kingdee-dbapi/logger"
    "kingdee-dbapi/nsqclient"
)
 
var JoHeadTemplate = `
    {
        "fdate": "%s",  //日期 当天日期
        "ftype": 1054, //固定值
        "forderinterid": 0, //固定值
        "fpporderinterid": 0, //固定值
        "fparentinterid": 0, //固定值
        "fsupplyid": 0, //固定值
        "fplanconfirmed": 0, //计划确认
        "fplanmode": 14036,  //计划模式
        "fworktypeid": 55, //生产类型
        "fmrp": 1052, //单据来源
        "fbomcategory": 36820, //BOM 类别
        "fcardclosed": 1059, //流转卡关联关闭
        "fprintcount": 0, //打印次数
        "ffinclosed": 0, //财务结算标志
        "ffinclosedate": "", //财务结算日期
        "ffincloseer": 0, //财务结算人
        "fmtono": " ", //计划跟踪号:
        "fauxqtyforitem": 0, //因料报废数量
        "funitid": 0, //单位 接口自动获取, 设置成0就可以
        "fcostobjid": 0, //成本对象 , 接口自动获取, 设置成0就可以
        "fbominterid": 0, //BOM编号 接口自动获取, 设置成0就可以
        "fbillerid": 16394, //与制单人一致
        "fplancategory": 2, //计划类别
        "fcheckdate": "%s", //制单日期
        "fstartdate": "%s", //开工日期
        "ffinishdate": "%s", //完工日期
        "fplancommitdate": "%s",  //计划开工日期
        "fplanfinishdate": "%s", //计划完工日期
        "fitemid": "%s->", //物料编码 *
        "fworkshop": "%s->", //生产车间编号
        "fauxqty": %d,  //计划生产数量
        "fauxinhighlimitqty": %d, //完工入库上限
        "fauxinlowlimitqty": %d, //完工入库下限
        "finhighlimit": 0, //完工入库超收比例
        "finlowlimit": 0 //完工入库欠收比例
    }
`
 
type CSTNsqQuery struct {
    FBillNo     string  `json:"FBillNo"`     // 订单编号
    FNumber     string  `json:"FNumber"`     // 物料代码
    FSource     string  `json:"FSource"`     // 生产车间代码
    FStartDate  string  `json:"FStartDate"`  // 开工日期
    FFinishDate string  `json:"FFinishDate"` // 完工日期
    UseAmount   float64 `json:"UseAmount"`   // 使用数量
}
 
type CSTNsqReply struct {
    FBillNo string `json:"FBillNo"` // 订单编号
    FNumber string `json:"FNumber"` // 物料代码
    ICMONo  string `json:"ICMONo"`  // 金蝶系统的生产任务单编号
    Code    int    `json:"code"`    // CST接口返回的code, 成功200
    Message string `json:"message"` // 失败的错误信息
}
 
type CSTServiceResponse struct {
    ErrCode int    `json:"errcode"`
    ErrMsg  string `json:"errmsg"`
    Data    struct {
        FBillNo      string `json:"fbillno"`
        FBillId      string `json:"fbillid"`
        FTranType    string `json:"ftrantype"`
        FClassTypeId int    `json:"fclasstypeid"`
    } `json:"data"`
}
 
func CSTQueryHandle(msg []byte) error {
    var query []CSTNsqQuery
    var reply []CSTNsqReply
 
    if err := json.Unmarshal(msg, &query); err != nil {
        logger.Warn("解析请求失败, %s", err.Error())
        return err
    }
    logger.Debug("接收到创建生产任务单请求, 共%d条订单", len(query))
 
    for _, q := range query {
        ret := Commit2CSTService(q)
        reply = append(reply, ret)
    }
 
    replyData, _ := json.Marshal(reply)
    ok := nsqclient.Produce(config.Options.CSTReplyTopic, replyData)
    logger.Warn("应答查询请求结果:%t, key:%s", ok, replyData)
 
    return nil
}
 
func Commit2CSTService(order CSTNsqQuery) (result CSTNsqReply) {
    result.Code = -1
    result.FBillNo = order.FBillNo
    result.FNumber = order.FNumber
 
    if result.FBillNo == "" || result.FNumber == "" {
        result.Message = "订单编号或物料编号不能为空"
        return
    }
 
    today := time.Now().Format("2006-01-02")
    joHead := fmt.Sprintf(JoHeadTemplate,
        today,                // 日期
        today,                // 制单日期
        order.FStartDate,     // 开工日期
        order.FFinishDate,    // 完工日期
        order.FStartDate,     // 计划开工日期
        order.FFinishDate,    // 计划完工日期
        order.FNumber,        // 物料编码
        order.FSource,        // 生产车间编码
        int(order.UseAmount), // 生产数量
        int(order.UseAmount), // 完工入库上限
        int(order.UseAmount), // 完工入库下限
    )
    //fmt.Println(joHead)
    params := map[string]string{
        "action":  "生产任务单.新增",
        "fuserid": "16394",
        "jo_head": joHead,
        "ja_body": "[{}]",
    }
 
    request, err := newMultipartRequest(config.Options.CSTWebApi, params)
    if err != nil {
        result.Message = err.Error()
        return
    }
 
    client := &http.Client{}
    resp, err := client.Do(request)
    if err != nil {
        result.Message = err.Error()
        return
    }
 
    defer resp.Body.Close()
 
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        result.Message = err.Error()
        return
    }
 
    var rspMsg CSTServiceResponse
    err = json.Unmarshal(body, &rspMsg)
    if err != nil {
        result.Message = err.Error()
        return
    }
 
    if rspMsg.ErrCode == 0 {
        result.Code = 200
        result.ICMONo = rspMsg.Data.FBillNo
    } else {
        result.Code = rspMsg.ErrCode
        result.Message = rspMsg.ErrMsg
    }
 
    return
}
 
func newMultipartRequest(url string, params map[string]string) (*http.Request, error) {
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
 
    // 设置Boundary, 接口验证了六个-
    if err := writer.SetBoundary("------basicHttpClient" + strconv.Itoa(int(time.Now().Unix()))); err != nil {
        fmt.Println(err.Error())
    }
 
    for key, val := range params {
        _ = writer.WriteField(key, val)
    }
 
    writer.Close()
 
    req, err := http.NewRequest("POST", url, body)
    if err != nil {
        return nil, err
    }
 
    req.Header.Set("Content-Type", writer.FormDataContentType())
    req.Header.Set("User-Agent", "basicHttpClient/0.0.1")
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("Accept", "*/*")
 
    return req, err
}