Skip to content
This repository was archived by the owner on Feb 17, 2023. It is now read-only.

Commit b7e320c

Browse files
authored
Merge pull request #5 from W-A-L-L-3/develop
v1.0.0
2 parents 9b08a30 + a1c6cc8 commit b7e320c

37 files changed

+1211
-2
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,9 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130+
131+
# Ignore PyCharm files
132+
.idea/
133+
134+
#Ignore storehouse model file
135+
storehouse.pickle

API/README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ppo_it_5_2021
2+
3+
## Сервис для моделирования аппаратной части электронного скада
4+
5+
Для установки зависимостей:
6+
7+
```bash
8+
pip3 install -r requirements.txt
9+
```
10+
11+
Запуск:
12+
13+
```bash
14+
python3 app.py
15+
```
16+
17+
При запуске создается случайным образом схема вертикального склада.
18+
19+
Приложение по умолчанию запускается на `localhost:5000`.
20+
21+
Для изменения адреса и порта воспользуйтесь документацией [flask](https://flask.palletsprojects.com/en/1.1.x/).

API/__init__.py

Whitespace-only changes.

API/app.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python3
2+
import json
3+
4+
from flask import Flask, request
5+
6+
from storage import Storage
7+
8+
app = Flask(__name__)
9+
10+
11+
@app.route('/scheme', methods=['GET'])
12+
def index():
13+
return json.dumps(st.storageStructure)
14+
15+
16+
@app.route('/', methods=['POST'])
17+
def addItems():
18+
putData = request.get_json()
19+
addItemsResponse = True
20+
for item in putData:
21+
localResponse = st.putInStorage(item['uuid'], item['destination'])
22+
if localResponse is False:
23+
addItemsResponse = False
24+
if addItemsResponse is True:
25+
return {"status": "ok"}
26+
else:
27+
return {"status": "error"}, 400
28+
29+
30+
@app.route('/position', methods=['GET'])
31+
def getItems():
32+
destination = request.args.getlist('destination')
33+
getItemsResponse = st.getFromStorage(destination)
34+
if getItemsResponse >= 0:
35+
return {"status": "ok"}
36+
elif getItemsResponse == -1:
37+
return {"status": "position is empty"}, 404
38+
elif getItemsResponse == -2:
39+
return {"status": "position does not exist"}, 400
40+
41+
42+
if __name__ == '__main__':
43+
st = Storage()
44+
st.generateStorage()
45+
app.run(debug=True)

API/storage.py

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
from random import randint
2+
3+
MIN_SIZE = 3
4+
MAX_SIZE = 9
5+
MIN_MERGED_CELLS = 2
6+
7+
QUAD_CELLS = 4
8+
DOUBLE_CELLS = 2
9+
10+
11+
class Storage:
12+
def __init__(self):
13+
self.x = 0
14+
self.y = 0
15+
self.z = 0
16+
self.mergedCells = []
17+
self.busyCells = []
18+
self.storageStructure = {
19+
'size': {},
20+
'merged': []
21+
}
22+
23+
def setStorageSizes(self, x, y, z):
24+
if x > 0 and y > 0 and z > 0:
25+
self.x = int(x)
26+
self.y = int(y)
27+
self.z = int(z)
28+
self.storageStructure['size']['size_x'] = self.x
29+
self.storageStructure['size']['size_y'] = self.y
30+
self.storageStructure['size']['size_z'] = self.z
31+
32+
def changeCellName(self, x, y):
33+
return chr(ord(str(x)) + 16) + str(y)
34+
35+
def setStorageMergedCells(self, cellsList):
36+
addedList = []
37+
for i in range(0, len(cellsList) - 1, 2):
38+
self.mergedCells.append([cellsList[i], cellsList[i + 1]])
39+
addedList.append(self.changeCellName(cellsList[i], cellsList[i + 1]))
40+
self.storageStructure['merged'].append(sorted(addedList))
41+
42+
def generateRandomMergedCells(self, typeMergCells):
43+
localX = max(self.x, self.z)
44+
x1 = randint(1, localX)
45+
y1 = randint(1, self.y)
46+
x2 = x1
47+
y2 = y1 + 1 if y1 < self.y else y1 - 1
48+
iter = 0
49+
while ([x1, y1] in self.mergedCells or [x2, y2] in self.mergedCells):
50+
x1 = randint(1, localX)
51+
y1 = randint(1, self.y)
52+
x2 = x1
53+
y2 = y1 + 1 if y1 < self.y else y1 - 1
54+
iter += 1
55+
if iter == 200:
56+
return
57+
if typeMergCells == DOUBLE_CELLS:
58+
self.setStorageMergedCells([x1, y1, x2, y2])
59+
return
60+
if typeMergCells == QUAD_CELLS:
61+
x3 = x1 + 1 if x1 < localX else x1 - 1
62+
x4 = x3
63+
y3 = y1
64+
y4 = y2
65+
if [x3, y3] in self.mergedCells or [x4, y4] in self.mergedCells:
66+
return False
67+
else:
68+
self.setStorageMergedCells([x1, y1, x2, y2, x3, y3, x4, y4])
69+
return True
70+
71+
def generateStorage(self):
72+
typeOfStorage = 1
73+
if typeOfStorage == 1:
74+
self.setStorageSizes(randint(MIN_SIZE, MAX_SIZE),
75+
randint(MIN_SIZE, MAX_SIZE), 1)
76+
else:
77+
self.setStorageSizes(1, randint(MIN_SIZE, MAX_SIZE),
78+
randint(MIN_SIZE, MAX_SIZE))
79+
localX = max(self.x, self.z)
80+
maxQuontatyMerged = localX * self.y // 3
81+
quontatyMerged = randint(MIN_MERGED_CELLS, maxQuontatyMerged)
82+
quontSquadCells = quontatyMerged // 3 if quontatyMerged // 3 > 1 else 1
83+
for _ in range(quontSquadCells):
84+
self.generateRandomMergedCells(QUAD_CELLS)
85+
for _ in range(quontatyMerged - quontSquadCells):
86+
self.generateRandomMergedCells(DOUBLE_CELLS)
87+
self.storageStructure['merged'].sort()
88+
89+
def putInStorage(self, id, destination):
90+
returnCode = True
91+
if destination in self.storageStructure['merged']:
92+
for i in destination:
93+
if i in self.busyCells:
94+
returnCode = False
95+
break
96+
if returnCode is True:
97+
for i in destination:
98+
self.busyCells.append(i)
99+
elif len(destination) == 1:
100+
strDest = destination[0]
101+
x = int(chr(ord(strDest[0]) - 16)) # from symbol to int
102+
y = int(strDest[1])
103+
localX = max(self.x, self.z)
104+
if (x <= localX and y <= self.y and
105+
strDest not in self.busyCells):
106+
self.busyCells.append(strDest)
107+
else:
108+
returnCode = False
109+
else:
110+
returnCode = False
111+
return returnCode
112+
113+
def checkCellExistence(self, cellName):
114+
localX = max(self.x, self.z)
115+
if len(cellName) > 2 or cellName[0] > 'I':
116+
return False
117+
x = int(chr(ord(cellName[0]) - 16))
118+
y = int(cellName[1])
119+
print(x)
120+
print(y)
121+
if (x <= localX and y <= self.y):
122+
return True
123+
else:
124+
return False
125+
126+
def getFromStorage(self, destination):
127+
returnCode = 0
128+
for i in destination:
129+
cellInStorageFlag = True if self.checkCellExistence(i) else False
130+
if cellInStorageFlag is True:
131+
if i in self.busyCells:
132+
self.busyCells.remove(i)
133+
else:
134+
returnCode = -1
135+
else:
136+
returnCode = -2
137+
return returnCode
138+
139+
140+
if __name__ == '__main__':
141+
st = Storage()
142+
st.generateStorage()
143+
print(st.storageStructure)

README.md

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,23 @@
1-
# electronic-storehouse
2-
Московская предпрофессиональная олимпиада школьников. Профиль "Информационные технологии". Командный кейс №5 "Электронный склад"
1+
# Электронный склад
2+
3+
Московская предпрофессиональная олимпиада школьников.
4+
5+
Профиль "Информационные технологии".
6+
7+
Командный кейс №5 "Электронный склад"
8+
9+
[Исходный текст технического задания](https://github.com/W-A-L-L-3/electronic-storehouse/blob/main/docs/technical-requirements.pdf)
10+
11+
## Кратное описание
12+
13+
Информационный сервис обеспечивающий взаимодействие пользователей (операторов) с автоматизированным складом.
14+
15+
## Функциональность
16+
17+
1. Добавление нескольких позиций из поставки на склад.
18+
2. Отображение в виде списка позиций (товаров), с указанием ячейки, в которой товар находится на складе (по запросу в
19+
пользовательском интерфейсе).
20+
21+
3. Выбора определенного товара (позиции), для осуществления выдачи его аппаратной частью.
22+
4. Наличие удалённого склада для позиций, которые невозможно разместить на основном складе.
23+
5. Отображение в виде списка позиций (товаров), находящихся на удалённом складе.

constants.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# File with constants
2+
3+
STOREHOUSE_FILE_NAME = 'storehouse.pickle'
4+
GET_PARAMS_ADDRESS = 'http://127.0.0.1:5000/scheme'
5+
MAX_ADDING_ITEMS = 30 # Maximum number of rows on one adding-window
6+
7+
8+
class AddingW:
9+
NAME_INDEX = 1
10+
SIZE_INDEX = 2
11+
MASS_INDEX = 3

docs/img/adding_window_1.jpg

15.8 KB
Loading

docs/img/adding_window_2.jpg

18.2 KB
Loading

docs/img/adding_window_3.jpg

16.3 KB
Loading

docs/img/adding_window_4.jpg

15.8 KB
Loading

docs/img/correct_adding.jpg

10.8 KB
Loading

docs/img/correct_taking.jpg

9.46 KB
Loading

docs/img/info_window.jpg

12 KB
Loading

docs/img/main_window_1.jpg

23.8 KB
Loading

docs/img/main_window_2.jpg

29.8 KB
Loading

docs/img/receiving_error.jpg

11.7 KB
Loading

docs/img/remote_info_window.jpg

7.35 KB
Loading
8.71 KB
Loading

docs/img/taking_error.jpg

9.1 KB
Loading

docs/img/taking_window.jpg

6.57 KB
Loading

docs/img/value_error.jpg

8.78 KB
Loading

docs/technical-requirements.pdf

124 KB
Binary file not shown.

exceptions.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# File with my exceptions
2+
3+
RECEIVING_ERROR = 1
4+
OK = 0
5+
6+
7+
class ReceivingError(Exception):
8+
pass
9+
10+
11+
class EntryContentError(ValueError):
12+
"""Incorrect values in entries"""
13+
14+
def __init__(self, field, exception_type=""):
15+
self.field = field # Field index
16+
self.exception_type = exception_type
17+
18+
19+
class ItemNotFoundError(Exception):
20+
pass

gui/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)