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.

232 lines
7.5 KiB

3 years ago
  1. package seq
  2. import (
  3. "fmt"
  4. "github.com/go-xorm/xorm"
  5. "leit.com/leit_seat_aps/common"
  6. "leit.com/leit_seat_aps/db"
  7. "leit.com/leit_seat_aps/glog"
  8. "leit.com/leit_seat_aps/service"
  9. "strings"
  10. "time"
  11. )
  12. /**
  13. 基于已派工生产订单计算拣料单
  14. 基本逻辑
  15. 1. 加载产线对应的拣料单模板
  16. 2. 循环加载派工生产订单按产线和schedKey排序
  17. 3. 遍历生产订单零件列表
  18. 4. 遍历零件属性和生产订单对应产线的拣料单属性进行适配满足则将该零件和数量添加到该拣料单中
  19. 5. 拣料单满关闭拣料单并新建一个空拣料单
  20. **/
  21. // 拣料单服务
  22. // 功能描述:基于排序产线对应的已下达的生产订单,通过属性匹配自动创建拣料单,并填充待拣料项,直至到达需求上限
  23. // 拣料单创建初始状态 = 20 计划;填充完 = 26 下达;
  24. func RunPicker() (err error) {
  25. var (
  26. pkordsn string
  27. pe service.PickingEngine
  28. bl_wolist []service.BL_WorkOrder
  29. bl_wline service.BL_Workline
  30. i int
  31. //pln db.Pln_custorder
  32. )
  33. // 获取拣料单序列号
  34. if pkordsn, err = service.GetSysStringParameter(2, "*", "JIS_PICKORDER_SN"); err != nil {
  35. return
  36. }
  37. if strings.TrimSpace(pkordsn) == "" {
  38. pkordsn = "PICKORDER" // 默认流水ID
  39. }
  40. fmt.Println("JIS_PICKORDER_SN = ", pkordsn)
  41. // 初始化
  42. pe = service.PickingEngine{PickOrderSN: pkordsn}
  43. // 加载主数据
  44. fmt.Println("准备开始加载主数据......")
  45. if err = pe.LoadMasterData(); err != nil {
  46. return
  47. }
  48. fmt.Println("完成主数据加载!")
  49. glog.InfoExtln("PickingTmpDict","PickingTmpDict:",pe.PickingTmpDict)
  50. // 循环服务
  51. for {
  52. fmt.Println("循环服务开启......")
  53. //判断生成订单是否有未下达的,如果有的话,那么不往下进行
  54. //data, err := pln.SelectTenArr()
  55. //if err != nil || len(data) > 0 {
  56. // //有未下达的,则等待五秒
  57. // time.Sleep(5 * time.Second)
  58. // continue
  59. //}
  60. // 遍历产线
  61. for _, bl_wline = range pe.WorklineDict {
  62. fmt.Println(" 遍历产线:", bl_wline.WorklineId)
  63. // 从数据库中循环读取指定产线已派工下达未拣料的排序订单
  64. if bl_wolist, err = bl_wline.GetUnpickedWorkorderList(); err != nil {
  65. glog.InfoExtln("拣料单服务", "Failed to GetUnpickedWorkorderList:", err)
  66. continue
  67. }
  68. if len(bl_wolist) == 0{
  69. //判断生成订单的长度
  70. time.Sleep(5 * time.Second)
  71. continue
  72. }
  73. // 遍历产线上未拣料的生产订单并对它进行拣料
  74. for i = 0; i < len(bl_wolist); i++ {
  75. if err = PickLineWorkorder(&bl_wline, &bl_wolist[i], &pe); err != nil {
  76. glog.InfoExtln("拣料单服务", "Failed to PickLineWorkorder:", err)
  77. continue
  78. }
  79. }
  80. }
  81. time.Sleep(10 * time.Second)
  82. }
  83. }
  84. // 对产线上的派工订单进行拣料
  85. func PickLineWorkorder(bl_wline *service.BL_Workline, bl_wo *service.BL_WorkOrder, pe *service.PickingEngine) (err error) {
  86. var (
  87. session *xorm.Session
  88. bl_wopart service.BL_WorkOrder_Part
  89. bl_part service.BL_Part
  90. bl_pktmp service.BL_PickingTemplate
  91. bl_pko service.BL_PickingOrder
  92. bl_ordmsg service.BL_Ordmsg
  93. pktmpattrtab db.Pln_picktemplate_attrlst
  94. pktmpparttab db.Pln_picktemplate_itemlst
  95. i,attrcode int
  96. pickorderid, picktmpid, partid, wonr string
  97. ok, bflag, matched, exist, released bool
  98. pkodict map[string]service.BL_PickingTemplate
  99. )
  100. // 生产订单项目是否存在,如果不存在则不作处理
  101. if _, ok = pe.Projectdict[bl_wo.Workordertab.Projnr]; !ok {
  102. return
  103. }
  104. session = db.G_DbEngine.NewSession()
  105. defer session.Close()
  106. if err = session.Begin(); err != nil {
  107. return
  108. }
  109. // 遍历订单零件列表
  110. bflag = true
  111. pkodict = make(map[string]service.BL_PickingTemplate)
  112. for i = 0; i < len(bl_wo.Workordertab.Partlst); i++ {
  113. // 如果遍历零件不能存在则跳过
  114. if bl_part, ok = pe.Projectdict[bl_wo.Projnr].Partdict[bl_wo.Workordertab.Partlst[i].Partid]; !ok {
  115. continue
  116. }
  117. if bl_wopart, ok = bl_wo.Bl_wopartdict[bl_wo.Workordertab.Partlst[i].Partid]; !ok {
  118. continue
  119. }
  120. bl_wopart.Workordertab = bl_wo.Workordertab
  121. bl_wopart.Parttab = bl_part.Parttab
  122. // 获取零件在当前产线的拣料单模板,如果适配
  123. matched = false
  124. // 零件只能进入到一个匹配模板,因此要遍历产线上的所有拣料单模板,一旦适配则返回
  125. for _, bl_pktmp = range bl_wline.PickTmpDict {
  126. // 基于不同的适配模式做属性或者零件的适配
  127. switch bl_pktmp.Picktemplatetab.Adaptway {
  128. case common.PKT_ADAPT_BY_ATTR: // 比对零件属性是否在模板分配的属性中
  129. for _, pktmpattrtab = range bl_pktmp.AssignAttrDict {
  130. if _, ok = bl_part.AtcodDict[pktmpattrtab.Attrcode]; ok {
  131. matched = true
  132. wonr = bl_wo.Workordertab.Workordernr
  133. attrcode = pktmpattrtab.Attrcode
  134. picktmpid = bl_pktmp.TemplateId
  135. break
  136. }
  137. }
  138. case common.PKT_ADAPT_BY_PART: // 比对订单零件和模板分配零件是否相同
  139. for _, pktmpparttab = range bl_pktmp.AssignPartDict {
  140. if bl_wopart.Partid == pktmpparttab.Partid {
  141. matched = true
  142. wonr = bl_wo.Workordertab.Workordernr
  143. partid = bl_wo.Workordertab.Partlst[i].Partid
  144. picktmpid = bl_pktmp.TemplateId
  145. break
  146. }
  147. }
  148. default:
  149. continue
  150. }
  151. // 匹配成功,则该零件将不再进行对其它模板的匹配
  152. if matched {
  153. break
  154. }
  155. }
  156. // 如果适配,则将该零件加入到开口拣料单
  157. if matched {
  158. // 基于拣料单模板得到当前产线开口的拣料单
  159. bl_pko.TemplateId = picktmpid
  160. if exist, pickorderid, err = pe.GetOpenPickOrderByTemplate(session, &bl_pko, wonr, attrcode, partid); err != nil {
  161. bflag = false
  162. break
  163. }
  164. if !exist {
  165. // 不存在开口拣料单则新建
  166. if pickorderid, err = bl_pko.CreatePickOrder(session, pe, picktmpid); err != nil {
  167. bflag = false
  168. break
  169. }
  170. }
  171. // 将零件加入开口拣料单
  172. if err = bl_pko.AddPickingPart(session, attrcode, bl_wopart, pickorderid); err != nil {
  173. bflag = false
  174. break
  175. }
  176. // 判断拣料单是否已满,满则下达并生成拣料单消息用于拣料单打印
  177. if bl_pktmp.Picktemplatetab.Countmode == common.PKT_COUNT_MODE_BY_QTY {
  178. if released, err = bl_pko.TryToRelease(session, pickorderid, &bl_pktmp); err != nil {
  179. return
  180. }
  181. if released {
  182. // 生成用于打印的拣料单消息
  183. bl_ordmsg = service.BL_Ordmsg{MsgType: common.MSG_TYPE_PICK, MsgObjid: pickorderid, MsgEvent: common.MSG_EVENT_PRINT}
  184. if err = bl_ordmsg.Create(session); err != nil {
  185. return
  186. }
  187. }
  188. } else {
  189. pkodict[pickorderid] = bl_pktmp
  190. }
  191. }
  192. }
  193. // 检查那些按工单计数的开口拣料单是否达到计数要求,如是则关闭这些拣料单
  194. for pickorderid, bl_pktmp = range pkodict {
  195. if released, err = bl_pko.TryToRelease(session, pickorderid, &bl_pktmp); err != nil {
  196. return
  197. }
  198. if released {
  199. // 生成用于打印的拣料单消息
  200. bl_ordmsg = service.BL_Ordmsg{MsgType: common.MSG_TYPE_PICK, MsgObjid: pickorderid, MsgEvent: common.MSG_EVENT_PRINT}
  201. if err = bl_ordmsg.Create(session); err != nil {
  202. return
  203. }
  204. }
  205. }
  206. // 完成工单所有零件的匹配,更新工单的拣料状态
  207. if err = bl_wo.SetPickingStatus(session, 1); err != nil {
  208. bflag = false
  209. }
  210. if bflag {
  211. session.Commit()
  212. } else {
  213. session.Rollback()
  214. }
  215. session.Close()
  216. return
  217. }