def recv_cancel():

    try:
        recv_id = request.args[0]
    except:
        redirect(URL(f="recv"))

    rtable = s3db.inv_recv
    if not auth.s3_has_permission("delete", rtable, record_id=recv_id):
        session.error = T("You do not have permission to cancel this received shipment.")
        redirect(URL(c="inv", f="recv", args=[recv_id]))

    recv_record = db(rtable.id == recv_id).select(rtable.status,
                                                  limitby=(0, 1)).first()

    inv_ship_status = s3db.inv_ship_status
    if recv_record.status != inv_ship_status["RECEIVED"]:
        session.error = T("This shipment has not been received - it has NOT been canceled because it can still be edited.")
        redirect(URL(c="inv", f="recv", args=[recv_id]))

    stable = s3db.inv_send
    tracktable = s3db.inv_track_item
    inv_item_table = s3db.inv_inv_item
    ritable = s3db.req_req_item
    siptable = s3db.supply_item_pack

    # Go through each item in the shipment remove them from the site store
    # and put them back in the track item record
    query = (tracktable.recv_id == recv_id) & \
            (tracktable.deleted == False)
    recv_items = db(query).select(tracktable.recv_inv_item_id,
                                  tracktable.recv_quantity,
                                  tracktable.send_id,
                                  )
    send_id = None
    for recv_item in recv_items:
        inv_item_id = recv_item.recv_inv_item_id
        # This assumes that the inv_item has the quantity
        quantity = inv_item_table.quantity - recv_item.recv_quantity
        if quantity == 0:
            db(inv_item_table.id == inv_item_id).delete()
        else:
            db(inv_item_table.id == inv_item_id).update(quantity = quantity)
        db(tracktable.recv_id == recv_id).update(status = 2) # In transit
        # @todo potential problem in that the send id should be the same for all track items but is not explicitly checked
        if send_id is None and recv_item.send_id is not None:
            send_id = recv_item.send_id
    track_rows = db(tracktable.recv_id == recv_id).select(tracktable.req_item_id,
                                                          tracktable.item_pack_id,
                                                          tracktable.recv_quantity,
                                                          )
    for track_item in track_rows:
        # If this is linked to a request
        # then remove these items from the quantity in fulfil
        if track_item.req_item_id:
            req_id = track_item.req_item_id
            req_item = db(ritable.id == req_id).select(ritable.quantity_fulfil,
                                                       ritable.item_pack_id,
                                                       limitby=(0, 1)).first()
            req_quantity = req_item.quantity_fulfil
            # @ToDo: Optimise by reading these 2 in a single DB query
            req_pack_quantity = db(siptable.id == req_item.item_pack_id).select(siptable.quantity,
                                                                                limitby=(0, 1)
                                                                                ).first().quantity
            track_pack_quantity = db(siptable.id == track_item.item_pack_id).select(siptable.quantity,
                                                                                    limitby=(0, 1)
                                                                                    ).first().quantity
            quantity_fulfil = s3db.supply_item_add(req_quantity,
                                                   req_pack_quantity,
                                                   - track_item.recv_quantity,
                                                   track_pack_quantity
                                                  )
            db(ritable.id == req_id).update(quantity_fulfil = quantity_fulfil)
            s3db.req_update_status(req_id)
    # Now set the recv record to cancelled and the send record to sent
    db(rtable.id == recv_id).update(date = request.utcnow,
                                    status = inv_ship_status["CANCEL"],
                                    owned_by_user = None,
                                    owned_by_group = ADMIN)
    if send_id != None:
        # The sent record is now set back to SENT so the source warehouse can
        # now cancel this record to get the stock back into their warehouse.
        # IMPORTANT reports need to locate this record otherwise it can be
        # a mechanism to circumvent the auditing of stock
        db(stable.id == send_id).update(status = inv_ship_status["SENT"],
                                        owned_by_user = None,
                                        owned_by_group = ADMIN)
    redirect(URL(c="inv", f="recv",
                 args=[recv_id]))

# =============================================================================
Cancel a Received Shipment
dataset/ETHPy150Open sahana/eden/controllers/inv.py/recv_cancel