models.py 45 KB

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