def update_purchase(id): """ Update the purchase with the given id. :param id: Is the purchase id. :return: A message that the update was successful and a list of all updated fields. :raises EntryNotFound: If the purchase with this ID does not exist. :raises EntryNotRevocable: An attempt is made to revoked a purchase whose product is not revocable. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises NothingHasChanged: If no change occurred after the update. :raises CouldNotUpdateEntry: If any other error occurs. """ # Check purchase purchase = Purchase.query.filter_by(id=id).first() if not purchase: raise exc.EntryNotFound() # Query the product product = Product.query.filter_by(id=purchase.product_id).first() data = json_body() updateable = {'revoked': bool, 'amount': int} check_forbidden(data, updateable, purchase) check_fields_and_types(data, None, updateable) updated_fields = [] # Handle purchase revoke if 'revoked' in data: # In case that the product is not revocable, an exception must be made. if not product.revocable: raise exc.EntryNotRevocable() if purchase.revoked == data['revoked']: raise exc.NothingHasChanged() purchase.toggle_revoke(revoked=data['revoked']) updated_fields.append('revoked') del data['revoked'] # Handle all other fields updated_fields = update_fields(data, purchase, updated=updated_fields) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({ 'message': 'Updated purchase.', 'updated_fields': updated_fields }), 201
def update_stocktakingcollection(admin, id): """ Update the stocktakingcollection with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the stocktakingcollection id. :return: A message that the update was successful. :raises EntryNotFound: If the stocktakingcollection with this ID does not exist. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises NothingHasChanged: If no change occurred after the update. :raises CouldNotUpdateEntry: If any other error occurs. """ # Check StocktakingCollection collection = (StocktakingCollection.query.filter_by(id=id).first()) if not collection: raise exc.EntryNotFound() data = json_body() if data == {}: raise exc.NothingHasChanged() updateable = {'revoked': bool} check_forbidden(data, updateable, collection) check_fields_and_types(data, None, updateable) updated_fields = [] # Handle revoke if 'revoked' in data: if collection.revoked == data['revoked']: raise exc.NothingHasChanged() collection.toggle_revoke(revoked=data['revoked'], admin_id=admin.id) del data['revoked'] updated_fields.append('revoked') # Handle all other fields updated_fields = update_fields(data, collection, updated_fields) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({ 'message': 'Updated stocktakingcollection.', 'updated_fields': updated_fields }), 201
def update_stocktaking(admin, id): """ Update the stocktaking with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the stocktaking id. :return: A message that the update was successful and a list of all updated fields. :raises EntryNotFound: If the stocktaking with this ID does not exist. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises NothingHasChanged: If no change occurred after the update. :raises CouldNotUpdateEntry: If any other error occurs. """ # Check Stocktaking stocktaking = Stocktaking.query.filter_by(id=id).first() if not stocktaking: raise exc.EntryNotFound() # Data validation data = json_body() updateable = {'count': int} check_forbidden(data, updateable, stocktaking) check_fields_and_types(data, None, updateable) updated_fields = [] message = 'Updated stocktaking.' # Check count if 'count' in data: if data['count'] < 0: raise exc.InvalidAmount() if data['count'] == stocktaking.count: raise exc.NothingHasChanged() # Handle all other fields updated_fields = update_fields(data, stocktaking, updated_fields) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({'message': message, 'updated_fields': updated_fields}), 201
def update_tag(admin, id): """ Update the tag with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the tag id. :return: A message that the update was successful and a list of all updated fields. :raises EntryNotFound: If the tag with this ID does not exist. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises CouldNotUpdateEntry: If any other error occurs. """ data = json_body() # Check, if the product exists. tag = Tag.query.filter_by(id=id).first() if not tag: raise exc.EntryNotFound() updateable = {'name': str} # Check forbidden fields check_forbidden(data, updateable, tag) # Check types check_fields_and_types(data, None, updateable) updated_fields = update_fields(data, tag) tag.created_by = admin.id # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({ 'message': 'Updated tag.', 'updated_fields': updated_fields }), 201
def update_replenishment(admin, id): """ Update the replenishment with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the replenishment id. :return: A message that the update was successful and a list of all updated fields. :raises EntryNotFound: If the replenishment with this ID does not exist. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises NothingHasChanged: If no change occurred after the update. :raises CouldNotUpdateEntry: If any other error occurs. """ # Check Replenishment repl = Replenishment.query.filter_by(id=id).first() if not repl: raise exc.EntryNotFound() # Get the corresponding ReplenishmentCollection replcoll = (ReplenishmentCollection.query.filter_by( id=repl.replcoll_id).first()) # Get all not revoked replenishments corresponding to the # replenishmentcollection before changes are made repls_nr = replcoll.replenishments.filter_by(revoked=False).all() # Data validation data = json_body() updateable = {'revoked': bool, 'amount': int, 'total_price': int} check_forbidden(data, updateable, repl) check_fields_and_types(data, None, updateable) updated_fields = [] message = 'Updated replenishment.' # Handle replenishment revoke if 'revoked' in data: if repl.revoked == data['revoked']: raise exc.NothingHasChanged() if not data['revoked'] and not repls_nr: replcoll.toggle_revoke(revoked=False, admin_id=admin.id) message = message + ( ' Rerevoked ReplenishmentCollection ID: {}'.format( replcoll.id)) repl.toggle_revoke(revoked=data['revoked'], admin_id=admin.id) del data['revoked'] updated_fields.append('revoked') # Handle all other fields updated_fields = update_fields(data, repl, updated_fields) # Check if ReplenishmentCollection still has unrevoked Replenishments repls = replcoll.replenishments.filter_by(revoked=False).all() if not repls and not replcoll.revoked: message = message + (' Revoked ReplenishmentCollection ID: {}'.format( replcoll.id)) replcoll.toggle_revoke(revoked=True, admin_id=admin.id) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({'message': message, 'updated_fields': updated_fields}), 201
def update_replenishmentcollection(admin, id): """ Update the replenishmentcollection with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the replenishmentcollection id. :return: A message that the update was successful. :raises EntryNotFound: If the replenishmentcollection with this ID does not exist. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises NothingHasChanged: If no change occurred after the update. :raises CouldNotUpdateEntry: If any other error occurs. :raises EntryNotRevocable: If the replenishmentcollections was revoked by by replenishment_update, because all replenishments are revoked, the revoked field can not be set to true. """ # Check ReplenishmentCollection replcoll = (ReplenishmentCollection.query.filter_by(id=id).first()) if not replcoll: raise exc.EntryNotFound() # Which replenishments are not revoked? repls = replcoll.replenishments.filter_by(revoked=False).all() data = json_body() if data == {}: raise exc.NothingHasChanged() updateable = {'revoked': bool, 'comment': str, 'timestamp': int} check_forbidden(data, updateable, replcoll) check_fields_and_types(data, None, updateable) updated_fields = [] # Handle replenishmentcollection revoke if 'revoked' in data: if replcoll.revoked == data['revoked']: raise exc.NothingHasChanged() # Check if the revoke was caused through the replenishment_update and # therefor cant be changed if not data['revoked'] and not repls: raise exc.EntryNotRevocable() replcoll.toggle_revoke(revoked=data['revoked'], admin_id=admin.id) del data['revoked'] updated_fields.append('revoked') # Handle new timestamp if 'timestamp' in data: try: timestamp = datetime.datetime.fromtimestamp(data['timestamp']) assert timestamp <= datetime.datetime.now() replcoll.timestamp = timestamp updated_fields.append('revoked') except (AssertionError, TypeError, ValueError, OSError, OverflowError): """ AssertionError: The timestamp lies in the future. TypeError: Invalid type for conversion. ValueError: Timestamp is out of valid range. OSError: Value exceeds the data type. OverflowError: Timestamp out of range for platform time_t. """ raise exc.InvalidData() del data['timestamp'] # Handle all other fields updated_fields = update_fields(data, replcoll, updated_fields) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({ 'message': 'Updated replenishmentcollection.', 'updated_fields': updated_fields }), 201
def update_product(admin, id): """ Update the product with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the product id. :return: A message that the update was successful and a list of all updated fields. :raises EntryNotFound: If the product with this ID does not exist. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises EntryNotFound: If the image is to be changed but no image with this name exists. :raises CouldNotUpdateEntry: If any other error occurs. """ data = json_body() # Check, if the product exists. product = Product.query.filter_by(id=id).first() if not product: raise exc.EntryNotFound() optional = { 'name': str, 'price': int, 'barcode': str, 'imagename': str, 'countable': bool, 'revocable': bool } # Check forbidden fields check_forbidden(data, optional, product) # Check types check_fields_and_types(data, None, optional) updated_fields = [] # Check for price change if 'price' in data: price = int(data['price']) del data['price'] if price != product.price: product.set_price(price=price, admin_id=admin.id) updated_fields.append('price') # Check for barcode change if 'barcode' in data: if Product.query.filter_by(barcode=data['barcode']).first(): raise exc.EntryAlreadyExists() # Check for image change. if 'imagename' in data: imagename = data['imagename'] del data['imagename'] if imagename != product.imagename: upload = Upload.query.filter_by(filename=imagename).first() if not upload: raise exc.EntryNotFound() product.image_upload_id = upload.id updated_fields.append('imagename') # Update all other fields updated_fields = update_fields(data, product, updated=updated_fields) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({ 'message': 'Updated product.', 'updated_fields': updated_fields }), 201
def update_user(admin, id): """ Update the user with the given id. :param admin: Is the administrator user, determined by @adminRequired. :param id: Is the user id. :return: A message that the update was successful and a list of all updated fields. :raises EntryNotFound: If the user with this ID does not exist. :raises UserIsNotVerified: If the user has not yet been verified. :raises ForbiddenField: If a forbidden field is in the request data. :raises UnknownField: If an unknown parameter exists in the request data. :raises InvalidType: If one or more parameters have an invalid type. :raises PasswordsDoNotMatch: If the password and its repetition do not match. :raises DataIsMissing: If the password is to be updated but no repetition of the password exists in the request. """ data = json_body() # Query user user = User.query.filter(User.id == id).first() if not user: raise exc.EntryNotFound() # Raise an exception if the user has not been verified yet. if not user.is_verified: raise exc.UserIsNotVerified() allowed = { 'firstname': str, 'lastname': str, 'password': str, 'password_repeat': str, 'is_admin': bool, 'rank_id': int } # Check the data for forbidden fields. check_forbidden(data, allowed, user) # Check all allowed fields and for their types. check_fields_and_types(data, None, allowed) updated_fields = [] # Update admin role if 'is_admin' in data: user.set_admin(is_admin=data['is_admin'], admin_id=admin.id) if not user.is_admin: users = User.query.all() admins = list(filter(lambda x: x.is_admin, users)) if not admins: raise exc.NoRemainingAdmin() updated_fields.append('is_admin') del data['is_admin'] # Update rank if 'rank_id' in data: user.set_rank_id(rank_id=data['rank_id'], admin_id=admin.id) updated_fields.append('rank_id') del data['rank_id'] # Check password if 'password' in data: if 'password_repeat' in data: password = data['password'].strip() password_repeat = data['password_repeat'].strip() if password != password_repeat: raise exc.PasswordsDoNotMatch() if len(password) < app.config['MINIMUM_PASSWORD_LENGTH']: raise exc.PasswordTooShort() user.password = bcrypt.generate_password_hash(password) updated_fields.append('password') del data['password_repeat'] else: raise exc.DataIsMissing() del data['password'] # All other fields updateable = ['firstname', 'lastname'] check_forbidden(data, updateable, user) updated_fields = update_fields(data, user, updated=updated_fields) # Apply changes try: db.session.commit() except IntegrityError: raise exc.CouldNotUpdateEntry() return jsonify({ 'message': 'Updated user.', 'updated_fields': updated_fields }), 201