SJA APS后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

831 lines
34 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package calloff
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "fmt"
  6. "github.com/go-xorm/xorm"
  7. "io"
  8. "io/ioutil"
  9. "leit.com/leit_seat_aps/common"
  10. "leit.com/leit_seat_aps/db"
  11. "leit.com/leit_seat_aps/etcd"
  12. "leit.com/leit_seat_aps/glog"
  13. "leit.com/leit_seat_aps/service"
  14. "os"
  15. "regexp"
  16. "strconv"
  17. "strings"
  18. "time"
  19. )
  20. // Calloff文件解析和保存
  21. func ParseCalloffNew() {
  22. for {
  23. var (
  24. err error
  25. projtab db.Me_project
  26. projtablst []db.Me_project
  27. cfland CalloffLandData
  28. cfProj service.CalloffProject
  29. rd []os.FileInfo
  30. fi os.FileInfo
  31. edi_file string
  32. mail db.Sendmailtab
  33. matched bool
  34. )
  35. projtab = db.Me_project{}
  36. if projtablst, err = projtab.GetAllActive(); err != nil {
  37. glog.InfoExtln("Calloff解析", "Failed to get project list!")
  38. return
  39. }
  40. for i, _ := range projtablst {
  41. cfProj = service.CalloffProject{}
  42. cfProj.Projecttab = projtablst[i]
  43. cfProj.Projectid = projtablst[i].Projectid
  44. fmt.Println("Ready to load data for project:", projtablst[i].Projectid)
  45. // 读取文件夹内的文件并解析
  46. if rd, err = ioutil.ReadDir(cfProj.Projecttab.Calloff_folder + "/inbox"); err != nil {
  47. return
  48. }
  49. rds := common.SortByTime(rd)
  50. for _, fi = range rds {
  51. if fi.IsDir() {
  52. continue
  53. }
  54. edi_file = cfProj.Projecttab.Calloff_folder + "/inbox" + "/" + fi.Name()
  55. // 判断文件的合规性
  56. if matched, err = regexp.MatchString(cfProj.Projecttab.Calloff_filename_regexp, fi.Name()); err != nil {
  57. glog.InfoExtln("Calloff解析", "Failed to match EDI file name: due to: ", fi.Name(), err)
  58. os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name())
  59. continue
  60. }
  61. if !matched {
  62. glog.InfoExtln("Calloff解析", "The specified EDI file: doesn't match the required name specification!", fi.Name())
  63. os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name())
  64. continue
  65. }
  66. // 解析CALLOFF文件到字典
  67. fmt.Println("Ready to read tod data......")
  68. cfland = CalloffLandData{}
  69. cfland.Projnr = projtablst[i].Projectid
  70. cfland.Edifile = edi_file
  71. if err = cfland.ReadCalloffData(edi_file); err != nil {
  72. glog.InfoExtln("Calloff解析", "Failed to parse Calloff file due to: ", err)
  73. os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name())
  74. return
  75. }
  76. // 保存CALLOFF字典到临时缓存表
  77. if err = cfland.SaveCalloffData(); err != nil {
  78. glog.InfoExtln("Calloff解析", "Failed to save Calloff parse result due to: ", err)
  79. //发邮件
  80. host := projtablst[i].Emailserver_host + ":" + common.ValueToString(projtablst[i].Emailserver_port, "")
  81. body := "项目号: " + projtablst[i].Projectid + "\r\nEdifile :" + fi.Name() + "\r\nErrorinfo :" + err.Error()
  82. mail.Status = "waiting"
  83. mail.Body = body
  84. mail.Subject = "calloff解析错误"
  85. mail.Name = projtablst[i].From_email
  86. mail.Tomail = projtablst[i].Calloff_error_to_recievers
  87. mail.Host = host
  88. mail.Password = projtablst[i].From_pwd
  89. mail.Username = projtablst[i].From_email
  90. err = mail.Add()
  91. os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name())
  92. continue
  93. }
  94. // 将文件移到outbox
  95. os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/outbox"+"/"+fi.Name())
  96. }
  97. }
  98. time.Sleep(10 * time.Second)
  99. }
  100. }
  101. // 读取Calloff信息并生成发运包装
  102. func ParseCalloffOrder() {
  103. for {
  104. var (
  105. err error
  106. i, j, k, prevCS, m, n int
  107. projtab db.Me_project
  108. projtablst []db.Me_project
  109. cfProj service.CalloffProject
  110. cflandtab db.Pln_calloffdata_landing
  111. cflandtablst []db.Pln_calloffdata_landing
  112. cflandtablst2 []db.Pln_calloffdata_landing
  113. cftab db.Pln_calloffdata_landing
  114. cftablst []db.Pln_calloffdata_landing
  115. edictrltab db.Edi_control
  116. bl_co service.BL_CustOrder
  117. bl_prevco service.BL_CustOrder
  118. wotab db.Pln_workorder
  119. exist, ok, audit, relstat, stop bool
  120. prevOemord string
  121. sgdict map[string]string
  122. bl_pakordlst []service.BL_PackOrder
  123. bl_pakord service.BL_PackOrder
  124. cferror db.Pln_calloff_errorlst
  125. errorlst []db.Pln_calloff_errorlst
  126. mail db.Sendmailtab
  127. session *xorm.Session
  128. )
  129. projtab = db.Me_project{}
  130. if projtablst, err = projtab.GetAllActive(); err != nil {
  131. glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to get project list!")
  132. return
  133. }
  134. for i, _ = range projtablst {
  135. cfProj = service.CalloffProject{}
  136. cfProj.Projecttab = projtablst[i]
  137. cfProj.Projectid = projtablst[i].Projectid
  138. glog.InfoExtln("CALLOFF-Debug", "----------------循环读取Calloff项目", projtablst[i].Projectid, "----------------")
  139. // 判断calloff是否已暂停
  140. edictrltab = db.Edi_control{Projectid: projtablst[i].Projectid, Ediid: "CALLOFF"}
  141. if edictrltab, err = edictrltab.SelectOne(); edictrltab.Enabled <= 0 {
  142. continue
  143. }
  144. // 加载项目主数据
  145. fmt.Println("Ready to load data for project:", projtablst[i].Projectid)
  146. if err = cfProj.LoadMasterData(); err != nil {
  147. glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to load project master data due to: !", err)
  148. return
  149. }
  150. // 循环读取未处理的Calloff消息,按零件族和CheckSequence排序
  151. cflandtab = db.Pln_calloffdata_landing{Projnr: cfProj.Projectid}
  152. if cflandtablst, err = cflandtab.GetUnparsedLandingData(); err != nil {
  153. glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to get unparsed calloff landding data due to:", err)
  154. return
  155. }
  156. // 遍历未处理的Calloff消息
  157. for j = 0; j < len(cflandtablst); j++ {
  158. // 判断calloff是否已暂停
  159. edictrltab = db.Edi_control{Projectid: projtablst[i].Projectid, Ediid: "CALLOFF"}
  160. if edictrltab, err = edictrltab.SelectOne(); edictrltab.Enabled <= 0 {
  161. break
  162. }
  163. errorlst = []db.Pln_calloff_errorlst{}
  164. glog.InfoExtln("CALLOFF-Debug", j, "-- calloff 解析请求", cflandtablst[j])
  165. // 读取项目各零件族解析的最大CheckSequence号
  166. if err = cfProj.LoadPartFamilyMaxParsedCheckSequence(); err != nil {
  167. glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to load project parsed max check sequence data for each partfamily due to: ", err)
  168. return
  169. }
  170. // 验证Calloff有效性
  171. // 1. 基于零件族判断CheckSequence是否连续
  172. if projtablst[i].Calloff_verify_checksequence > 0 {
  173. if prevCS, ok = cfProj.Pfcsdict[cflandtablst[j].Partfamilyid]; !ok {
  174. glog.InfoExtln("读取Calloff信息并生成发运包装", "CheckSequence不连续:", prevCS, "==>", cflandtablst[j].Checksequence)
  175. return
  176. }
  177. // 检查checksequence是否连续,如果不连续查询两者之间是否有报错的解析记录,如果没有报错,如果有继续不处理
  178. if prevCS > 0 && prevCS+1 != cflandtablst[j].Checksequence {
  179. if exist, err = cflandtablst[j].AnyErrorRecordBetweenCheckSequence(cfProj.Projectid, cflandtablst[j].Partfamilyid, prevCS, cflandtablst[j].Checksequence); err != nil {
  180. glog.InfoExtln("读取Calloff信息并生成发运包装", "查询零件族:", cflandtablst[j].Partfamilyid, "checksequence区间失败:", prevCS, cflandtablst[j].Checksequence)
  181. return
  182. }
  183. if exist {
  184. continue
  185. } else {
  186. cferror = db.Pln_calloff_errorlst{}
  187. cferror.Finr = db.G_FINR
  188. cferror.Calloffnr = cflandtablst[j].Calloffnr
  189. cferror.Errortype = common.CALLOFF_CHECK_SEQUENCE
  190. cferror.Consumeplant = cflandtablst[j].Consumeplant
  191. cferror.Partfamilyid = cflandtablst[j].Partfamilyid
  192. cferror.Oemordernr = cflandtablst[j].Oemordernr
  193. cferror.Errorstatus = "O"
  194. cferror.Errorinfo = "CheckSequence不连续:" + common.ValueToString(prevCS, "") + ";" + common.ValueToString(cflandtablst[j].Checksequence, "")
  195. cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  196. cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  197. errorlst = append(errorlst, cferror)
  198. // CheckSequence 不连续,报错
  199. fmt.Println("CheckSequence不连续:", prevCS, "==>", cflandtablst[j].Checksequence)
  200. }
  201. }
  202. }
  203. // 2. 判断客户订单是否存在
  204. /* 获取锁 */
  205. LOOP:
  206. err = etcd.G_jobLock.TryLock("lock")
  207. if err != nil {
  208. fmt.Println("calloff groutine lock fail!")
  209. time.Sleep(5 * time.Millisecond)
  210. goto LOOP
  211. }
  212. fmt.Println("calloff groutine lock success!")
  213. bl_co = service.BL_CustOrder{Projnr: cflandtablst[j].Projnr, Oemordernr: cflandtablst[j].Oemordernr, Partfamilyid: cflandtablst[j].Partfamilyid}
  214. if exist, err = bl_co.GetCalloffOemorder(); err != nil {
  215. glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to get custorder for oemorder due to: ", cflandtablst[j].Oemordernr, err)
  216. etcd.G_jobLock.UnLock()
  217. return
  218. }
  219. if !exist {
  220. cferror = db.Pln_calloff_errorlst{}
  221. cferror.Finr = db.G_FINR
  222. cferror.Calloffnr = cflandtablst[j].Calloffnr
  223. cferror.Errortype = common.CALLOFF_ORDER_NOTEXIST
  224. cferror.Consumeplant = cflandtablst[j].Consumeplant
  225. cferror.Partfamilyid = cflandtablst[j].Partfamilyid
  226. cferror.Oemordernr = cflandtablst[j].Oemordernr
  227. cferror.Errorstatus = "O"
  228. cferror.Errorinfo = "Calloff的客户订单不存在:Partfamilyid:" + cflandtablst[j].Partfamilyid + ";Oemordernr:" + cflandtablst[j].Oemordernr
  229. cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  230. cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  231. errorlst = append(errorlst, cferror)
  232. glog.InfoExtln("读取Calloff信息并生成发运包装", "Calloff的客户订单不存在 :", cflandtablst[j].Oemordernr, cflandtablst[j].Partfamilyid)
  233. }
  234. glog.InfoExtln("CALLOFF-Debug", "获取客户订单:", bl_co.Custordertab.Custordernr, "生产工单数:", len(bl_co.Custordertab.Wotablst))
  235. // 如果没有生产工单,则不再处理
  236. if len(bl_co.Custordertab.Wotablst) <= 0 {
  237. fmt.Println("获取客户订单:", bl_co.Custordertab.Custordernr, "生产工单数:", len(bl_co.Custordertab.Wotablst))
  238. etcd.G_jobLock.UnLock()
  239. continue
  240. }
  241. prevCS, _ = cfProj.Pfcsdict[cflandtablst[j].Partfamilyid]
  242. prevOemord = ""
  243. if prevCS > 0 {
  244. cflandtab = db.Pln_calloffdata_landing{Projnr: cfProj.Projectid, Checksequence: prevCS, Partfamilyid: cflandtablst[j].Partfamilyid}
  245. if cflandtablst2, err = cflandtab.GetByProjectCheckSequencePartfamily(); len(cflandtablst2) > 0 {
  246. prevOemord = cflandtablst2[0].Oemordernr
  247. // 获取前序客户订单对应的calloff记录
  248. cftab = db.Pln_calloffdata_landing{Projnr: cfProj.Projectid, Oemordernr: prevOemord}
  249. // 获取前序calloff的所有记录
  250. if cftablst, err = cftab.GetByProjectOemorder(); err != nil {
  251. glog.InfoExtln("读取Calloff信息并生成发运包装", "查询项目客户订单的calloff记录失败:", cftab.Projnr, cftab.Oemordernr, err)
  252. etcd.G_jobLock.UnLock()
  253. return
  254. }
  255. // 获取前序客户订单
  256. bl_prevco = service.BL_CustOrder{Projnr: cfProj.Projectid, Oemordernr: cflandtablst2[0].Oemordernr, Partfamilyid: cflandtablst2[0].Partfamilyid}
  257. if exist, err = bl_prevco.GetCalloffOemorder(); err != nil {
  258. glog.InfoExtln("读取Calloff信息并生成发运包装", "获取前序客户订单失败:", cflandtablst2[0].Oemordernr, err)
  259. etcd.G_jobLock.UnLock()
  260. return
  261. }
  262. // 校验客户订单的零件族是否齐全
  263. sgdict = make(map[string]string)
  264. if sgdict, err = bl_prevco.GetOemorderModelSpecPfdict(); err != nil {
  265. glog.InfoExtln("读取Calloff信息并生成发运包装", "查询项目客户订单的车型规格字典记录失败:", bl_co.Custordertab.Projnr, bl_co.Custordertab.Custordernr, err)
  266. etcd.G_jobLock.UnLock()
  267. return
  268. }
  269. if len(sgdict) != len(cftablst) {
  270. // 整车副缺零件族
  271. glog.InfoExtln("CALLOFF-Debug", "整车副缺零件族len(cftablst):", len(cftablst), "整车副缺零件族len(sgdict):", len(sgdict))
  272. etcd.G_jobLock.UnLock()
  273. continue
  274. }
  275. // 校验是否解析有错误
  276. if len(cftablst) > 0 {
  277. // 校验前车付的calloff是否有错
  278. stop = false
  279. for k = 0; k < len(cftablst); k++ {
  280. //fmt.Println(k,"-->",cftablst[k])
  281. if cftablst[k].Parsed == 0 || cftablst[k].Handlestatus != common.CO_PARSE_STATUS_OK {
  282. stop = true
  283. break
  284. }
  285. }
  286. if stop {
  287. fmt.Println("前序未完成处理,跳过!")
  288. etcd.G_jobLock.UnLock()
  289. continue
  290. }
  291. }
  292. }
  293. }
  294. // 3. 判断客户订单状态是否满足
  295. if projtablst[i].Calloff_verify_orderstatus > 0 && bl_co.Custordertab.Status < common.CO_STATUS_PLANNED {
  296. cferror = db.Pln_calloff_errorlst{}
  297. cferror.Finr = db.G_FINR
  298. cferror.Calloffnr = cflandtablst[j].Calloffnr
  299. cferror.Errortype = common.CALLOFF_ORDER_NOTSTATUS
  300. cferror.Consumeplant = cflandtablst[j].Consumeplant
  301. cferror.Partfamilyid = cflandtablst[j].Partfamilyid
  302. cferror.Oemordernr = cflandtablst[j].Oemordernr
  303. cferror.Errorstatus = "O"
  304. cferror.Errorinfo = "calloff的客户订单状态不满足:Partfamilyid:" + cflandtablst[j].Partfamilyid + ";Oemordernr:" + cflandtablst[j].Oemordernr
  305. cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  306. cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  307. errorlst = append(errorlst, cferror)
  308. }
  309. // 4. 判断客户订单规格是否已审核
  310. if projtablst[i].Calloff_verify_orderspec > 0 {
  311. if audit, err = bl_co.IsCarmodelSpecAudited(); err != nil {
  312. glog.InfoExtln("读取Calloff信息并生成发运包装", "获取客户订单规格失败 :", bl_co.Custordernr)
  313. etcd.G_jobLock.UnLock()
  314. return
  315. } else {
  316. if !audit {
  317. cferror = db.Pln_calloff_errorlst{}
  318. cferror.Finr = db.G_FINR
  319. cferror.Calloffnr = cflandtablst[j].Calloffnr
  320. cferror.Errortype = common.CALLOFF_ORDER_NOTSPEC
  321. cferror.Consumeplant = cflandtablst[j].Consumeplant
  322. cferror.Partfamilyid = cflandtablst[j].Partfamilyid
  323. cferror.Oemordernr = cflandtablst[j].Oemordernr
  324. cferror.Errorstatus = "O"
  325. cferror.Errorinfo = "calloff的客户订单的规格型号未审核:" + cflandtablst[j].Partfamilyid + ";Oemordernr:" + cflandtablst[j].Oemordernr
  326. cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  327. cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss")
  328. errorlst = append(errorlst, cferror)
  329. }
  330. }
  331. }
  332. // 如果有错,则停下不解析
  333. if len(errorlst) > 0 {
  334. session = db.G_DbEngine.NewSession()
  335. if err = session.Begin(); err != nil {
  336. session.Close()
  337. etcd.G_jobLock.UnLock()
  338. return
  339. }
  340. //保存错误
  341. if err = cferror.InsertList(session, errorlst); err != nil {
  342. glog.InfoExtln("读取Calloff信息并生成发运包装", "插入Calloff解析错误记录失败 :", err)
  343. session.Rollback()
  344. session.Close()
  345. etcd.G_jobLock.UnLock()
  346. return
  347. }
  348. //发邮件
  349. host := projtablst[i].Emailserver_host + ":" + common.ValueToString(projtablst[i].Emailserver_port, "")
  350. body := "项目号: " + projtablst[i].Projectid + "\r\nOemordernr 订单号: " + cferror.Oemordernr + "\r\nErrorinfo :" + cferror.Errorinfo
  351. mail.Status = "waiting"
  352. mail.Body = body
  353. mail.Subject = "calloff解析错误"
  354. mail.Name = projtablst[i].From_email
  355. mail.Tomail = projtablst[i].Calloff_error_to_recievers
  356. mail.Host = host
  357. mail.Password = projtablst[i].From_pwd
  358. mail.Username = projtablst[i].From_email
  359. err = mail.Add()
  360. if err != nil {
  361. glog.InfoExtln("发送邮件", "err is :", err)
  362. }
  363. cflandtablst[j].Parsed = common.EDI_PARSE_YES
  364. cflandtablst[j].Handlestatus = common.CO_PARSE_STATUS_ERROR
  365. cflandtablst[j].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
  366. if err = cflandtablst[j].UpdateFields(session, "parsed,handlestatus,lastmodif"); err != nil {
  367. glog.InfoExtln("读取Calloff信息并生成发运包装", "更新Calloff解析记录失败 :", err)
  368. session.Rollback()
  369. session.Close()
  370. etcd.G_jobLock.UnLock()
  371. return
  372. }
  373. session.Commit()
  374. session.Close()
  375. etcd.G_jobLock.UnLock()
  376. continue
  377. }
  378. // Hardcode: 对于G38项目的PF2的CALLOFF需要等同一客户订单的PF1的CALL进来后才解析
  379. if cflandtablst[j].Projnr == "G38" && cflandtablst[j].Partfamilyid == "SITKD2" {
  380. // 获取同项目OEMORDER的Calloff判断解析状态
  381. if exist, err = cflandtab.ExistUnParsedCfByProjectOemorderPf(cfProj.Projectid, cflandtablst[j].Oemordernr, "SITKD1"); err != nil {
  382. glog.InfoExtln("读取Calloff信息并生成发运包装", "获取项目客户订单零件族的calloff记录失败 :", cfProj.Projectid, cflandtablst[j].Oemordernr, cflandtablst[j].Partfamilyid, err)
  383. etcd.G_jobLock.UnLock()
  384. return
  385. }
  386. if exist {
  387. glog.InfoExtln("读取Calloff信息并生成发运包装", "408行 exist is false :", err)
  388. etcd.G_jobLock.UnLock()
  389. continue
  390. }
  391. }
  392. session = db.G_DbEngine.NewSession()
  393. if err = session.Begin(); err != nil {
  394. session.Close()
  395. etcd.G_jobLock.UnLock()
  396. return
  397. }
  398. // 遍历客户订单的生产订单列表,将生产订单加入包装
  399. for k = 0; k < len(bl_co.Custordertab.Wotablst); k++ {
  400. glog.InfoExtln("CALLOFF-Debug", "遍历客户订单的生产订单", k, "--", bl_co.Custordertab.Wotablst[k])
  401. wotab = bl_co.Custordertab.Wotablst[k]
  402. if wotab.Shippable == 0 || wotab.Packstatus == common.WO_STATUS_PACKED {
  403. continue
  404. }
  405. glog.InfoExtln("CALLOFF-Debug", "需要包装的工单:", wotab.Workordernr, "供应组:", wotab.Supplygroupid, "OEMSEQ:", wotab.Oemseq, "CheckSeq:", cflandtablst[j].Checksequence)
  406. // 初始化
  407. bl_pakord = service.BL_PackOrder{}
  408. // 基于checksequence和工单的供应组ID查找包装单
  409. if exist, bl_pakord, err = cfProj.GetPackOrderByCheckSequenceSupplyGroup(session, cflandtablst[j].Checksequence, wotab.Supplygroupid); err != nil {
  410. glog.InfoExtln("读取Calloff信息并生成发运包装", "无法获取checksequence的包装订单,原因是:", cflandtablst[j].Checksequence, err)
  411. session.Rollback()
  412. session.Close()
  413. etcd.G_jobLock.UnLock()
  414. return
  415. }
  416. // 基于OEMSEQ和工单的供应组ID查找包装单
  417. if !exist {
  418. glog.InfoExtln("CALLOFF-Debug", "基于checkseq:", cflandtablst[j].Checksequence, "工单供应组:", wotab.Supplygroupid, "未找到开口包装!")
  419. if exist, bl_pakord, err = cfProj.GetPackOrderByOemseqSupplyGroup(session, wotab); err != nil {
  420. glog.InfoExtln("读取Calloff信息并生成发运包装", "无法获取OEMSEQ的包装订单,原因是:", wotab.Oemseq, err)
  421. session.Rollback()
  422. session.Close()
  423. etcd.G_jobLock.UnLock()
  424. return
  425. }
  426. } else {
  427. glog.InfoExtln("CALLOFF-Debug", "基于checkseq:", cflandtablst[j].Checksequence, "工单供应组:", wotab.Supplygroupid, "找到适配包装!")
  428. glog.InfoExtln("CALLOFF-Debug", "适配包装:", bl_pakord.Pkotab)
  429. }
  430. // 不存在则新建包装单
  431. if !exist {
  432. glog.InfoExtln("CALLOFF-Debug", "基于OEMSEQ", wotab.Oemseq, "工单供应组:", wotab.Supplygroupid, "未找到开口包装!")
  433. if bl_pakordlst, err = cfProj.CreatePackOrderByCheckSeqWO(session, cflandtablst[j], wotab); err != nil {
  434. glog.InfoExtln("读取Calloff信息并生成发运包装", "创建开口包装单失败,原因是:", err)
  435. session.Rollback()
  436. session.Close()
  437. etcd.G_jobLock.UnLock()
  438. return
  439. }
  440. // 获取当前checksequence的包装单
  441. ok = false
  442. glog.InfoExtln("CALLOFF-Debug", "新建开口包装成功,数量:", len(bl_pakordlst))
  443. for m = 0; m < len(bl_pakordlst); m++ {
  444. glog.InfoExtln("CALLOFF-Debug", m, "----遍历开口包装适配:", bl_pakordlst[m].PackorderId)
  445. for n = 0; n < len(bl_pakordlst[m].Pkotab.Itemlst); n++ {
  446. glog.InfoExtln("CALLOFF-Debug", n, " ----匹配包装项:", bl_pakordlst[m].Pkotab.Itemlst[n])
  447. if bl_pakordlst[m].Pkotab.Itemlst[n].Seq == cflandtablst[j].Checksequence && bl_pakordlst[m].Pkotab.Itemlst[n].Supplygroupid == wotab.Supplygroupid {
  448. ok = true
  449. bl_pakord = bl_pakordlst[m]
  450. break
  451. }
  452. }
  453. if ok {
  454. break
  455. }
  456. }
  457. if !ok {
  458. glog.InfoExtln("CALLOFF-Debug", "生产工单", wotab.Workordernr, "匹配包装失败!!!")
  459. glog.InfoExtln("读取Calloff信息并生成发运包装", "无法为当前工单找到包装单!", wotab.Workordernr)
  460. continue
  461. }
  462. } else {
  463. glog.InfoExtln("CALLOFF-Debug", "基于OEMSEQ:", wotab.Oemseq, "工单供应组:", wotab.Supplygroupid, "找到适配包装!")
  464. glog.InfoExtln("CALLOFF-Debug", "适配包装:", bl_pakord.Pkotab)
  465. }
  466. // 将工单加入到当前包装单
  467. glog.InfoExtln("CALLOFF-Debug", "尝试将工单:", wotab.Workordernr, "添加到包装单:", bl_pakord.PackorderId)
  468. if ok, err = cfProj.AddWOToPackOrder(wotab, cflandtablst[j].Checksequence, &bl_pakord, session); err != nil {
  469. glog.InfoExtln("读取Calloff信息并生成发运包装", "添加工单到包装单出错,原因是:", wotab.Workordernr, bl_pakord.PackorderId, err)
  470. session.Rollback()
  471. session.Close()
  472. etcd.G_jobLock.UnLock()
  473. return
  474. }
  475. if ok {
  476. fmt.Println("成功添加工单", wotab.Workordernr, "到包装单", bl_pakord.PackorderId)
  477. glog.InfoExtln("CALLOFF-Debug", "成功添加工单", wotab.Workordernr, "到包装单", bl_pakord.PackorderId)
  478. // 关闭当前包装
  479. if relstat, err = cfProj.ReleasePackOrder(session, bl_pakord); err != nil {
  480. glog.InfoExtln("读取Calloff信息并生成发运包装", "下达包装单出错!", bl_pakord.PackorderId, err)
  481. session.Rollback()
  482. session.Close()
  483. etcd.G_jobLock.UnLock()
  484. return
  485. }
  486. if relstat {
  487. glog.InfoExtln("CALLOFF-Debug", "成功下达包装单!", bl_pakord.PackorderId)
  488. glog.InfoExtln("读取Calloff信息并生成发运包装", "成功下达包装单!", bl_pakord.PackorderId)
  489. }
  490. } else {
  491. glog.InfoExtln("CALLOFF-Debug", "无法添加工单", wotab.Workordernr, "到包装单", bl_pakord.PackorderId)
  492. }
  493. }
  494. // 更新客户订单Call off相关信息
  495. bl_co.Custordertab.Calloffnr = cflandtablst[j].Calloffnr
  496. bl_co.Custordertab.Calloffswet = cflandtablst[j].Swet
  497. bl_co.Custordertab.Checksequence = cflandtablst[j].Checksequence
  498. bl_co.Custordertab.Consumecompany = cflandtablst[j].Consumecompany
  499. bl_co.Custordertab.Consumeplant = cflandtablst[j].Consumeplant
  500. bl_co.Custordertab.Consigneecompany = cflandtablst[j].Consigneecompany
  501. bl_co.Custordertab.Consigneeplant = cflandtablst[j].Consigneeplant
  502. bl_co.Custordertab.Vehicleidset = cflandtablst[j].Vehicleidset
  503. bl_co.Custordertab.Vehicleid = cflandtablst[j].Vehicleid
  504. bl_co.Custordertab.Unloadingplace = cflandtablst[j].Unloadingplace
  505. bl_co.Custordertab.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
  506. if err = bl_co.Custordertab.UpdateFields(session, "calloffnr, calloffswet, checksequence, consumecompany, consumeplant, consigneecompany, consigneeplant, vehicleidset, vehicleid, unloadingplace, lastmodif"); err != nil {
  507. glog.InfoExtln("读取Calloff更新客户订单数据", "Rollback", err)
  508. session.Rollback()
  509. session.Close()
  510. etcd.G_jobLock.UnLock()
  511. return
  512. }
  513. // calloff 客户订单成功,将landdata置位
  514. cflandtablst[j].Handlestatus = common.CO_PARSE_STATUS_OK
  515. cflandtablst[j].Parsed = common.EDI_PARSE_YES
  516. cflandtablst[j].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
  517. if err = cflandtablst[j].UpdateFields(session, "parsed,handlestatus, lastmodif"); err != nil {
  518. glog.InfoExtln("读取Calloff信息并生成发运包装", "Rollback", err)
  519. session.Rollback()
  520. session.Close()
  521. etcd.G_jobLock.UnLock()
  522. return
  523. }
  524. session.Commit()
  525. session.Close()
  526. etcd.G_jobLock.UnLock()
  527. time.Sleep(10 * time.Millisecond)
  528. }
  529. }
  530. time.Sleep(1 * time.Second)
  531. }
  532. }
  533. // 将26下达的包装单加载到发运车中,系统根据实际加载情况
  534. func GenerateDeliveryCar() {
  535. for {
  536. var (
  537. err error
  538. i, j, idx int
  539. projtab db.Me_project
  540. projtablst []db.Me_project
  541. pkotab db.Jit_packorder
  542. pkotablst []db.Jit_packorder
  543. cfProj service.CalloffProject
  544. bl_sco service.BL_ShipcarOrder
  545. bl_scolst []service.BL_ShipcarOrder
  546. fillable, canfix, canrelease bool
  547. shiptplid string
  548. session *xorm.Session
  549. )
  550. projtab = db.Me_project{}
  551. if projtablst, err = projtab.GetAllActive(); err != nil {
  552. glog.InfoExtln("Calloff包装单", "Failed to get project list!")
  553. return
  554. }
  555. for i, _ = range projtablst {
  556. cfProj = service.CalloffProject{}
  557. cfProj.Projecttab = projtablst[i]
  558. cfProj.Projectid = projtablst[i].Projectid
  559. fmt.Println("Ready to load data for project:", projtablst[i].Projectid)
  560. // 读取项目的包装类型主数据
  561. if err = cfProj.LoadPackageType(); err != nil {
  562. glog.InfoExtln("Calloff包装单", "Failed to load project package type data due to: ", err)
  563. return
  564. }
  565. // 读取项目的发运车模板主数据
  566. if err = cfProj.LoadShipCarTemplate(); err != nil {
  567. glog.InfoExtln("Calloff包装单", "Failed to load project ship car data due to: ", err)
  568. return
  569. }
  570. // 循环读取状态>=26已下达且未装车的包装单
  571. pkotab = db.Jit_packorder{}
  572. if pkotablst, err = pkotab.GetUnloadedPackOrders(cfProj.Projectid); err != nil {
  573. glog.InfoExtln("Calloff包装单", "Failed to load project unloaded pack orders due to: ", err)
  574. return
  575. }
  576. // 遍历包装单
  577. for j = 0; j < len(pkotablst); j++ {
  578. // 判断状态
  579. if pkotablst[j].Status < common.PKO_STATUS_PLANNED || pkotablst[j].Loadstatus == common.PKO_STATUS_LOADED {
  580. continue
  581. }
  582. // 获取开口发运车订单并添加到发运车中
  583. if bl_scolst, err = cfProj.GetOpenShipCarOrder(); err != nil {
  584. glog.InfoExtln("Calloff包装单", "Failed to get open car orders due to: ", err)
  585. return
  586. }
  587. session = db.G_DbEngine.NewSession()
  588. defer session.Close()
  589. if err = session.Begin(); err != nil {
  590. return
  591. }
  592. // 匹配所有可用模板计算各包装项最大装载量并与已填充量比较,确认是否可以继续填充 => 有可用发运车
  593. if len(bl_scolst) > 0 {
  594. fillable, idx = cfProj.CheckOpenCarOrdersForPackOrder(bl_scolst, pkotablst[j])
  595. }
  596. bl_sco = service.BL_ShipcarOrder{}
  597. if len(bl_scolst) > 0 && fillable {
  598. bl_sco.Shiporderid = bl_scolst[idx].Shiporderid
  599. if err = bl_sco.AddPackOrder(session, pkotablst[j]); err != nil {
  600. glog.InfoExtln("Calloff包装单", "Failed to add packorder :, into shipcar order :, due to: ",
  601. pkotablst[j].Packorderid, bl_sco.Shiporderid, err)
  602. session.Rollback()
  603. return
  604. }
  605. } else {
  606. // 如果没有开口发运车,则创建发运车并添加
  607. if bl_sco, err = cfProj.CreateShipCarOrder(session); err != nil {
  608. glog.InfoExtln("Calloff包装单", "Failed to create shipcar order due to: ", err)
  609. session.Rollback()
  610. return
  611. }
  612. if err = bl_sco.AddPackOrder(session, pkotablst[j]); err != nil {
  613. glog.InfoExtln("Calloff包装单", "Failed to add packorder : , into shipcar order :, due to: ",
  614. pkotablst[j].Packorderid, bl_sco.Shiporderid, err)
  615. session.Rollback()
  616. return
  617. }
  618. }
  619. // 获取发运车最新的数据
  620. if err = bl_sco.GetOrderDataBySession(session); err != nil {
  621. glog.InfoExtln("Calloff包装单", "Failed to get ship order data!", bl_sco.Shiporderid)
  622. session.Rollback()
  623. return
  624. }
  625. // 检查发运车是否可以指定模板,状态从10 -> 20
  626. if bl_sco.Spordtab.Status < common.SPO_STATUS_PLANNED {
  627. cfProj.InitShipOrderWorkoload(&bl_sco)
  628. cfProj.RecalShipItemWorkloadMaxQty(&bl_sco)
  629. if canfix, shiptplid, err = cfProj.IsShipcarOrderFixTemplate(&bl_sco); err != nil {
  630. glog.InfoExtln("Calloff包装单", "Failed to check shiporder fixable due to :", err)
  631. session.Rollback()
  632. return
  633. }
  634. if canfix {
  635. // 释放发运车并更新匹配的模板
  636. if err = cfProj.FixShipCarOrderTemplate(session, &bl_sco, shiptplid); err != nil {
  637. glog.InfoExtln("Calloff包装单", "Failed to release ship car order!")
  638. session.Rollback()
  639. return
  640. }
  641. }
  642. }
  643. // 检查发运车是否达到上限可关闭,状态从20 -> 26
  644. if canrelease, err = cfProj.IsShipcarOrderReleasable(&bl_sco); err != nil {
  645. glog.InfoExtln("Calloff包装单", "Failed to check shiporder releasable due to :", err)
  646. session.Rollback()
  647. return
  648. }
  649. if canrelease {
  650. // 释放发运车并更新匹配的模板
  651. if err = cfProj.ReleaseShipCarOrder(session, &bl_sco); err != nil {
  652. glog.InfoExtln("Calloff包装单", "Failed to release ship car order!")
  653. session.Rollback()
  654. return
  655. }
  656. }
  657. fmt.Println("---------------------生成xmL_msg1")
  658. //APS向WMS传递发运包装信息
  659. var o = PlnCalloffdataLandingXml{}
  660. o.Packorderid = pkotablst[j].Packorderid
  661. o.Packtemplateid = pkotablst[j].Packtemplateid
  662. o.Projnr = pkotablst[j].Projnr
  663. o.Status = strconv.Itoa(pkotablst[j].Status)
  664. o.Shortpack = strconv.Itoa(pkotablst[j].Shortpack)
  665. o.Orderinfo = pkotablst[j].Orderinfo
  666. o.Boxsn = pkotablst[j].Boxsn
  667. o.Packtypeid = pkotablst[j].Packtypeid
  668. o.Printerid = pkotablst[j].Printerid
  669. o.Templatefile = pkotablst[j].Templatefile
  670. o.Planqty = strconv.Itoa(pkotablst[j].Planqty)
  671. o.Actqty = strconv.Itoa(pkotablst[j].Actqty)
  672. for _, info := range pkotablst[j].Itemlst{
  673. o.Details = append(o.Details, Pln_calloffdata_landing_Xml{
  674. Packorderid :info.Packorderid,
  675. Pos :common.ValueToString(info.Pos,""),
  676. Poscode :info.Poscode,
  677. Oemseq : common.ValueToString(info.Oemseq, ""),
  678. Checkseq :common.ValueToString(info.Seq,""),
  679. Supplygroupid : info.Supplygroupid,
  680. Workordernr : info.Workordernr,
  681. Status : common.ValueToString(info.Status,""),
  682. Planqty :common.ValueToString(info.Planqty,""),
  683. Actqty :common.ValueToString(info.Actqty,""),
  684. })
  685. }
  686. jsonBytes, err := json.Marshal(o)
  687. if err != nil {
  688. fmt.Println(err)
  689. }
  690. bl_xmlmsg := service.BL_Xmlmsg{MsgType: common.MSG_TYPE_SHIP, Msg: string(jsonBytes)}
  691. fmt.Println("---------------------生成xmL_msg2")
  692. if err = bl_xmlmsg.Create(session); err != nil {
  693. fmt.Println(err)
  694. }
  695. err = session.Commit()
  696. if err != nil {
  697. fmt.Println(err)
  698. return
  699. }
  700. }
  701. }
  702. time.Sleep(10 * time.Second)
  703. }
  704. }
  705. func CallOffXmlTick(){
  706. timer := time.NewTicker(60 * time.Second)
  707. for {
  708. select {
  709. case <-timer.C:
  710. Xml_msg := db.Xml_msg{}
  711. if xmllst, err := Xml_msg.GetUnXmlMessages(); err != nil {
  712. glog.InfoExtln("Calloff包装单", "解析发运单消息失败: ", err)
  713. }else{
  714. for _, xmlInfo := range xmllst{
  715. var xmlStruct PlnCalloffdataLandingXml
  716. json.Unmarshal([]byte(xmlInfo.Msg), &xmlStruct)
  717. resXML, err := xml.MarshalIndent(xmlStruct, " ", " ")
  718. if err != nil {
  719. glog.InfoExtln("Calloff包装单", "Failed to create xml due to :",err)
  720. }
  721. timeS := time.Now().Format("20060102150405.999")
  722. fileName := strings.Trim(timeS,".")
  723. f, err := os.Create("./OutData/"+fileName +".xml")
  724. if err != nil {
  725. glog.InfoExtln("Calloff包装单", "Failed to create xml due to :",err)
  726. }
  727. io.WriteString(f, xml.Header)
  728. io.WriteString(f, string(resXML))
  729. Xml_msg.Msgid = xmlInfo.Msgid
  730. Xml_msg.Status = common.MSG_STATUS_FINISHED
  731. Xml_msg.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
  732. Xml_msg.Lastuser = "service"
  733. if err = Xml_msg.UpdateFieldsWithoutSession("status,lastmodif,lastuser"); err != nil {
  734. glog.InfoExtln("Calloff包装单", "Failed to create xml due to :",err)
  735. }
  736. }
  737. }
  738. }
  739. }
  740. }
  741. type PlnCalloffdataLandingXml struct {
  742. XMLName xml.Name `xml:"Content"`
  743. Packorderid string `xml:"packorderid,attr"`
  744. Packtemplateid string `xml:"packtemplateid,attr"`
  745. Projnr string `xml:"projnr,attr"`
  746. Status string `xml:"status,attr"`
  747. Shortpack string `xml:"shortpack,attr"`
  748. Orderinfo string `xml:"orderinfo,attr"`
  749. Boxsn string `xml:"boxsn,attr"`
  750. Packtypeid string `xml:"packtypeid,attr"`
  751. Printerid string `xml:"printerid,attr"`
  752. Templatefile string `xml:"templatefile,attr"`
  753. Planqty string `xml:"planqty,attr"`
  754. Actqty string `xml:"actqty,attr"`
  755. Details []Pln_calloffdata_landing_Xml `xml:"Details"`
  756. Description string `xml:",innerxml"`
  757. }
  758. type Pln_calloffdata_landing_Xml struct {
  759. XMLName xml.Name `xml:"Details"`
  760. Packorderid string `xml:"packorderid,attr"`
  761. Pos string `xml:"pos,attr"`
  762. Poscode string `xml:"poscode,attr"`
  763. Oemseq string `xml:"oemseq,attr"`
  764. Checkseq string `xml:"checkseq,attr"`
  765. Supplygroupid string `xml:"supplygroupid,attr"`
  766. Workordernr string `xml:"workordernr,attr"`
  767. Status string `xml:"status,attr"`
  768. Planqty string `xml:"planqty,attr"`
  769. Actqty string `xml:"actqty,attr"`
  770. }