models.py 45 KB

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