models.py 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. from django.db import models
  2. from container.models import ContainerListModel,ContainerWCSModel,TaskModel
  3. # 库位主表(记录实时状态)
  4. class LocationModel(models.Model):
  5. LOCATION_TYPES = (
  6. ('T5', '5货位'), # 5托盘/批次
  7. ('T4', '4货位'), # 4托盘/批次
  8. ('S4', '4单货位'), # 4单托盘
  9. ('T2', '2货位'), # 2托盘/批次
  10. ('T1', '散货位'), # 1托盘
  11. ('M1', '通道区'), # 通道区
  12. ('E1', '提升机'), # 提升机
  13. ('C1', '输送机'), # 输送机
  14. ('B1', '充电桩'), # 货架区
  15. )
  16. LOCATION_STATUS = (
  17. ('available', '可用'),
  18. ('occupied', '占用'),
  19. ('disabled', '禁用'),
  20. ('reserved', '预留'),
  21. ('maintenance', '维护中'),
  22. )
  23. warehouse_code = models.CharField(max_length=255, verbose_name="Warehouse code")
  24. warehouse_name = models.CharField(max_length=255, verbose_name="Warehouse Name")
  25. shelf_type = models.CharField(max_length=255,default = 'storage', verbose_name="Shelf Type")
  26. row = models.IntegerField(verbose_name="Row") # 位置的行号
  27. col = models.IntegerField(verbose_name="Column") # 位置的列号
  28. layer = models.IntegerField(verbose_name="Layer") # 位置的层号
  29. update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
  30. empty_label = models.BooleanField(default=True, verbose_name="Empty Flag")
  31. location_code = models.CharField(max_length=20, unique=True, verbose_name='库位编码')
  32. location_group = models.CharField(max_length=20, verbose_name='库位组')
  33. # 示例:T1-L1C001-1
  34. # T1-L1C001-1 代表货位类型为T1,层号为1,列号为001,货位号为1
  35. location_type = models.CharField(max_length=3, choices=LOCATION_TYPES, verbose_name='货位类型')
  36. status = models.CharField(max_length=20, choices=LOCATION_STATUS, default='available', verbose_name='库位状态')
  37. max_capacity = models.PositiveIntegerField(verbose_name='最大容量') # 根据类型自动设置
  38. current_quantity = models.PositiveIntegerField(default=0, verbose_name='当前数')
  39. c_number = models.IntegerField(default=1, verbose_name='库位远近排序')
  40. current_containers = models.ManyToManyField(ContainerListModel,
  41. through='LocationContainerLink',
  42. verbose_name='当前存放托盘')
  43. coordinate = models.CharField(max_length=50, verbose_name='三维坐标') # 格式:行-列-层
  44. access_priority = models.IntegerField(
  45. default=0,
  46. verbose_name='访问优先级',
  47. help_text='值越大表示越远离主通道,应优先使用'
  48. )
  49. is_active = models.BooleanField(default=True, verbose_name='是否有效')
  50. class Meta:
  51. db_table = 'location'
  52. verbose_name = 'Location'
  53. verbose_name_plural = "Location"
  54. ordering = ['-id']
  55. unique_together = ( 'warehouse_code','row', 'col', 'layer') # 防止重复坐标
  56. @classmethod
  57. def get_existing_positions(cls, warehouse_code, rows, cols, layers):
  58. """获取已存在的坐标集合"""
  59. return set(
  60. cls.objects.filter(
  61. warehouse_code=warehouse_code,
  62. row__lte=rows,
  63. col__lte=cols,
  64. layer__lte=layers
  65. ).values_list('row', 'col', 'layer')
  66. )
  67. # 在LocationModel类中新增方法
  68. @classmethod
  69. def generate_locations(cls, warehouse_code):
  70. # 清空现有数据(新增部分)
  71. cls.objects.filter(warehouse_code=warehouse_code).delete()
  72. """根据规划图生成库位"""
  73. # 定义核心参数(根据规划图调整)
  74. MAIN_AISLES = [18, 1] # 子通道列号
  75. SUB_AISLES = [2,8, 13] # 主通道行号
  76. for row in range(1, 14): # 1-13行
  77. for col in range(1, 3): # 1-19列
  78. for layer in range(1, 4): # 1-3层
  79. # 判断通道区
  80. if col in MAIN_AISLES or row in SUB_AISLES:
  81. loc_type = 'M1'
  82. c_number = row
  83. # 通道
  84. if col ==1 and row == 1:
  85. loc_type = 'T1'
  86. c_number = 1
  87. # 判断货位类型(根据实际规划)
  88. else:
  89. if row <2:
  90. loc_type = 'T1'
  91. c_number = 1
  92. elif row < 8:
  93. loc_type = 'T5'
  94. c_number = row-2
  95. elif row < 13:
  96. loc_type = 'T4'
  97. c_number = row-8
  98. else:
  99. loc_type = 'T2'
  100. c_number = 16-row
  101. # 生成唯一编码
  102. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  103. location_group = f"{loc_type}-L{layer}C{col:03d}"
  104. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  105. # 创建库位
  106. cls.objects.update_or_create(
  107. warehouse_code=warehouse_code,
  108. warehouse_name="立体仓库",
  109. row=row,
  110. col=col,
  111. layer=layer,
  112. c_number=c_number,
  113. shelf_type=loc_type,
  114. defaults={
  115. 'location_code': location_code,
  116. 'location_group': location_group,
  117. 'location_type': loc_type,
  118. 'max_capacity': {
  119. 'T5': 5,
  120. 'T4': 4,
  121. 'T2': 2,
  122. 'T1': 1,
  123. 'M1': 0,
  124. 'E1': 0,
  125. 'C1': 0
  126. }[loc_type],
  127. 'coordinate': f"{row}-{col}-{layer}",
  128. 'is_active': True
  129. },
  130. access_priority=c_number
  131. )
  132. for row in range(1, 16): # 1-15行
  133. for col in range(3, 17): # 1-16列
  134. for layer in range(1, 4): # 1-3层
  135. # 判断通道区
  136. if col in MAIN_AISLES or row in SUB_AISLES:
  137. loc_type = 'M1'
  138. c_number = row
  139. # 通道
  140. if col ==18 and row == 1:
  141. loc_type = 'T1'
  142. c_number = 1
  143. # 判断货位类型(根据实际规划)
  144. else:
  145. if row <2:
  146. loc_type = 'T1'
  147. c_number = 1
  148. elif row < 8:
  149. loc_type = 'T5'
  150. c_number = row-2
  151. elif row < 13:
  152. loc_type = 'T4'
  153. c_number = row-8
  154. else:
  155. loc_type = 'T2'
  156. c_number = 16-row
  157. # 生成唯一编码
  158. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  159. location_group = f"{loc_type}-L{layer}C{col:03d}"
  160. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  161. # 创建库位
  162. cls.objects.update_or_create(
  163. warehouse_code=warehouse_code,
  164. row=row,
  165. col=col,
  166. layer=layer,
  167. c_number=c_number,
  168. shelf_type=loc_type,
  169. defaults={
  170. 'location_code': location_code,
  171. 'location_group': location_group,
  172. 'location_type': loc_type,
  173. 'max_capacity': {
  174. 'T5': 5,
  175. 'T4': 4,
  176. 'T2': 2,
  177. 'T1': 1,
  178. 'M1': 0,
  179. 'E1': 0,
  180. 'C1': 0
  181. }[loc_type],
  182. 'coordinate': f"{row}-{col}-{layer}",
  183. 'is_active': True
  184. },
  185. access_priority=c_number
  186. )
  187. # print("✅ 库位生成成功!")
  188. for row in range(1, 14): # 1-15行
  189. for col in range(17, 20): # 1-16列
  190. for layer in range(1, 4): # 1-3层
  191. # 判断通道区
  192. if col in MAIN_AISLES or row in SUB_AISLES:
  193. loc_type = 'M1'
  194. c_number = row
  195. # 通道
  196. if col ==18 and row == 1:
  197. loc_type = 'T1'
  198. c_number = 1
  199. # 判断货位类型(根据实际规划)
  200. else:
  201. if row <2:
  202. loc_type = 'T1'
  203. c_number = 1
  204. elif row < 8:
  205. loc_type = 'T5'
  206. c_number = row-2
  207. elif row < 13:
  208. loc_type = 'T4'
  209. c_number = row-8
  210. else:
  211. loc_type = 'T2'
  212. c_number = 16-row
  213. # 生成唯一编码
  214. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  215. location_group = f"{loc_type}-L{layer}C{col:03d}"
  216. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  217. # 创建库位
  218. cls.objects.update_or_create(
  219. warehouse_code=warehouse_code,
  220. row=row,
  221. col=col,
  222. layer=layer,
  223. c_number=c_number,
  224. shelf_type=loc_type,
  225. defaults={
  226. 'location_code': location_code,
  227. 'location_group': location_group,
  228. 'location_type': loc_type,
  229. 'max_capacity': {
  230. 'T5': 5,
  231. 'T4': 4,
  232. 'T2': 2,
  233. 'T1': 1,
  234. 'M1': 0,
  235. 'E1': 0,
  236. 'C1': 0
  237. }[loc_type],
  238. 'coordinate': f"{row}-{col}-{layer}",
  239. 'is_active': True
  240. },
  241. access_priority=c_number
  242. )
  243. # print("✅ 库位生成成功!")
  244. for row in range(1, 18): # 1-17行
  245. for col in range(20, 30): # 19-29列
  246. for layer in range(1, 4): # 1-3层
  247. # 判断通道区
  248. if col in MAIN_AISLES or row in SUB_AISLES:
  249. loc_type = 'M1'
  250. c_number = row
  251. # 通道
  252. if col ==18 and row == 1:
  253. loc_type = 'T1'
  254. c_number = 1
  255. if col ==29 and row == 1:
  256. loc_type = 'T1'
  257. c_number = 1
  258. if col ==29 and row == 14:
  259. loc_type = 'S4'
  260. c_number = 4
  261. if col ==29 and row == 15:
  262. loc_type = 'S4'
  263. c_number = 3
  264. if col ==29 and row == 16:
  265. loc_type = 'S4'
  266. c_number = 2
  267. if col ==29 and row == 17:
  268. loc_type = 'S4'
  269. c_number = 1
  270. # 判断货位类型(根据实际规划)
  271. else:
  272. # 判断货位类型(根据实际规划)
  273. if row < 2:
  274. loc_type = 'T1'
  275. c_number = row
  276. elif row < 8:
  277. loc_type = 'T5'
  278. c_number = row-2
  279. elif row < 13:
  280. loc_type = 'T4'
  281. c_number = row-8
  282. else:
  283. loc_type = 'S4'
  284. c_number = 18-row
  285. # 生成唯一编码
  286. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  287. location_group = f"{loc_type}-L{layer}C{col:03d}"
  288. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  289. # 创建库位
  290. cls.objects.update_or_create(
  291. warehouse_code=warehouse_code,
  292. row=row,
  293. col=col,
  294. layer=layer,
  295. c_number=c_number,
  296. shelf_type=loc_type,
  297. defaults={
  298. 'location_code': location_code,
  299. 'location_group': location_group,
  300. 'location_type': loc_type,
  301. 'max_capacity': {
  302. 'T5': 5,
  303. 'T4': 4,
  304. 'S4': 4,
  305. 'T2': 2,
  306. 'T1': 1,
  307. 'M1': 0,
  308. 'E1': 0,
  309. 'C1': 0,
  310. 'B1': 0
  311. }[loc_type],
  312. 'coordinate': f"{row}-{col}-{layer}",
  313. 'is_active': True
  314. },
  315. access_priority=c_number
  316. )
  317. # 输送机
  318. for row in [14]: # 1-17行
  319. for col in [1,18]: # 1-19列
  320. for layer in range(1, 4): # 1-3层
  321. # 判断货位类型(根据实际规划)
  322. loc_type = 'C1'
  323. c_number = 1
  324. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  325. location_group = f"{loc_type}-L{layer}C{col:03d}"
  326. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  327. # 创建库位
  328. # 创建库位
  329. cls.objects.update_or_create(
  330. warehouse_code=warehouse_code,
  331. row=row,
  332. col=col,
  333. layer=layer,
  334. c_number=c_number,
  335. shelf_type=loc_type,
  336. defaults={
  337. 'location_code': location_code,
  338. 'location_group': location_group,
  339. 'location_type': loc_type,
  340. 'max_capacity': {
  341. 'T5': 5,
  342. 'T4': 4,
  343. 'S4': 4,
  344. 'T2': 2,
  345. 'T1': 1,
  346. 'M1': 0,
  347. 'E1': 0,
  348. 'C1': 0,
  349. 'B1': 0
  350. }[loc_type],
  351. 'coordinate': f"{row}-{col}-{layer}",
  352. 'is_active': True
  353. },
  354. access_priority=c_number
  355. )
  356. for row in [16]: # 1-17行
  357. for col in [1,18]: # 1-19列
  358. for layer in [1]: # 1-3层
  359. # 判断货位类型(根据实际规划)
  360. loc_type = 'C1'
  361. c_number = row
  362. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  363. location_group = f"{loc_type}-L{layer}C{col:03d}"
  364. # 创建库位
  365. cls.objects.update_or_create(
  366. warehouse_code=warehouse_code,
  367. row=row,
  368. col=col,
  369. layer=layer,
  370. c_number=c_number,
  371. shelf_type=loc_type,
  372. defaults={
  373. 'location_code': location_code,
  374. 'location_group': location_group,
  375. 'location_type': loc_type,
  376. 'max_capacity': {
  377. 'T5': 5,
  378. 'T4': 4,
  379. 'S4': 4,
  380. 'T2': 2,
  381. 'T1': 1,
  382. 'M1': 0,
  383. 'E1': 0,
  384. 'C1': 0,
  385. 'B1': 0
  386. }[loc_type],
  387. 'coordinate': f"{row}-{col}-{layer}",
  388. 'is_active': True
  389. },
  390. access_priority=c_number
  391. )
  392. # 提升机
  393. for row in [15]: # 1-17行
  394. for col in [1,18]: # 1-19列
  395. for layer in range(1, 4): # 1-3层
  396. # 判断货位类型(根据实际规划)
  397. loc_type = 'E1'
  398. c_number = row
  399. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  400. location_group = f"{loc_type}-L{layer}C{col:03d}"
  401. # 创建库位
  402. cls.objects.update_or_create(
  403. warehouse_code=warehouse_code,
  404. row=row,
  405. col=col,
  406. layer=layer,
  407. c_number=c_number,
  408. shelf_type=loc_type,
  409. defaults={
  410. 'location_code': location_code,
  411. 'location_group': location_group,
  412. 'location_type': loc_type,
  413. 'max_capacity': {
  414. 'T5': 5,
  415. 'T4': 4,
  416. 'S4': 4,
  417. 'T2': 2,
  418. 'T1': 1,
  419. 'M1': 0,
  420. 'E1': 0,
  421. 'C1': 0,
  422. 'B1': 0
  423. }[loc_type],
  424. 'coordinate': f"{row}-{col}-{layer}",
  425. 'is_active': True
  426. },
  427. access_priority=c_number
  428. )
  429. # 充电桩
  430. for row in [14]: # 1-17行
  431. for col in [2]: # 1-19列
  432. for layer in range(1, 3): # 1-3层
  433. # 判断货位类型(根据实际规划)
  434. loc_type = 'B1'
  435. c_number = 1
  436. location_code = f"{loc_type}-L{layer}C{col:03d}-{c_number:02d}"
  437. location_group = f"{loc_type}-L{layer}C{col:03d}"
  438. # 创建库位
  439. cls.objects.update_or_create(
  440. warehouse_code=warehouse_code,
  441. row=row,
  442. col=col,
  443. layer=layer,
  444. c_number=c_number,
  445. shelf_type=loc_type,
  446. defaults={
  447. 'location_code': location_code,
  448. 'location_group': location_group,
  449. 'location_type': loc_type,
  450. 'max_capacity': {
  451. 'T5': 5,
  452. 'T4': 4,
  453. 'S4': 4,
  454. 'T2': 2,
  455. 'T1': 1,
  456. 'M1': 0,
  457. 'E1': 0,
  458. 'C1': 0,
  459. 'B1': 0
  460. }[loc_type],
  461. 'coordinate': f"{row}-{col}-{layer}",
  462. 'is_active': True
  463. },
  464. access_priority=c_number
  465. )
  466. class LocationGroupModel(models.Model):
  467. LOCATION_TYPES = (
  468. ('T5', '5货位'), # 5托盘/批次
  469. ('T4', '4货位'), # 4托盘/批次
  470. ('S4', '4单货位'), # 4单托盘
  471. ('T2', '2货位'), # 2托盘/批次
  472. ('T1', '散货位'), # 1托盘
  473. )
  474. LOCATION_STATUS = (
  475. ('available', '可用'),
  476. ('occupied', '占用'),
  477. ('full', '满'),
  478. ('disabled', '禁用'),
  479. ('reserved', '预留'),
  480. ('maintenance', '维护中'),
  481. )
  482. warehouse_code = models.CharField(max_length=50, verbose_name='仓库编码')
  483. group_name = models.CharField(max_length=50, verbose_name='库位组名称')
  484. group_type = models.CharField(max_length=50, choices=LOCATION_TYPES, verbose_name='库位组类型')
  485. group_code = models.CharField(max_length=50, verbose_name='库位组编码')
  486. layer = models.PositiveIntegerField(verbose_name='层数')
  487. location_items = models.ManyToManyField(LocationModel, verbose_name='库位')
  488. status = models.CharField(max_length=20, choices=LOCATION_STATUS, default='available', verbose_name='库位状态')
  489. max_capacity = models.PositiveIntegerField(verbose_name='最大容量') # 根据类型自动设置
  490. current_quantity = models.PositiveIntegerField(default=0, verbose_name='当前托盘数')
  491. current_goods_quantity = models.PositiveIntegerField(default=0, verbose_name='当前货物数')
  492. current_batch = models.CharField(max_length=50, default='', verbose_name='当前批次')
  493. current_goods_code = models.CharField(max_length=50, default='', verbose_name='当前货物编码')
  494. access_priority = models.IntegerField(
  495. default=0,
  496. verbose_name='访问优先级',
  497. help_text='值越大表示越远离主通道,应优先使用'
  498. )
  499. left_priority = models.IntegerField(
  500. default=0,
  501. verbose_name='左侧优先级',
  502. help_text='值越大表示越靠左,应优先使用'
  503. )
  504. right_priority = models.IntegerField(
  505. default=0,
  506. verbose_name='右侧优先级',
  507. help_text='值越大表示越靠右,应优先使用'
  508. )
  509. is_active = models.BooleanField(default=True, verbose_name='是否有效')
  510. # create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
  511. class Meta:
  512. db_table = 'location_group'
  513. verbose_name = 'Location Group'
  514. verbose_name_plural = "Location Group"
  515. ordering = ['-id']
  516. unique_together = ( 'warehouse_code', 'group_code') # 防止重复组编码
  517. @classmethod
  518. def generate_group(cls,warehouse_code):
  519. cls.objects.filter(warehouse_code=warehouse_code).delete()
  520. MAIN_AISLES = [18, 1] # 子通道列号
  521. SUB_AISLES = [2,8, 13] # 主通道行号
  522. for row in range(1, 14): # 1-13行
  523. for col in range(1, 3): # 1-19列
  524. for layer in range(1, 4): # 1-3层
  525. # 判断通道区
  526. if col in MAIN_AISLES or row in SUB_AISLES:
  527. loc_type = 'M1'
  528. c_number = row
  529. # 通道
  530. if col ==1 and row == 1:
  531. loc_type = 'T1'
  532. c_number = 1
  533. # 判断货位类型(根据实际规划)
  534. else:
  535. if row <2:
  536. loc_type = 'T1'
  537. c_number = 1
  538. elif row < 8:
  539. loc_type = 'T5'
  540. c_number = row-2
  541. elif row < 13:
  542. loc_type = 'T4'
  543. c_number = row-8
  544. else:
  545. loc_type = 'T2'
  546. c_number = 16-row
  547. # 生成唯一编码
  548. print(f"生成库组:{row}-{col}-{layer}")
  549. if loc_type == 'M1':
  550. continue
  551. # 创建库位
  552. group_code = f"{loc_type}-L{layer}C{col:03d}"
  553. group_name = f"{loc_type}-L{layer}C{col:03d}"
  554. # 使用(row+col)*layer作为库位排序
  555. left_priority = (abs(row-13)+abs(col-1))*layer
  556. right_priority = (abs(row-13)+abs(col-18))*layer
  557. if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
  558. group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
  559. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  560. group_item.save()
  561. else:
  562. group_item = cls.objects.create(
  563. warehouse_code=warehouse_code,
  564. layer=layer,
  565. group_name=group_name,
  566. group_type=loc_type,
  567. group_code=group_code,
  568. max_capacity={
  569. 'T5': 5,
  570. 'T4': 4,
  571. 'T2': 2,
  572. 'T1': 1,
  573. 'S4': 4,
  574. 'M1': 0,
  575. 'E1': 0,
  576. 'C1': 0
  577. }[loc_type],
  578. current_quantity=0,
  579. status='available',
  580. access_priority=c_number,
  581. left_priority=left_priority,
  582. right_priority=right_priority,
  583. is_active=True
  584. )
  585. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  586. group_item.save()
  587. for row in range(1, 16): # 1-15行
  588. for col in range(3, 17): # 1-16列
  589. for layer in range(1, 4): # 1-3层
  590. # 判断通道区
  591. if col in MAIN_AISLES or row in SUB_AISLES:
  592. loc_type = 'M1'
  593. c_number = row
  594. # 通道
  595. if col ==18 and row == 1:
  596. loc_type = 'T1'
  597. c_number = 1
  598. # 判断货位类型(根据实际规划)
  599. else:
  600. if row <2:
  601. loc_type = 'T1'
  602. c_number = 1
  603. elif row < 8:
  604. loc_type = 'T5'
  605. c_number = row-2
  606. elif row < 13:
  607. loc_type = 'T4'
  608. c_number = row-8
  609. else:
  610. loc_type = 'T2'
  611. c_number = 16-row
  612. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  613. if loc_type == 'M1':
  614. continue
  615. # 创建库位
  616. group_code = f"{loc_type}-L{layer}C{col:03d}"
  617. group_name = f"{loc_type}-L{layer}C{col:03d}"
  618. left_priority = (abs(row-13)+abs(col-1))*layer
  619. right_priority = (abs(row-13)+abs(col-18))*layer
  620. if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
  621. group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
  622. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  623. group_item.save()
  624. else:
  625. group_item = cls.objects.create(
  626. warehouse_code=warehouse_code,
  627. layer=layer,
  628. group_name=group_name,
  629. group_type=loc_type,
  630. group_code=group_code,
  631. max_capacity={
  632. 'T5': 5,
  633. 'T4': 4,
  634. 'T2': 2,
  635. 'T1': 1,
  636. 'S4': 4,
  637. 'M1': 0,
  638. 'E1': 0,
  639. 'C1': 0
  640. }[loc_type],
  641. current_quantity=0,
  642. status='available',
  643. access_priority=c_number,
  644. left_priority=left_priority,
  645. right_priority=right_priority,
  646. is_active=True
  647. )
  648. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  649. group_item.save()
  650. for row in range(1, 14): # 1-15行
  651. for col in range(17, 20): # 1-16列
  652. for layer in range(1, 4): # 1-3层
  653. # 判断通道区
  654. if col in MAIN_AISLES or row in SUB_AISLES:
  655. loc_type = 'M1'
  656. c_number = row
  657. # 通道
  658. if col ==18 and row == 1:
  659. loc_type = 'T1'
  660. c_number = 1
  661. # 判断货位类型(根据实际规划)
  662. else:
  663. if row <2:
  664. loc_type = 'T1'
  665. c_number = 1
  666. elif row < 8:
  667. loc_type = 'T5'
  668. c_number = row-2
  669. elif row < 13:
  670. loc_type = 'T4'
  671. c_number = row-8
  672. else:
  673. loc_type = 'T2'
  674. c_number = 16-row
  675. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  676. if loc_type == 'M1':
  677. continue
  678. # 创建库位
  679. group_code = f"{loc_type}-L{layer}C{col:03d}"
  680. group_name = f"{loc_type}-L{layer}C{col:03d}"
  681. left_priority = (abs(row-13)+abs(col-1))*layer
  682. right_priority = (abs(row-13)+abs(col-18))*layer
  683. if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
  684. group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
  685. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  686. group_item.save()
  687. else:
  688. group_item = cls.objects.create(
  689. warehouse_code=warehouse_code,
  690. layer=layer,
  691. group_name=group_name,
  692. group_type=loc_type,
  693. group_code=group_code,
  694. max_capacity={
  695. 'T5': 5,
  696. 'T4': 4,
  697. 'T2': 2,
  698. 'T1': 1,
  699. 'S4': 4,
  700. 'M1': 0,
  701. 'E1': 0,
  702. 'C1': 0
  703. }[loc_type],
  704. current_quantity=0,
  705. status='available',
  706. access_priority=c_number,
  707. left_priority=left_priority,
  708. right_priority=right_priority,
  709. is_active=True
  710. )
  711. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  712. group_item.save()
  713. for row in range(1, 18): # 1-17行
  714. for col in range(20, 30): # 19-29列
  715. for layer in range(1, 4): # 1-3层
  716. # 判断通道区
  717. if col in MAIN_AISLES or row in SUB_AISLES:
  718. loc_type = 'M1'
  719. c_number = row
  720. # 通道
  721. if col ==18 and row == 1:
  722. loc_type = 'T1'
  723. c_number = 1
  724. if col ==29 and row == 1:
  725. loc_type = 'T1'
  726. c_number = 1
  727. if col ==29 and row == 14:
  728. loc_type = 'S4'
  729. c_number = 4
  730. if col ==29 and row == 15:
  731. loc_type = 'S4'
  732. c_number = 3
  733. if col ==29 and row == 16:
  734. loc_type = 'S4'
  735. c_number = 2
  736. if col ==29 and row == 17:
  737. loc_type = 'S4'
  738. c_number = 1
  739. # 判断货位类型(根据实际规划)
  740. else:
  741. # 判断货位类型(根据实际规划)
  742. if row < 2:
  743. loc_type = 'T1'
  744. c_number = row
  745. elif row < 8:
  746. loc_type = 'T5'
  747. c_number = row-2
  748. elif row < 13:
  749. loc_type = 'T4'
  750. c_number = row-8
  751. else:
  752. loc_type = 'S4'
  753. c_number = 18-row
  754. # print(f"生成库位:{location_code}-{row}-{col}-{layer}")
  755. if loc_type == 'M1':
  756. continue
  757. # 创建库位
  758. group_code = f"{loc_type}-L{layer}C{col:03d}"
  759. group_name = f"{loc_type}-L{layer}C{col:03d}"
  760. left_priority = (abs(row-13)+abs(col-1))*layer
  761. right_priority = (abs(row-13)+abs(col-18))*layer
  762. if cls.objects.filter(warehouse_code=warehouse_code, group_code=group_code).exists():
  763. group_item = cls.objects.get(warehouse_code=warehouse_code, group_code=group_code)
  764. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  765. group_item.save()
  766. else:
  767. group_item = cls.objects.create(
  768. warehouse_code=warehouse_code,
  769. layer=layer,
  770. group_name=group_name,
  771. group_type=loc_type,
  772. group_code=group_code,
  773. max_capacity={
  774. 'T5': 5,
  775. 'T4': 4,
  776. 'T2': 2,
  777. 'T1': 1,
  778. 'S4': 4,
  779. 'M1': 0,
  780. 'E1': 0,
  781. 'C1': 0
  782. }[loc_type],
  783. current_quantity=0,
  784. status='available',
  785. access_priority=c_number,
  786. left_priority=left_priority,
  787. right_priority=right_priority,
  788. is_active=True
  789. )
  790. group_item.location_items.add(LocationModel.objects.get(warehouse_code=warehouse_code, row=row, col=col, layer=layer))
  791. group_item.save()
  792. # 库位-托盘关联表(记录实时存放关系)
  793. class LocationContainerLink(models.Model):
  794. location = models.ForeignKey(
  795. LocationModel,
  796. on_delete=models.CASCADE,
  797. related_name='container_links', # 关键修复点
  798. verbose_name='库位'
  799. )
  800. container = models.ForeignKey(
  801. ContainerListModel,
  802. on_delete=models.CASCADE,
  803. related_name='location_links', # 容器到链接的反向关联
  804. verbose_name='关联容器'
  805. )
  806. task_wcs = models.ForeignKey(
  807. ContainerWCSModel,
  808. on_delete=models.CASCADE,
  809. )
  810. task_wcs = models.ForeignKey(ContainerWCSModel, on_delete=models.CASCADE, null=True, blank=True)
  811. task_detail = models.ForeignKey(TaskModel, on_delete=models.CASCADE, null=True, blank=True)
  812. put_time = models.DateTimeField(auto_now_add=True, verbose_name='上架时间')
  813. operator = models.CharField(max_length=50, verbose_name='操作人')
  814. is_active = models.BooleanField(default=True, verbose_name='是否有效')
  815. class Meta:
  816. db_table = 'location_container_link'
  817. verbose_name = 'Location-Container Link'
  818. verbose_name_plural = "Location-Container Link"
  819. ordering = ['-id']
  820. unique_together = ( 'location', 'container') # 防止重复关联
  821. class DeviceModel(models.Model):
  822. warehouse_code = models.CharField(max_length=255, verbose_name="Warehouse Code")
  823. location = models.ForeignKey(LocationModel, on_delete=models.CASCADE)
  824. device_id = models.CharField(max_length=255, verbose_name="Device ID")
  825. device_name = models.CharField(max_length=255, verbose_name="Device Name")
  826. device_type = models.CharField(max_length=255, verbose_name="Device Type")
  827. ip_address = models.CharField(max_length=255, verbose_name="IP Address")
  828. port = models.IntegerField(verbose_name="Port")
  829. mode = models.CharField(default='inbound', max_length=255, verbose_name="Mode")
  830. status = models.CharField(max_length=255, verbose_name="Status")
  831. create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
  832. update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
  833. class Meta:
  834. db_table = 'device'
  835. verbose_name = 'Device'
  836. verbose_name_plural = "Device"
  837. ordering = ['-id']
  838. unique_together = ( 'location', 'device_id') # 防止重复设备
  839. @classmethod
  840. def generate_device(cls,warehouse_code):
  841. cls.objects.filter(warehouse_code=warehouse_code).delete()
  842. # 输送机
  843. location = LocationModel.objects.get(warehouse_code=warehouse_code, row=16, col=1, layer=1)
  844. # 创建库位
  845. cls.objects.update_or_create(
  846. warehouse_code=warehouse_code,
  847. location=location,
  848. device_id=f"203",
  849. device_name=f"203",
  850. device_type='输送机',
  851. ip_address='192.168.18.1',
  852. mode = 'inbound',
  853. port=203,
  854. status='available',
  855. )
  856. location = LocationModel.objects.get(warehouse_code=warehouse_code, row=16, col=18, layer=1)
  857. # 创建库位
  858. cls.objects.update_or_create(
  859. warehouse_code=warehouse_code,
  860. location=location,
  861. device_id=f"103",
  862. device_name=f"103",
  863. device_type='输送机',
  864. ip_address='192.168.18.1',
  865. mode = 'outbound',
  866. port=103,
  867. status='available',
  868. )
  869. # 库位变更记录(历史追溯)
  870. class LocationChangeLog(models.Model):
  871. OPERATION_TYPES = (
  872. ('put', '上架'),
  873. ('pick', '下架'),
  874. ('move_in', '移入'),
  875. ('move_out', '移出')
  876. )
  877. location = models.ForeignKey(LocationModel, on_delete=models.CASCADE, verbose_name='库位')
  878. container = models.ForeignKey(ContainerListModel, on_delete=models.CASCADE, verbose_name='托盘')
  879. task_wcs = models.ForeignKey(ContainerWCSModel, on_delete=models.CASCADE, null=True, blank=True, verbose_name='WCS任务')
  880. task_detail = models.ForeignKey(TaskModel, on_delete=models.CASCADE, null=True, blank=True, verbose_name='批次详情')
  881. operation_type = models.CharField(max_length=10, choices=OPERATION_TYPES, verbose_name='操作类型')
  882. related_location = models.ForeignKey(LocationModel,
  883. on_delete=models.SET_NULL,
  884. null=True,
  885. related_name='related_logs',
  886. verbose_name='关联库位') # 用于移库操作
  887. timestamp = models.DateTimeField(auto_now_add=True, verbose_name='操作时间')
  888. class Meta:
  889. db_table = 'location_change_log'
  890. verbose_name = 'Location Change Log'
  891. verbose_name_plural = "Location Change Log"
  892. ordering = ['-id']
  893. class base_location(models.Model):
  894. layer1_pressure = models.IntegerField(default=0, verbose_name='第一层工作压力')
  895. layer2_pressure = models.IntegerField(default=0, verbose_name='第二层工作压力')
  896. layer3_pressure = models.IntegerField(default=0, verbose_name='第三层工作压力')
  897. class Meta:
  898. db_table = 'base_location'
  899. verbose_name = 'Base_location'
  900. verbose_name_plural = "Base_location"
  901. ordering = ['-id']
  902. class alloction_pre(models.Model):
  903. batch_number = models.CharField(max_length=255, verbose_name='批次号')
  904. layer_pre_type = models.JSONField(default=list, verbose_name='预留方案')
  905. layer_solution_type = models.JSONField(default=list, verbose_name='规划方案')
  906. layer1_task_finish_number = models.IntegerField(default=0, verbose_name='第一层任务完成数')
  907. layer2_task_finish_number = models.IntegerField(default=0, verbose_name='第二层任务完成数')
  908. layer3_task_finish_number = models.IntegerField(default=0, verbose_name='第三层任务完成数')
  909. create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
  910. class Meta:
  911. db_table = 'allocation_pre'
  912. verbose_name = 'Allocation_pre'
  913. verbose_name_plural = "Allocation_pre"
  914. ordering = ['-id']
  915. class allocation_history(models.Model):
  916. location = models.ForeignKey(LocationModel, on_delete=models.CASCADE, verbose_name='库位')
  917. container = models.ForeignKey(ContainerListModel, on_delete=models.CASCADE, verbose_name='托盘')
  918. task_wcs = models.ForeignKey(ContainerWCSModel, on_delete=models.CASCADE, null=True, blank=True, verbose_name='WCS任务')
  919. task_detail = models.ForeignKey(TaskModel, on_delete=models.CASCADE, null=True, blank=True, verbose_name='批次详情')
  920. operation_type = models.CharField(max_length=10, verbose_name='操作类型')
  921. related_location = models.ForeignKey(LocationModel,
  922. on_delete=models.SET_NULL,
  923. null=True,
  924. related_name='related_logs_history',
  925. verbose_name='关联库位') # 用于移库操作
  926. timestamp = models.DateTimeField(auto_now_add=True, verbose_name='操作时间')
  927. class Meta:
  928. db_table = 'allocation_history'
  929. verbose_name = 'Allocation_history'
  930. verbose_name_plural = "Allocation_history"
  931. ordering = ['-id']