def sku_patch(id): try: json = sku_patch_schema.extend({"id": prefixed_id("SKU", id)})(request.json) except MultipleInvalid as e: return problem.invalid_params_response(e) existing = Sku.from_mongodb_doc(db.sku.find_one({"_id": id})) if not existing: return problem.invalid_params_response( problem.missing_resource_param_error("id")) if "owned_codes" in json: db.sku.update_one({"_id": id}, {"$set": { "owned_codes": json["owned_codes"] }}) if "associated_codes" in json: db.sku.update_one( {"_id": id}, {"$set": { "associated_codes": json["associated_codes"] }}) if "name" in json: db.sku.update_one({"_id": id}, {"$set": {"name": json["name"]}}) if "props" in json: db.sku.update_one({"_id": id}, {"$set": {"props": json["props"]}}) updated_sku = Sku.from_mongodb_doc(db.sku.find_one({"_id": id})) return SkuEndpoint.from_sku(updated_sku).updated_success_response()
def test_sku_equality(original_sku): serde1_sku = Sku.from_json(original_sku.to_json()) serde2_sku = Sku.from_mongodb_doc(original_sku.to_mongodb_doc()) assert original_sku == serde1_sku assert serde1_sku == original_sku assert original_sku == serde2_sku assert serde2_sku == original_sku assert serde1_sku == serde2_sku assert original_sku == original_sku
def test_change_batch_sku(): state = InventoryStateMachine() sku0 = state.new_sku(sku=Sku(id='SKU000000', name='')) sku1 = state.new_sku(sku=Sku(id='SKU000001', name='')) data = dst.DataProxy(Batch(id='BAT000000', sku_id=sku0)) batch0 = state.new_batch_existing_sku(data=data, sku_id=sku0) state.attempt_update_nonanonymous_batch_sku_id(batch_id=batch0, patch={}, sku_id=sku1) state.teardown()
def new_sku_bad_format_owned_codes(self, sku, bad_code): assume(sku.id not in self.model_skus.keys()) temp_sku = Sku.from_json(sku.to_json()) temp_sku.owned_codes.append(bad_code) resp = self.client.post('/api/skus', json=temp_sku.to_dict()) assert resp.status_code == 400 assert resp.is_json assert resp.json['type'] == 'validation-error' temp_sku = Sku.from_json(sku.to_json()) temp_sku.associated_codes.append(bad_code) resp = self.client.post('/api/skus', json=temp_sku.to_dict()) assert resp.status_code == 400 assert resp.is_json assert resp.json['type'] == 'validation-error'
def test_update_sku(): state = InventoryStateMachine() v1 = state.new_sku(sku=Sku( associated_codes=[], id='SKU000000', name='', owned_codes=[], props={})) state.update_sku(patch={}, sku_id=v1) state.teardown()
def sku_batches_get(id): resp = Response() existing = Sku.from_mongodb_doc(db.sku.find_one({"_id": id})) if not existing: resp.status_code = 404 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "missing-resource", "title": "Can not get batches for a sku that does not exist.", "invalid-params": [{ "name": "id", "reason": "must be an exisiting sku id" }] }) return resp batches = [ Batch.from_mongodb_doc(bson).id for bson in db.batch.find({"sku_id": id}) ] resp.mimetype = "application/json" resp.data = json.dumps({"state": batches}) return resp
def sku_get(id): # detailed = request.args.get("details") == "true" sku = Sku.from_mongodb_doc(db.sku.find_one({"_id": id})) if sku is None: return problem.missing_bin_response(id) return SkuEndpoint.from_sku(sku).get_response()
def json_to_data_model(in_json_dict): if in_json_dict['id'].startswith("BIN"): return Bin.from_json(in_json_dict) if in_json_dict['id'].startswith("SKU"): return Sku.from_json(in_json_dict) if in_json_dict['id'].startswith("BAT"): return Batch.from_json(in_json_dict)
def sku_bins_get(id): resp = Response() existing = Sku.from_mongodb_doc(db.sku.find_one({"_id": id})) if not existing: resp.status_code = 404 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "missing-resource", "title": "Can not get locations of sku that does not exist.", "invalid-params": [{ "name": "id", "reason": "must be an exisiting sku id" }] }) return resp contained_by_bins = [ Bin.from_mongodb_doc(bson) for bson in db.bin.find({f"contents.{id}": { "$exists": True }}) ] locations = {bin.id: {id: bin.contents[id]} for bin in contained_by_bins} resp.status_code = 200 resp.mimetype = "application/json" resp.data = json.dumps({"state": locations}) return resp
def test_delete_sku(): state = InventoryStateMachine() v1 = state.new_sku(sku=Sku(associated_codes=[], id='SKU000000', name='', owned_codes=[], props=None)) state.delete_unused_sku(sku_id=v1) state.teardown()
def test_move_sku(data): state = InventoryStateMachine() v1 = state.new_bin(bin=Bin(contents={}, id='BIN000000', props=None)) v2 = state.new_bin(bin=Bin(contents={}, id='BIN000001', props=None)) v3 = state.new_sku(sku=Sku(id='SKU000000')) state.receive_sku(bin_id=v1, sku_id=v3, quantity=1) state.move(data=data, destination_binId=v2, source_binId=v1) state.get_existing_bin(bin_id=v1) state.get_existing_bin(bin_id=v2) state.teardown()
def test_delete_used_sku(): state = InventoryStateMachine() v1 = state.new_bin(bin=Bin(contents={}, id='BIN000000', props=None)) v2 = state.new_sku(sku=Sku(associated_codes=[], id='SKU000000', name='', owned_codes=[], props=None)) state.receive_sku(bin_id=v1, quantity=1, sku_id=v2) state.attempt_delete_used_sku(sku_id=v2) state.teardown()
def test_new_batch_bad_format_owned_codes(): state = InventoryStateMachine() v1 = state.new_sku(sku=Sku( associated_codes=[], id='SKU000000', name='', owned_codes=[], props={})) data = dst.DataProxy( Batch(associated_codes=[], id='BAT000000', name='', owned_codes=[], props={}, sku_id='SKU000000')) state.new_batch_bad_format_owned_codes(bad_code='', data=data, sku_id=v1) state.teardown()
def test_update_sku_batch(): state = InventoryStateMachine() v1 = state.new_sku(sku=Sku(associated_codes=[], id='SKU000001', name='', owned_codes=[], props=None)) v2 = state.new_sku(sku=Sku(associated_codes=[], id='SKU000002', name='', owned_codes=[], props=None)) # state.delete_missing_sku(sku_id='SKU000000') data = dst.DataProxy( Batch(associated_codes=[], id='BAT000000', owned_codes=[], props={0: 0}, sku_id='SKU000001')) v2 = state.new_batch_existing_sku(data=data, sku_id=v1) state.attempt_update_nonanonymous_batch_sku_id(batch_id=v2, patch={}, sku_id='SKU000002') state.teardown()
def test_update_batch_existing_sku(): state = InventoryStateMachine() v1 = state.new_sku(sku=Sku( associated_codes=[], id='SKU000000', name='', owned_codes=[], props={})) data = dst.DataProxy( Batch(associated_codes=[], id='BAT000000', name='', owned_codes=[], props={}, sku_id='SKU000000')) v2 = state.new_batch_existing_sku(data=data, sku_id=v1) state.update_batch(batch_id=v2, patch={}) state.teardown()
def test_add_sku_to_anonymous_batch(): state = InventoryStateMachine() v1 = state.new_sku(sku=Sku(associated_codes=[], id='SKU000000', name='', owned_codes=[], props=None)) v2 = state.new_anonymous_batch(batch=Batch(associated_codes=[], id='BAT000000', owned_codes=[], props=None, sku_id=None)) state.update_anonymous_batch_existing_sku_id(batch_id=v2, patch={}, sku_id=v1) state.teardown()
def skus_(draw, id=None, owned_codes=None, name=None, associated_codes=None, props=None): id = id or draw(label_("SKU")) owned_codes = owned_codes or draw(lists(text("abc", min_size=1))) associated_codes = associated_codes or draw(lists(text("abc", min_size=1))) name = name or draw(text("ABC")) props = props or draw(propertyDicts) return Sku(id=id, owned_codes=owned_codes, name=name, associated_codes=associated_codes, props=props)
def sku_delete(id): existing = Sku.from_mongodb_doc(db.sku.find_one({"_id": id})) resp = Response() resp.headers.add("Cache-Control", "no-cache") if existing is None: resp.status_code = 404 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "missing-resource", "title": "Can not delete sku that does not exist.", "invalid-params": [{ "name": "id", "reason": "must be an exisiting sku id" }] }) return resp num_contained_by_bins = db.bin.count_documents( {f"contents.{id}": { "$exists": True }}) if num_contained_by_bins > 0: resp.status_code = 403 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "resource-in-use", "title": "Can not delete sku that is being used. Try releasing all instances of this sku.", "invalid-params": { "name": "id", "reason": "must be an unused sku" } }) return resp db.sku.delete_one({"_id": existing.id}) resp.status_code = 204 return resp
def skus_post(): try: json = new_sku_schema(request.json) except MultipleInvalid as e: return problem.invalid_params_response(e) if db.sku.find_one({'_id': json['id']}): return problem.duplicate_resource_response("id") sku = Sku.from_json(json) admin_increment_code("SKU", sku.id) db.sku.insert_one(sku.to_mongodb_doc()) # dbSku = Sku.from_mongodb_doc(db.sku.find_one({'id': sku.id})) # Add text index if not yet created # TODO: This should probably be turned into a global flag if "name_text" not in db.sku.index_information().keys(): # print("Creating text index for sku#name") # was too noisy db.sku.create_index([("name", TEXT)]) return SkuEndpoint.from_sku(sku).created_success_response()
def search(): query = request.args['query'] limit = getIntArgs(request.args, "limit", 20) startingFrom = getIntArgs(request.args, "startingFrom", 0) resp = Response() results = [] # debug flags if query == '!ALL': results.extend([Sku.from_mongodb_doc(e) for e in db.sku.find()]) results.extend([Batch.from_mongodb_doc(e) for e in db.batch.find()]) results.extend([Bin.from_mongodb_doc(e) for e in db.bin.find()]) if query == '!BINS': results.extend([Bin.from_mongodb_doc(e) for e in db.bin.find()]) if query == '!SKUS': results.extend([Sku.from_mongodb_doc(e) for e in db.sku.find()]) if query == '!BATCHES': results.extend([Batch.from_mongodb_doc(e) for e in db.batch.find()]) # search by label if query.startswith('SKU'): results.append(Sku.from_mongodb_doc(db.sku.find_one({'_id': query}))) if query.startswith('BIN'): results.append(Bin.from_mongodb_doc(db.bin.find_one({'_id': query}))) if query.startswith('BAT'): results.append( Batch.from_mongodb_doc(db.batch.find_one({'_id': query}))) results = [result for result in results if result != None] # search for skus with owned_codes cursor = db.sku.find({"owned_codes": query}) for sku_doc in cursor: results.append(Sku.from_mongodb_doc(sku_doc)) # search for skus with associated codes cursor = db.sku.find({"associated_codes": query}) for sku_doc in cursor: results.append(Sku.from_mongodb_doc(sku_doc)) # search for skus with owned_codes cursor = db.batch.find({"owned_codes": query}) for batch_doc in cursor: results.append(Batch.from_mongodb_doc(batch_doc)) # search for batchs with associated codes cursor = db.batch.find({"associated_codes": query}) for batch_doc in cursor: results.append(Batch.from_mongodb_doc(batch_doc)) # if not DEV_ENV: # maybe use global flag + env variable instead. Shouldn't need to check this every time in production/ if "name_text" in db.sku.index_information().keys(): cursor = db.sku.find({"$text": {"$search": query}}) for sku_doc in cursor: results.append(Sku.from_mongodb_doc(sku_doc)) if "name_text" in db.batch.index_information().keys(): cursor = db.batch.find({"$text": {"$search": query}}) for batch_doc in cursor: results.append(Batch.from_mongodb_doc(batch_doc)) if results != []: paged = results[startingFrom:(startingFrom + limit)] resp.status_code = 200 resp.mimetype = "application/json" # TODO: Add next page / prev page operations resp.data = json.dumps( { 'state': { "total_num_results": len(results), "starting_from": startingFrom, "limit": limit, "returned_num_results": len(paged), "results": paged }, "operations": [] }, cls=Encoder) return resp resp.status_code = 200 resp.mimetype = "application/json" resp.data = json.dumps( { 'state': { "total_num_results": len(results), "starting_from": startingFrom, "limit": limit, "returned_num_results": 0, "results": [] }, "operations": [] }, cls=Encoder) return resp
def bin_contents_post(id): into_bin = Bin.from_mongodb_doc(db.bin.find_one({"_id": id})) item_id = request.json['id'] quantity = request.json['quantity'] resp = Response() resp.headers.add("Cache-Control", "no-cache") if not into_bin: resp.status_code = 404 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "missing-resource", "title": "Can not receive items into a bin that does not exist.", "invalid-params": [{ "name": "id", "reason": "must be an exisiting bin id" }] }) return resp if item_id.startswith("SKU"): exisiting_sku = Sku.from_mongodb_doc(db.sku.find_one({"_id": item_id})) if not exisiting_sku: resp.status_code = 409 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "missing-resource", "title": "Can not receive sku that does not exist.", "invalid-params": [{ "name": "item_id", "reason": "must be an exisiting batch or sku id" }] }) return resp else: db.bin.update_one({"_id": into_bin.id}, {"$inc": { f"contents.{item_id}": quantity }}) resp.status_code = 201 return resp elif item_id.startswith("BAT"): existing_batch = Batch.from_mongodb_doc( db.batch.find_one({"_id": item_id})) if not existing_batch: resp.status_code = 409 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "missing-resource", "title": "Can not receive batch that does not exist.", "invalid-params": [{ "name": "item_id", "reason": "must be an exisiting batch or sku id" }] }) return resp else: db.bin.update_one({"_id": into_bin.id}, {"$inc": { f"contents.{item_id}": quantity }}) resp.status_code = 201 return resp else: resp.status_code = 409 resp.mimetype = "application/problem+json" resp.data = json.dumps({ "type": "bad-id-format", "title": "Received item id must be a batch or sku.", "invalid-params": [{ "name": "item_id", "reason": "must be an exisiting batch or sku id" }] }) return resp
def get_existing_sku(self, sku_id): rp = self.client.get(f"/api/sku/{sku_id}") assert rp.status_code == 200 assert rp.is_json found_sku = Sku(**rp.json['state']) assert found_sku == self.model_skus[sku_id]