forked from shotput/BoxPackingAPI
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathviews.py
234 lines (217 loc) · 7.68 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
from fulfillment_api.api_verify import verify_box_api
from fulfillment_api.constants import permissions
from .errors import APIError, BoxError
from .messages as msg
from ..authentication.login_required import (login_required,
shotput_permission_required)
from ..crossdomain import crossdomain
from ..permissions.decorators import view_requires_team_permission
from .helper import (api_packing_algorithm, compare_1000_times,
how_many_items_fit, pre_pack_boxes, space_after_packing)
from flask import Blueprint, current_app, jsonify, request
blueprint = Blueprint('box_packing', __name__)
@blueprint.route('/box_packing_api/basic',
methods=['POST', 'OPTIONS'])
@crossdomain(api=True)
@login_required
@verify_box_api
@view_requires_team_permission(permissions.box_packing_read)
def get_best_fit():
'''
A non-database calling endpoint which is a simple usage of the box packing
algorithm which accepts json with items and a single box.
Returns:
'packages': List[Dict[
items_packed: Dict[item, quantity]
total_weight: float
'''
json_data = request.get_json(force=True)
current_app.log.data(json_data)
try:
products_info = json_data['products_info']
box_info = json_data['box_info']
options = json_data.get('options', {})
except KeyError as e:
current_app.log.error(e)
return jsonify(error=msg.missing_value_for(e)), 400
try:
items_arrangement = pre_pack_boxes(box_info, products_info, options)
except BoxError as e:
current_app.log.error(e)
return jsonify(error=e.message), 400
except TypeError as e:
current_app.log.error(e)
return jsonify(error='Invalid data in request.'), 400
except ValueError as e:
current_app.log.error(e)
value = e.message.split(' ')[-1]
return jsonify(error=('Invalid data in request. Check value {}'
.format(value))), 400
except KeyError as e:
current_app.log.error(e)
return jsonify(error=msg.missing_value_for(e.message))
except APIError as e:
current_app.log.error(e)
return jsonify(error=e.message), e.status_code
return jsonify(packages=items_arrangement)
@blueprint.route('/box_packing_api/remaining_volume',
methods=['POST', 'OPTIONS'])
@crossdomain(api=True)
@login_required
@verify_box_api
@view_requires_team_permission(permissions.box_packing_read)
def get_space_after_packing():
'''
Non-database calling endpoint which calculates the remaining volume in a
block after packing. Assumes box and item are of same units
Input:
{
"box_info": {
"width": 9,
"height": 8,
"length": 5
},
"item_info": {
"width": 9,
"height": 8,
"length": 4
}
}
Output:
{
"remaining_dimensional_blocks": [
{
"height": 8,
"length": 9,
"width": 1
}
],
"remaining_volume": 72
}
'''
json_data = request.get_json(force=True)
current_app.log.data(json_data)
try:
item_info = json_data['product_info']
box_info = json_data['box_info']
space = space_after_packing(item_info, box_info)
except KeyError as e:
current_app.log.error(e)
return jsonify(error=msg.missing_value_for(e.message)), 400
except TypeError as e:
current_app.log.error(e)
return jsonify(error=msg.invalid_data), 400
except BoxError as e:
current_app.log.error(e)
return jsonify(error=e.message), 400
except APIError as e:
current_app.log.error(e)
return jsonify(error=e.message), e.status_code
return jsonify(space)
@blueprint.route('/box_packing_api/capacity', methods=['POST', 'OPTIONS'])
@crossdomain(api=True)
@login_required
@verify_box_api
@view_requires_team_permission(permissions.box_packing_read)
def how_many_fit():
'''
non-database hitting endpoint which calculates the capacity of a box
given a item size. Assumes dimensional units are the same.
Same inputs as remaining_volume.
Outputs:
{
"remaining_volume": 72,
"total_packed": 1
}
'''
json_data = request.get_json(force=True)
current_app.log.data(json_data)
try:
item_info = json_data['product_info']
box_info = json_data['box_info']
max_packed = json_data.get('max_packed')
return jsonify(how_many_items_fit(item_info, box_info, max_packed))
except KeyError as e:
current_app.log.error(e)
return jsonify(error=msg.missing_value_for(e.message)), 400
except TypeError as e:
current_app.log.error(e)
return jsonify(error=msg.invalid_data), 400
except BoxError as e:
current_app.log.error(e)
return jsonify(error=e.message)
except ValueError as e:
current_app.log.error(e)
value = e.message.split(' ')[-1]
return jsonify(error=('Invalid data in request. Check value {}'
.format(value))), 400
except APIError as e:
current_app.log.error(e)
return jsonify(error=e.message), e.status_code
@blueprint.route('/box_packing_api/compare_packing_efficiency',
methods=['GET', 'OPTIONS'])
@crossdomain(api=True)
@login_required
@shotput_permission_required
@view_requires_team_permission(permissions.global_god_mode)
def compare_pack():
'''
endpoint which can be used to verify the accuracy of
shotput v pyshipping
'''
params = request.args.to_dict()
current_app.log.data(params)
trials = params.get('trials')
return jsonify(compare_1000_times(trials))
@blueprint.route('/box_packing_api/full', methods=['POST', 'OPTIONS'])
@crossdomain(api=True)
@login_required
@verify_box_api
@view_requires_team_permission(permissions.box_packing_read)
def box_packing_api():
'''
a full access endpoint to the box algorithm, which accepts boxes and items
and returns the best box and the items arrangement
Outputs:
Dict[
'package_contents': List[Dict[
packed_prodcuts: Dict[item, quantity]
total_weight: float
box: Dict[
weight: float
height: float
length: float
width: float
dimension_units: ('inches', 'centimeters', 'feet', 'meters')
weight_units: ('grams', 'pounds', 'kilograms', 'onces')
name: String
]
]
]
'''
json_data = request.get_json(force=True)
current_app.log.data(json_data)
try:
boxes_info = json_data['boxes_info']
products_info = json_data['products_info']
options = json_data.get('options', {})
package_contents = api_packing_algorithm(boxes_info, products_info,
options)
except KeyError as e:
current_app.log.error(e)
return jsonify(error=msg.missing_value_for(e.message)), 400
except TypeError as e:
current_app.log.error(e)
return jsonify(error=msg.invalid_data), 400
except BoxError as e:
current_app.log.error(e)
return jsonify(error=e.message)
except ValueError as e:
current_app.log.error(e)
value = e.message.split(' ')[-1]
return jsonify(error=('Invalid data in request. Check value {}'
.format(value))), 400
except APIError as e:
current_app.log.error(e)
return jsonify(error=e.message), e.status_code
return jsonify(package_contents)