diff --git a/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/borrow_checkout.html b/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/borrow_checkout.html
index bdfa05c11b4cb2e7379167eb7c30173537be3f2a..f183fb0ca89dffddc57bab612d52465eac2896b8 100644
--- a/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/borrow_checkout.html
+++ b/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/borrow_checkout.html
@@ -2,10 +2,10 @@
 <html>
   <body>
     <div id="caosdb-form">
-      <div class="row" id="checkout-form-{containerid}" style="margin:0px">
+      <div class="row" id="checkout-form-{boxid}" style="margin:0px">
         <div class="col-lg-12">
-        <h2>Borrow Container</h2>
-        <form class="caosdb-container-checkout-form" autocomplete="on">
+        <h2>Borrow Box</h2>
+        <form class="caosdb-awi-box-checkout-form" autocomplete="on">
           <div>
             <h5>Please enter your full name and your email address. If you are doing this for the first time, a new user record will be created.</h5>
           </div>
@@ -40,24 +40,28 @@
                 </label>
               </div>
             </div>
+            <div class="col-sm-4">
+              <div class="form-group">
+                <label>Destination:
+                  <input id="loan-destination" required="required"/>
+                </label>
+              </div>
+            </div>
           </div>
           <div class="row caosdb-form-row">
             <div class="col-sm-12">
               <div class="form-group">
-                <div class="row" style="margin:0px">
-                  <label for="loan-comment" style="margin-bottom:0px">Purpose:</label>
-                </div>
-                <div class="row" style="margin:0px">
+                  <label for="loan-comment" style="margin-bottom:0px">Purpose:
                   <textarea id="loan-comment" class="form-control" rows="4" style="width:100%"
                             placeholder="Please indicate the purpose of the loan.">{purpose}</textarea>
-                </div>
+                  </label>
               </div>
             </div>
           </div>
           <div class="row caosdb-form-row">
             <div class="col-sm-12">
               <div class="form-check">
-                <label class="form-check-label">I am going to completely exhaust the contents of this container.
+                <label class="form-check-label">Are you going to completely exhaust the contents of this box?
                   <input type="checkbox" class="form-check-input" id="exhaust-contents" value="no" />
                 </label>
               </div>
diff --git a/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/return_box.html b/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/return_box.html
index c14a2984c0b4d106b1d804068edc74c92f26cd77..df49499263824210cc027e3b1980b84c30d00dc1 100644
--- a/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/return_box.html
+++ b/caosdb-server/caosdb-webui/src/ext/html/forms/loan-forms/return_box.html
@@ -2,10 +2,10 @@
 <html>
   <body>
     <div id="caosdb-form">
-      <div class="row" id="caosdb-return-form-{containerid}" style="margin:0px">
+      <div class="row" id="caosdb-return-form-{boxid}" style="margin:0px">
         <div class="col-lg-12">
-        <h2>Return Container</h2>
-        <form class="caosdb-container-return-form" autocomplete="on">
+        <h2>Return Box</h2>
+        <form class="caosdb-awi-box-return-form" autocomplete="on">
           <div>
             <h5>Please enter your full name and your email address. If you are doing this for the first time, a new user record will be created.</h5>
           </div>
@@ -40,6 +40,13 @@
                 </label>
               </div>
             </div>
+            <div class="col-sm-4">
+              <div class="form-group">
+                <label>Destination:
+                  <input name="location" type="text" class="form-control" id="current-location" required="required" value="{currentlocation}" />
+                </label>
+              </div>
+            </div>
           </div>
           <div class="row caosdb-form-row">
             <div class="col-sm-12">
@@ -49,7 +56,7 @@
                 </div>
                 <div class="row" style="margin:0px">
                   <textarea id="loan-comment" class="form-control" rows="4" style="width:100%"
-                            placeholder="Please insert what the container currently contains.">{new_content}</textarea>
+                            placeholder="Please insert what the box currently contains.">{new_content}</textarea>
                 </div>
               </div>
             </div>
diff --git a/caosdb-server/caosdb-webui/src/ext/js/box_loan.js b/caosdb-server/caosdb-webui/src/ext/js/box_loan.js
index 73494a0d06cf48a61c08e3829d51b7b6319e06ab..4f567a92a993e7343aabcdf98a157417b2c780b8 100644
--- a/caosdb-server/caosdb-webui/src/ext/js/box_loan.js
+++ b/caosdb-server/caosdb-webui/src/ext/js/box_loan.js
@@ -8,49 +8,38 @@ function get_formatted_date(split) {
     return ((new Date(Date.now() - tzoffset)).toISOString()).split(split)[0];
 }
 
-/**
- * This function retrieves an html form from the html subdirectory.
- *
- */
-var getHTMLForm = async function (pageName, variables) {
-    var site = await connection.get("webinterface/html/forms/" + pageName + ".html", "html");
-    var htmltext = site.getElementById("caosdb-form").innerHTML;
-    var req = /\{([0-9a-z-A-Z_]+)\}/g;
-    return htmltext.replace(req, (match, p1) => {
-        return variables[p1] || "";
-    });
-}
+
 
 /**
- * GEOMAR loan management, copied and adapted from AWI box-management code.
+ * AWI Box Loan, refactored code.
  */
-var loan_management = function () {
+var awi_box_loan = function () {
 
-    var logger = log.getLogger("loan_management");
+    var logger = log.getLogger("awi_box_loan");
 
     var datamodel = {
         loan: "Loan",
-        container: "Container",
+        box: "Box",
         returned: "returned",
     }
 
-    const _dismiss_button = '<button class="btn btn-secondary container-loan-btn">OK</button>'
+    const _dismiss_button = '<button class="btn btn-secondary box-loan-btn">OK</button>'
     const _server_did_not_respond = "The server did not respond. Please reload the page.";
-    const _return_container_button = '<a title="Return Container." class="btn btn-link container-loan-btn">Return Container</a>';
-    const _borrow_container_button = '<a title="Borrow Container." class="btn btn-link container-loan-btn">Borrow Container</a>';
-    const _confirm_loan_button = '<a title="Confirm Loan." class="btn btn-link container-loan-btn">Confirm Loan</a>';
-    const _manual_return_button = '<a title="Manual Return." class="btn btn-link container-loan-btn">Manual Return</a>';
-    const _accept_return_button = '<a title="Accept Return" class="btn btn-link container-loan-btn">Accept Return</a>';
-    const _reject_return_button = '<a title="Reject Return." class="btn btn-link container-loan-btn">Reject Return</a>';
-    const _accept_loan_button = '<a title="Accept Borrow Request." class="btn btn-link container-loan-btn">Accept Loan Request</a>';
-    const _container_update_alert = `
+    const _return_box_button = '<a title="Return Box." class="btn btn-link box-loan-btn">Return Box</a>';
+    const _borrow_box_button = '<a title="Borrow Box." class="btn btn-link box-loan-btn">Borrow Box</a>';
+    const _confirm_loan_button = '<a title="Confirm Loan." class="btn btn-link box-loan-btn">Confirm Loan</a>';
+    const _manual_return_button = '<a title="Manual Return." class="btn btn-link box-loan-btn">Manual Return</a>';
+    const _accept_return_button = '<a title="Accept Return" class="btn btn-link box-loan-btn">Accept Return</a>';
+    const _reject_return_button = '<a title="Reject Return." class="btn btn-link box-loan-btn">Reject Return</a>';
+    const _accept_loan_button = '<a title="Accept Borrow Request." class="btn btn-link box-loan-btn">Accept Loan Request</a>';
+    const _box_update_alert = `
         <div class="alert alert-danger alert-dismissible" role="alert">
-            <h4>Update the Container</h4>
+            <h4>Update the Box</h4>
             <p>
-                Are you sure that the container record is up-to-date (references etc.)?<br>Possibly have a look at the notes in the loan by clicking on the "References" button.<br> Do you  you want to apply further changes?
+                Are you sure that the box record is up-to-date (references etc.)?<br>Possibly have a look at the notes in the loan by clicking on the "References" button.<br> Do you  you want to apply further changes?
             </p><p>
-            <button type="button" class="btn btn-danger caosdb-f-manual-return-cancel">Cancel and change the container manually</button>
-            <button type="button" class="btn btn-secondary caosdb-f-manual-return-proceed">The container is up-to-date.</button>
+            <button type="button" class="btn btn-danger caosdb-f-manual-return-cancel">Cancel and change the box manually</button>
+            <button type="button" class="btn btn-secondary caosdb-f-manual-return-proceed">The box is up-to-date.</button>
         </p>
         </div>
     `;
@@ -68,10 +57,10 @@ var loan_management = function () {
     }
 
     /**
-     * Return the actions panel of a container entity.
+     * Return the actions panel of a box entity.
      */
-    var get_actions_panel = function (container) {
-        return $(container).find('.caosdb-entity-actions-panel');
+    var get_actions_panel = function (box) {
+        return $(box).find('.caosdb-entity-actions-panel');
     }
 
     /**
@@ -125,22 +114,22 @@ var loan_management = function () {
 
 
     /**
-     * Query for a Loan entity which references the container and which has no
+     * Query for a Loan entity which references the box and which has no
      * `returned` property.
      */
-    var get_active_loans = async function (container) {
-        return await query(`FIND ${datamodel.loan} WITH ${datamodel.container} -> ${container.id} AND WHICH DOES NOT HAVE A ${datamodel.returned}`);
+    var get_active_loans = async function (box) {
+        return await query(`FIND ${datamodel.loan} WITH ${datamodel.box} -> ${box.id} AND WHICH DOES NOT HAVE A ${datamodel.returned}`);
     }
 
     /**
-     * Returns detailed information about the loan state of this container:
+     * Returns detailed information about the loan state of this box:
      */
-    var get_loan_state = async function (container) {
+    var get_loan_state = async function (box) {
         const loan_state = {
             loan: undefined,
             state: undefined,
         };
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
         if (typeof loan === "undefined") {
             // no loan found
             return loan_state;
@@ -170,7 +159,7 @@ var loan_management = function () {
         }
     }
 
-    var show_result = function (container, result, container) {
+    var show_result = function (container, result, box) {
         const dismissable = $('<div/>');
         const restore = $(container).children();
         restore.hide();
@@ -196,7 +185,7 @@ var loan_management = function () {
         dismiss_btn.click(function () {
             dismissable.remove();
             restore.show();
-            init(container);
+            init(box);
         });
         dismissable.append(dismiss_btn);
     }
@@ -208,12 +197,17 @@ var loan_management = function () {
         const last_name = $(form).find("#last-name").val();
         const comment = $(form).find("#loan-comment").val();
         const expected_return_date = $(form).find("#expected-return").val();
+        const current_location = $(form).find("[name='location']").val();
+        const destination = $(form).find("[name='destination']").val();
         const exhaust_contents = $(form).find("#exhaust-contents").prop("checked");
 
         window.localStorage["borrower_email"] = email;
         window.localStorage["borrower_first_name"] = first_name;
         window.localStorage["borrower_last_name"] = last_name;
         window.localStorage["borrower_return_date"] = expected_return_date
+        if (destination) {
+            window.localStorage["borrower_destination"] = destination;
+        }
 
         return {
             email: email,
@@ -221,18 +215,20 @@ var loan_management = function () {
             last_name: last_name,
             comment: comment,
             expected_return_date: expected_return_date,
+            current_location: current_location,
             exhaust_contents: exhaust_contents,
+            destination: destination
         };
     }
 
 
     /**
-     * Generate a borrow function for a container.
-     * This function can also be used to assign values to multiple containers.
+     * Generate a borrow function for a box.
+     * This function can also be used to assign values to multiple boxes.
      */
-    var borrow_function = async function (form, container) {
+    var borrow_function = async function (form, box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
         $(form).hide()
 
@@ -240,35 +236,72 @@ var loan_management = function () {
 
 
         $.extend(loan_request, {
-            container: getEntityID(container),
+            box: getEntityID(box),
         });
 
         const result = await run_script("loan_management/request_loan.py", loan_request);
         $(wait).remove();
         $(form).remove();
-        show_result(actions_panel, result, container);
+        show_result(actions_panel, result, box);
     }
 
-    var _add_form = async function (container, form_generator, submit) {
-        const form = $(await form_generator(container));
-        form.insertAfter($(container).find('.caosdb-entity-actions-panel')).hide();
+    var _add_form = async function (box, form_generator, submit_callback) {
+        const form = $(await form_generator(box));
+        form.insertAfter($(box).find('.caosdb-entity-actions-panel')).hide();
         form.submit(() => {
-            submit(form[0], container);
+            submit_callback(form[0], box);
             return false;
         });
+
+        form.find("label").has(":required").prepend('<span style="font-size: 10px; color: red; margin-right: 4px; font-weight: 100;">*</span>');
+
+        // the footer adds the default styling as well as the *required-marker
+        const submit = form.find(":input[type='submit']")[0];
+        const footer = form_elements.make_footer();
+        footer.append(submit);
+        form.find("form").append(footer);
+
         return form[0];
     }
 
+    var _init_validator = function (form) {
+        // initiate validator
+        // Workaround for missing checkValidity function:
+        if (form.checkValidity == undefined) {
+            form.checkValidity = () => true;
+        }
+        if (form.reportValidity == undefined) {
+            form.reportValidity = () => logger.debug("Workaround for validity report");
+        }
+        form_elements.init_validator(form);
+        const submit = $(form).find(":input[type='submit']")[0];
+        form_elements.toggle_submit_button_form_valid(form, submit);
+    }
+
     /**
-     * Add Return button to containers' actions panels.
+     * Add Return button to boxes' actions panels.
      */
-    var add_return_button = async function (container) {
-        const but = $(_return_container_button);
-
-        get_actions_panel(container).append(but);
-        const form = await _add_form(container, generate_return_form, return_function);
+    var add_return_button = async function (box) {
+        const but = $(_return_box_button);
+
+        get_actions_panel(box).append(but);
+
+        const config = {
+            type: "reference_drop_down",
+            name: "location",
+            label: "",
+            required: true,
+            query: "FIND Record Location",
+            make_desc: getEntityName,
+        }
+        const dd = form_elements.make_form_field(config);
+        const form = await _add_form(box, generate_return_form, return_function);
+        $(dd).find(".col-sm-9").removeClass("col-sm-9");
+        $(dd).find(".col-sm-3").removeClass("col-sm-3");
+        $(form).find("#current-location").replaceWith(dd);
         $(form).find("label").css("display", "block");
 
+        _init_validator(form);
 
         but.click(() => {
             but.remove();
@@ -280,14 +313,14 @@ var loan_management = function () {
      * If the user is administrator (or a data curator) a button is added
      * to accept the borrow request. Else a message is added "pending loan request".
      */
-    var add_borrow_accept_button = function (container, loan) {
-        const actionPanel = get_actions_panel(container);
+    var add_borrow_accept_button = function (box, loan) {
+        const actionPanel = get_actions_panel(box);
         if (userIsAdministrator() === true || userHasRole("curator") === true) {
             const but = $(_accept_loan_button);
 
             but.click(() => {
                 but.remove();
-                accept_loan_function(container);
+                accept_loan_function(box);
             });
             actionPanel.append(but);
         } else {
@@ -299,21 +332,35 @@ var loan_management = function () {
         const loan_id = getEntityID(loan);
         const href = `${connection.getBasePath()}Entity/${loan_id}`;
         const title = "Open loan entity.";
-        const classes = "btn btn-link container-loan-btn";
+        const classes = "btn btn-link box-loan-btn";
         return `<a title="${title}" class="${classes}"
                 href="${href}">${text}<a>`;
     }
 
     /**
-     * Add Borrow buttons to the containers' action panels
+     * Add Borrow buttons to the boxes' action panels
      */
-    var add_borrow_button = async function (container) {
-        const but = $(_borrow_container_button);
-        get_actions_panel(container).append(but);
-
-        const form = await _add_form(container, generate_form_borrow_checkout, borrow_function);
+    var add_borrow_button = async function (box) {
+        const but = $(_borrow_box_button);
+        get_actions_panel(box).append(but);
+
+        const config = {
+            type: "reference_drop_down",
+            name: "destination",
+            label: "",
+            required: true,
+            query: "FIND Record Location",
+            make_desc: getEntityName,
+        }
+        const dd = form_elements.make_form_field(config);
+        const form = await _add_form(box, generate_form_borrow_checkout, borrow_function);
+        $(dd).find(".col-sm-9").removeClass("col-sm-9");
+        $(dd).find(".col-sm-3").removeClass("col-sm-3");
+        $(form).find("#loan-destination").replaceWith(dd);
         $(form).find("label").css("display", "block");
 
+        _init_validator(form);
+
         but.click(() => {
             but.remove();
             $(form).toggle()
@@ -321,29 +368,19 @@ var loan_management = function () {
     }
 
 
-    var _get_label_or_id = function (container) {
-        const bn = getProperty(container, "recommendedLabel", case_sensitive = false);
-        if (bn === undefined) {
-            // ID as fallback
-            return getEntityID(container);
-        }
-        return bn;
-
-    }
-
-    var open_accept_loan_mail = async function (loan, container) {
+    var open_accept_loan_mail = async function (loan, box) {
         try {
-            const borrower = (await retrieve(getProperty(loan, "borrower"), case_sensitive = false))[0];
+            const borrower = (await retrieve(getProperty(loan, "Borrower"), case_sensitive = false))[0];
 
             const email = getProperty(borrower, "email", case_sensitive = false);
             const firstName = getProperty(borrower, "firstName", case_sensitive = false);
             const lastName = getProperty(borrower, "lastName", case_sensitive = false);
-            const bn = _get_label_or_id(container);
+            const bn = getProperty(box, "Number", case_sensitive = false);
             const date = getProperty(loan, "expectedReturn", case_sensitive = false);
 
-            const subject = `Loan Request for Container ${bn} accepted`;
+            const subject = `Loan Request for Box ${bn} accepted`;
             const body = `Dear ${firstName} ${lastName}, %0D%0D` +
-                `You can pickup container ${bn} on ${date}. %0D%0D` +
+                `You can pickup box number ${bn} on ${date}. %0D%0D` +
                 `Kind Regards,%0D%0D ${getUserName()}`;
             open_mail_generic(email, subject, body)
         } catch (err) {
@@ -352,13 +389,12 @@ var loan_management = function () {
     }
 
 
-    var accept_loan_function = async function (container) {
-
+    var accept_loan_function = async function (box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
 
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
 
         const accept_loan_request = {
             loan: getEntityID(loan),
@@ -366,18 +402,17 @@ var loan_management = function () {
 
         const result = await run_script("loan_management/accept_loan_request.py", accept_loan_request);
         $(wait).remove();
-        show_result(actions_panel, result, container);
-
-        open_accept_loan_mail(loan, container);
+        show_result(actions_panel, result, box);
 
+        open_accept_loan_mail(loan, box);
     }
 
-    var manual_return_function = async function (container) {
+    var manual_return_function = async function (box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
 
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
 
         const manual_return_request = {
             loan: getEntityID(loan),
@@ -385,36 +420,36 @@ var loan_management = function () {
 
         const result = await run_script("loan_management/manual_return.py", manual_return_request);
         $(wait).remove();
-        show_result(actions_panel, result, container);
+        show_result(actions_panel, result, box);
     }
 
     /**
-     * Add Manual Return button to containers' actions panels.
+     * Add Manual Return button to boxes' actions panels.
      */
-    var add_manual_return_button = function (container, loan) {
-        const actionPanel = get_actions_panel(container);
+    var add_manual_return_button = function (box, loan) {
+        const actionPanel = get_actions_panel(box);
         if (userIsAdministrator() === true || userHasRole("curator") === true) {
             const but = $(_manual_return_button);
             actionPanel.append(but);
 
-            const container_update_alert = $(_container_update_alert);
-            container_update_alert.find(".caosdb-f-manual-return-cancel").click(() => {
+            const box_update_alert = $(_box_update_alert);
+            box_update_alert.find(".caosdb-f-manual-return-cancel").click(() => {
                 but.show();
-                container_update_alert.hide();
+                box_update_alert.hide();
             });
 
-            container_update_alert.find(".caosdb-f-manual-return-proceed").click(() => {
+            box_update_alert.find(".caosdb-f-manual-return-proceed").click(() => {
                 but.remove();
-                container_update_alert.remove();
-                manual_return_function(container);
+                box_update_alert.remove();
+                manual_return_function(box);
             });
 
-            actionPanel.append(container_update_alert);
-            container_update_alert.hide();
+            actionPanel.append(box_update_alert);
+            box_update_alert.hide();
 
             but.click(() => {
                 but.hide();
-                container_update_alert.show();
+                box_update_alert.show();
             });
         } else {
             actionPanel.append($(create_link_to_loan(loan, "Pending return.")));
@@ -422,12 +457,12 @@ var loan_management = function () {
     }
 
 
-    var confirm_loan_function = async function (container) {
+    var confirm_loan_function = async function (box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
 
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
 
         const confirm_loan_request = {
             loan: getEntityID(loan),
@@ -435,21 +470,22 @@ var loan_management = function () {
 
         const result = await run_script("loan_management/confirm_loan.py", confirm_loan_request);
         $(wait).remove();
-        show_result(actions_panel, result, container);
+        show_result(actions_panel, result, box);
     }
 
 
-    var open_reject_return_mail = async function (loan, container) {
+    var open_reject_return_mail = async function (loan, box) {
         try {
-            const borrower = (await retrieve(getProperty(loan, "borrower"), case_sensitive = false))[0];
+            const borrower = (await retrieve(getProperty(loan, "Borrower"), case_sensitive = false))[0];
 
             const email = getProperty(borrower, "email", case_sensitive = false);
             const firstName = getProperty(borrower, "firstName", case_sensitive = false);
             const lastName = getProperty(borrower, "lastName", case_sensitive = false);
-            const bn = _get_label_or_id(container);
-            const subject = `Return Request for Container ${bn} rejected`;
+            const bn = getProperty(box, "Number", case_sensitive = false);
+
+            const subject = `Return Request for Box ${bn} rejected`;
             const body = `Dear ${firstName} ${lastName}, %0D%0D` +
-                `your return request for container ${bn} cannot be accepted.` +
+                `your return request for box number ${bn} cannot be accepted.` +
                 `Kind Regards,%0D ${getUserName()}`;
             open_mail_generic(email, subject, body)
         } catch (err) {
@@ -458,18 +494,18 @@ var loan_management = function () {
     }
 
 
-    var open_accept_return_mail = async function (loan, container) {
+    var open_accept_return_mail = async function (loan, box) {
         try {
-            const borrower = (await retrieve(getProperty(loan, "borrower"), case_sensitive = false))[0];
+            const borrower = (await retrieve(getProperty(loan, "Borrower"), case_sensitive = false))[0];
 
             const email = getProperty(borrower, "email", case_sensitive = false);
             const firstName = getProperty(borrower, "firstName", case_sensitive = false);
             const lastName = getProperty(borrower, "lastName", case_sensitive = false);
-            const bn = _get_label_or_id(container);
+            const bn = getProperty(box, "Number", case_sensitive = false);
             const date = getProperty(loan, "expectedReturn", case_sensitive = false);
-            const subject = `Return Request for Container ${bn} accepted`;
+            const subject = `Return Request for Box ${bn} accepted`;
             const body = `Dear ${firstName} ${lastName}, %0D%0D` +
-                `please return container ${bn} on ${date}. %0D%0D` +
+                `please return box number ${bn} on ${date}. %0D%0D` +
                 `Kind Regards,%0D ${getUserName()}`;
             open_mail_generic(email, subject, body)
         } catch (err) {
@@ -478,12 +514,12 @@ var loan_management = function () {
     }
 
 
-    var accept_return_function = async function (container) {
+    var accept_return_function = async function (box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
 
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
 
         const accept_return_request = {
             loan: getEntityID(loan),
@@ -491,18 +527,18 @@ var loan_management = function () {
 
         const result = await run_script("loan_management/accept_return_request.py", accept_return_request);
         $(wait).remove();
-        show_result(actions_panel, result, container);
+        show_result(actions_panel, result, box);
 
-        open_accept_return_mail(loan, container);
+        open_accept_return_mail(loan, box);
     }
 
 
-    var reject_return_function = async function (container) {
+    var reject_return_function = async function (box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
 
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
 
         const reject_return_request = {
             loan: getEntityID(loan),
@@ -512,17 +548,17 @@ var loan_management = function () {
             "loan_management/reject_return_request.py",
             reject_return_request);
         $(wait).remove();
-        show_result(actions_panel, result, container);
+        show_result(actions_panel, result, box);
 
-        open_reject_return_mail(loan, container);
+        open_reject_return_mail(loan, box);
     }
 
 
     /**
      * Add two buttons for confirming or rejecting a return request.
      */
-    var add_confirm_reject_return = function (container, loan) {
-        const actionPanel = get_actions_panel(container);
+    var add_confirm_reject_return = function (box, loan) {
+        const actionPanel = get_actions_panel(box);
         if (userIsAdministrator() === true || userHasRole("curator") === true) {
             const confirmButton = $(_accept_return_button);
             actionPanel.append(confirmButton);
@@ -533,13 +569,13 @@ var loan_management = function () {
             confirmButton.click(() => {
                 confirmButton.remove();
                 rejectButton.remove();
-                accept_return_function(container);
+                accept_return_function(box);
             });
 
             rejectButton.click(() => {
                 confirmButton.remove();
                 rejectButton.remove();
-                reject_return_function(container);
+                reject_return_function(box);
             });
         } else {
             actionPanel.append($(create_link_to_loan(loan, "Pending return request.")));
@@ -549,51 +585,51 @@ var loan_management = function () {
     /**
      * Add a button for confirming the loan.
      */
-    var add_confirm_loan_button = function (container, loan) {
-        const actionsPanel = get_actions_panel(container);
+    var add_confirm_loan_button = function (box, loan) {
+        const actionsPanel = get_actions_panel(box);
         if (userIsAdministrator() === true || userHasRole("curator") === true) {
             const but = $(_confirm_loan_button);
             actionsPanel.append(but);
 
             but.click(() => {
                 but.remove();
-                confirm_loan_function(container);
+                confirm_loan_function(box);
             });
         } else {
             actionsPanel.append($(create_link_to_loan(loan, "Loan request accepted.")));
         }
     }
 
-    var return_function = async function (form, container) {
+    var return_function = async function (form, box) {
         const wait = getPleaseWaitSpan();
-        const actions_panel = get_actions_panel(container);
+        const actions_panel = get_actions_panel(box);
         $(actions_panel).append(wait).find('btn').hide()
         $(form).hide();
 
         const return_request = get_request_data(form);
 
 
-        const loan = (await get_active_loans(container))[0];
+        const loan = (await get_active_loans(box))[0];
 
 
         $.extend(return_request, {
-            container: getEntityID(container),
+            box: getEntityID(box),
             loan: getEntityID(loan),
         });
 
         const result = await run_script("loan_management/request_return.py", return_request);
         $(wait).remove();
         $(form).remove();
-        show_result(actions_panel, result, container);
+        show_result(actions_panel, result, box);
     }
 
 
     /**
-     * Add buttons for borrowing containers.
+     * Add buttons for borrowing boxes.
      */
-    var add_buttons = function (containers) {
-        $(containers).find('.container-loan-btn').remove();
-        $(containers).each(async function () {
+    var add_buttons = function (boxes) {
+        $(boxes).find('.box-loan-btn').remove();
+        $(boxes).each(async function () {
             const loan_state = await get_loan_state(this);
             if (typeof loan_state.loan !== "undefined") {
                 if (loan_state.state == "loan_requested") {
@@ -614,14 +650,15 @@ var loan_management = function () {
     }
 
     /**
-     * This function generates a form for borrowing containers.
-     * selectform can be used to generate the form for multiple containers.
-     * In case selectform is true, container will be ignored.
+     * This function generates a form for borrowing boxes.
+     * selectform can be used to generate the form for multiple boxes.
+     * In case selectform is true, box will be ignored.
      */
-    var generate_form_borrow_checkout = async function (container) {
+    var generate_form_borrow_checkout = async function (box) {
         const email = window.localStorage["borrower_email"];
         const firstname = window.localStorage["borrower_first_name"];
         const lastname = window.localStorage["borrower_last_name"];
+        const destination = window.localStorage["borrower_destination"];
         var exp_return = window.localStorage["borrower_return_date"];
         if (exp_return < Date.now()) {
             exp_return = "";
@@ -629,10 +666,11 @@ var loan_management = function () {
 
 
         return getHTMLForm("loan-forms/borrow_checkout", {
-            containerid: getEntityID(container),
+            boxid: getEntityID(box),
             first_name: firstname,
             last_name: lastname,
             email: email,
+            destination: destination,
             expected_return_date: exp_return,
             mindate: get_formatted_date("T")
         });
@@ -642,16 +680,17 @@ var loan_management = function () {
     /**
      * Generate form for a new Return Request, with fields
      *
-     * containerid (hidden)
+     * boxid (hidden)
      * first_name (pre-filled)
      * last_name (pre-filled)
      * email (pre-filled)
      * expectedreturn (pre-filled)
+     * currentlocation (pre-filled)
      * comment
      */
-    var generate_return_form = async function (container) {
-        const loan = (await get_active_loans(container))[0];
-        const borrower = (await retrieve(getProperty(loan, "borrower", case_sensitive = false)))[0];
+    var generate_return_form = async function (box) {
+        const loan = (await get_active_loans(box))[0];
+        const borrower = (await retrieve(getProperty(loan, "Borrower", case_sensitive = false)))[0];
 
         var email = getProperty(borrower, "email", case_sensitive = false);
         var first_name = getProperty(borrower, "firstName",
@@ -660,24 +699,26 @@ var loan_management = function () {
             case_sensitive = false);
         var exp_return = getProperty(loan, "expectedReturn",
             case_sensitive = false);
+        var cur_loc = getProperty(loan, "destination", case_sensitive = false);
 
-        return getHTMLForm("loan-forms/return_container", {
-            containerid: getEntityID(container),
+        return getHTMLForm("loan-forms/return_box", {
+            boxid: getEntityID(box),
             first_name: first_name,
             last_name: last_name,
             email: email,
             expectedreturn: exp_return,
+            currentlocation: cur_loc,
             mindate: get_formatted_date("T")
         });
     }
 
-    var init = function (containers) {
-        const init_containers = containers || $(".caosdb-entity-panel")
+    var init = function (boxes) {
+        const init_boxes = boxes || $(".caosdb-entity-panel")
             .not("[data-version-successor]")
-            /* TODO: This fails easily (ContainerType) */
-            .has(".caosdb-parent-name:contains('Container')")
-            .not(":has(.caosdb-parent-name:contains('ContainerT'))").toArray();
-        add_buttons(init_containers);
+            /* TODO: This fails easily (BoxType) */
+            .has(".caosdb-parent-name:contains('Box')")
+            .not(":has(.caosdb-parent-name:contains('BoxT'))").toArray();
+        add_buttons(init_boxes);
     }
 
     return {
@@ -695,5 +736,5 @@ var loan_management = function () {
  */
 $(document).ready(function () {
     // TODO build variable
-    loan_management.init();
+    awi_box_loan.init();
 });
diff --git a/caosdb-server/scripting/bin/loan_management/accept_loan_request.py b/caosdb-server/scripting/bin/loan_management/accept_loan_request.py
index c651d5d3954b9ddb326986e1fffe14185467e024..c4bc70401eb526130bac037756c350246d2b26a8 100755
--- a/caosdb-server/scripting/bin/loan_management/accept_loan_request.py
+++ b/caosdb-server/scripting/bin/loan_management/accept_loan_request.py
@@ -23,9 +23,9 @@ Accept a loan request.
 from __future__ import absolute_import
 import caosdb as db
 from caosadvancedtools.serverside.helper import print_success, get_timestamp
-from container_loan import (main, get_loan, F_LOAN, assert_loan_state,
-                            LOAN_ACCEPTED, S_LOAN_ACCEPTED, S_LOAN_REQUESTED,
-                            get_borrower_names, set_property)
+from box_loan import (main, get_loan, F_LOAN, assert_loan_state,
+                         LOAN_ACCEPTED, S_LOAN_ACCEPTED, S_LOAN_REQUESTED,
+                         get_borrower_names, set_property)
 
 
 def _accept_loan_request(data):
diff --git a/caosdb-server/scripting/bin/loan_management/accept_return_request.py b/caosdb-server/scripting/bin/loan_management/accept_return_request.py
index efbdc931cb99a29f5bb8e2d4a431048498a7ac67..b28a7d4c0aa2a61c0794566d01cb38f8a6a827cd 100755
--- a/caosdb-server/scripting/bin/loan_management/accept_return_request.py
+++ b/caosdb-server/scripting/bin/loan_management/accept_return_request.py
@@ -20,12 +20,14 @@
 """
 Accept a return request.
 """
+# @review Timm Fitschen 2022-03-16
 from __future__ import absolute_import
 import caosdb as db
 from caosadvancedtools.serverside.helper import print_success, get_timestamp
-from container_loan import (main, get_loan, set_property, F_LOAN,
-                            assert_loan_state, RETURN_ACCEPTED, S_RETURN_ACCEPTED,
-                            S_RETURN_REQUESTED, get_borrower_names)
+from box_loan import (BOX_BORROWED, CONTENT, main, get_loan, set_property,
+                      F_LOAN, assert_loan_state, RETURN_ACCEPTED,
+                      RETURNLOCATION, S_RETURN_ACCEPTED, S_RETURN_REQUESTED,
+                      get_borrower_names, set_location)
 
 
 def _accept_return_request(data):
@@ -38,8 +40,16 @@ def _accept_return_request(data):
 
     # To be sure that it worked:
     assert_loan_state(loan, S_RETURN_ACCEPTED)
+    box = set_location(loan, RETURNLOCATION, update=False)
+    if loan.get_property(CONTENT) is not None and loan.get_property(CONTENT).value:
+        if box.get_property(CONTENT) is not None:
+            box.get_property(CONTENT).value = loan.get_property(CONTENT).value
+        else:
+            box.add_property(id=CONTENT.retrieve().id,
+                             value=loan.get_property(CONTENT).value)
 
     db.Container().extend([
+        box,
         loan
     ]).update()
 
@@ -53,10 +63,15 @@ def accept_return_request(data):
     """
     loan = _accept_return_request(data)
     fn, ln = get_borrower_names(loan)
+    box_id = loan.get_property(BOX_BORROWED).value.split("@")[0]
 
-    print_success('Thank you for accepting the return request by {fn} {ln}. See '
-                  '<a href="{loan}" title="Go to the accepted loan '
-                  'request.">here</a>'.format(fn=fn, ln=ln, loan=loan.id))
+    print_success('Thank you for accepting the return request by {fn} {ln}.<br>'
+                  'If necessary, location and content of the box have been '
+                  'updated.<br>'
+                  '<a href="/Entity/{bid}" title="Reload this page.">Reload</a> '
+                  'to view the new Location.<br>'
+                  'See <a href="{loan}" title="Go to the accepted loan '
+                  'request.">here</a>'.format(fn=fn, ln=ln, loan=loan.id, bid=box_id))
     return 0
 
 
diff --git a/caosdb-server/scripting/bin/loan_management/box_loan.py b/caosdb-server/scripting/bin/loan_management/box_loan.py
old mode 100755
new mode 100644
index beba112aaec660461ef419c0f4c46e90e7fcf288..393c715c36c34f647be10f69acf877dee0ea9bc9
--- a/caosdb-server/scripting/bin/loan_management/box_loan.py
+++ b/caosdb-server/scripting/bin/loan_management/box_loan.py
@@ -37,18 +37,20 @@ from caosadvancedtools.serverside.logging import configure_server_side_logging
 from caosdb.exceptions import EmptyUniqueQueryError
 from validate_email import validate_email
 
-LOGGER_NAME = "container_loan"
+LOGGER_NAME = "box_loan"
 LOGGER = logging.getLogger(LOGGER_NAME)
 
 # Form names
-F_CONTAINER = "container"
+F_BOX = "box"
 F_FIRST_NAME = "first_name"
 F_LAST_NAME = "last_name"
 F_EMAIL = "email"
 F_EXPECTED_RETURN_DATE = "expected_return_date"
 F_EXHAUST_CONTENTS = "exhaust_contents"
 F_COMMENT = "comment"
+F_DESTINATION = "destination"
 F_LOAN = "loan"
+F_CURRENT_LOCATION = "current_location"
 
 S_RETURNED = "returned"
 S_RETURN_ACCEPTED = "return_accepted"
@@ -59,24 +61,26 @@ S_LOAN_REQUESTED = "loan_requested"
 
 
 _EMTPY_DATA = {
-    F_CONTAINER: None,
+    F_BOX: None,
     F_FIRST_NAME: None,
     F_LAST_NAME: None,
     F_EMAIL: None,
     F_EXPECTED_RETURN_DATE: None,
     F_EXHAUST_CONTENTS: None,
     F_COMMENT: None,
+    F_DESTINATION: None,
     F_LOAN: None,
+    F_CURRENT_LOCATION: None
 }
 
-CONTAINER = db.RecordType(name="Container")
-CONTAINER_RETURNED = "Container (returned)"
-CONTAINER_BORROWED = "Container (borrowed)"
+BOX = db.RecordType(name="Box")
+BOX_RETURNED = "Box (returned)"
+BOX_BORROWED = "Box (borrowed)"
 PERSON = db.RecordType(name="Person")
 LOAN = db.RecordType(name="Loan")
 
 RECORD_TYPES = [
-    CONTAINER,
+    BOX,
     PERSON,
     LOAN,
 ]
@@ -85,6 +89,9 @@ RECORD_TYPES = [
 FIRST_NAME = db.Property(name="firstName", datatype=db.TEXT)
 LAST_NAME = db.Property(name="lastName", datatype=db.TEXT)
 EMAIL = db.Property(name="email", datatype=db.TEXT)
+LOCATION = db.RecordType(name="Location")
+DESTINATION = db.Property(name="LoanLocation", datatype="Location")
+RETURNLOCATION = db.Property(name="ReturnLocation", datatype="Location")
 COMMENT = db.Property(name="comment", datatype=db.TEXT)
 EXHAUST_CONTENTS = db.Property(name="exhaustContents", datatype=db.BOOLEAN)
 BORROWER = db.Property(name="Borrower", datatype=PERSON.name)
@@ -96,11 +103,15 @@ LENT = db.Property(name="lent", datatype=db.DATETIME)
 RETURN_REQUESTED = db.Property(name="returnRequested", datatype=db.DATETIME)
 RETURN_ACCEPTED = db.Property(name="returnAccepted", datatype=db.DATETIME)
 RETURNED = db.Property(name="returned", datatype=db.DATETIME)
+BOX_NUMBER = db.Property(name="Number", datatype=db.TEXT)
 
 PROPERTIES = [
     FIRST_NAME,
     LAST_NAME,
     EMAIL,
+    LOCATION,
+    DESTINATION,
+    RETURNLOCATION,
     COMMENT,
     EXHAUST_CONTENTS,
     BORROWER,
@@ -112,6 +123,7 @@ PROPERTIES = [
     RETURN_REQUESTED,
     RETURN_ACCEPTED,
     RETURNED,
+    BOX_NUMBER,
 ]
 
 
@@ -211,10 +223,10 @@ def get_record_by_id(parent, entity_id):
                             unique=True)
 
 
-def get_container(container):
-    """ Retrieve a container record by id. """
+def get_box(box):
+    """ Retrieve a box record by id. """
 
-    return get_record_by_id(CONTAINER.name, container)
+    return get_record_by_id(BOX.name, box)
 
 
 def get_loan(loan):
@@ -294,10 +306,12 @@ def assert_email_pattern(email):
     EmailPatternError
     """
 
-    if email is None or not validate_email(email_address=email,
-                                           check_format=True, check_smtp=False,
-                                           check_dns=False,
-                                           check_blacklist=False):
+    if email is None or not validate_email(
+            email_address=email,
+            check_format=True,
+            check_blacklist=False,
+            check_dns=False,
+            check_smtp=False):
         raise EmailPatternError(email)
 
 
@@ -338,24 +352,25 @@ def get_external_server_uri():
 
 def send_loan_request_mail(data, borrower, loan):
     try:
-        containerid = str(loan.get_property(CONTAINER).value).split("@")[0]
-        container = get_container(containerid)
+        boxid = str(loan.get_property(BOX).value).split("@")[0]
+        box = get_box(boxid)
+        boxnumber = get_property_value(box, BOX_NUMBER, "UNKNOWN")
 
-        link = "{uri}Entity/{containerid}&{loanid}".format(
+        link = "{uri}Entity/{boxid}&{loanid}".format(
             uri=get_external_server_uri(),
-            containerid=containerid,
+            boxid=boxid,
             loanid=loan.id)
 
         body = """Dear Curator,
 
-    a new loan has been request by {borrower} for container {containername}.
+    a new loan has been request by {borrower} for box number {boxnumber}.
 
     Loan request:
         {data}
 
-    View container and loan records:
+    View box and loan records:
         {link}
-    """.format(containername=container.name, borrower=get_requester_string(borrower),
+    """.format(boxnumber=boxnumber, borrower=get_requester_string(borrower),
                data=data, link=link)
 
         send_mail(
@@ -363,11 +378,11 @@ def send_loan_request_mail(data, borrower, loan):
             to=EMAIL_CURATOR,
             subject="loan request",
             body=body)
-        print_info("An email has been sent to the responsible container curator.")
+        print_info("An email has been sent to the responsible box curator.")
     except BaseException as e:
-        print_error("""Sending an email to the responsible container curator failed
+        print_error("""Sending an email to the responsible box curator failed
 
-for an unknown reason. Please inform the container curator by yourself about your
+for an unknown reason. Please inform the box curator by yourself about your
 loan request and that the email sending failed. Thank you very much for your
 help.""")
         LOGGER.error(e)
@@ -375,36 +390,40 @@ help.""")
 
 def send_return_request_mail(data, returner, loan):
     try:
-        containerid = str(loan.get_property(CONTAINER).value).split("@")[0]
-        container = get_container(containerid)
+        boxid = str(loan.get_property(BOX).value).split("@")[0]
+        box = get_box(boxid)
+        boxnumber = get_property_value(box, BOX_NUMBER, "UNKNOWN")
+        current_location = data[F_CURRENT_LOCATION]
 
-        link = "{uri}Entity/{containerid}&{loanid}".format(
+        link = "{uri}Entity/{boxid}&{loanid}".format(
             uri=get_external_server_uri(),
-            containerid=containerid,
+            boxid=boxid,
             loanid=loan.id)
 
         body = """Dear Curator,
 
-    a new return request by {returner} for container {containername} is pending.
+    a new return request by {returner} for box number {boxnumber} is pending.
+    The current location of the box according to the return request is
+    "{current_location}".
 
     Return request:
         {data}
 
-    View container and loan records:
+    View box and loan records:
         {link}
-    """.format(containername=container.name, returner=get_requester_string(returner),
-               data=data, link=link)
+    """.format(boxnumber=boxnumber, returner=get_requester_string(returner),
+               data=data, link=link, current_location=current_location)
 
         send_mail(
             from_addr=EMAIL_FROM,
             to=EMAIL_CURATOR,
             subject="return request",
             body=body)
-        print_info("An email has been sent to the responsible container curator.")
+        print_info("An email has been sent to the responsible box curator.")
     except BaseException as e:
-        print_error("""Sending an email to the responsible container curator failed
+        print_error("""Sending an email to the responsible box curator failed
 
-for an unknown reason. Please inform the container curator by yourself about this
+for an unknown reason. Please inform the box curator by yourself about this
 
 return request and that the email sending failed. Thank you very much for your
 help.""")
@@ -526,6 +545,23 @@ def _caller(func, args):
     return func(data)
 
 
+def set_location(loan, kind, update=True):
+    """Set the location of the box to a location of the loan.
+
+    kind can be RETURNLOCATION or DESTINATION
+    """
+    # @review Timm Fitschen 2022-03-16
+
+    if loan.get_property(kind) is not None:
+        box_id = loan.get_property(BOX_BORROWED).value.split("@")[0]
+        box = db.Record(id=box_id).retrieve()
+        set_property(box, LOCATION, loan.get_property(kind).value)
+        if update:
+            box.update()
+        else:
+            return box
+
+
 def main(func, args=None):
     # configure_server_side_logging(LOGGER_NAME)
     try:
diff --git a/caosdb-server/scripting/bin/loan_management/confirm_loan.py b/caosdb-server/scripting/bin/loan_management/confirm_loan.py
index 07739e479c6ab2eb067b6a8dda9cbd6db3682bff..4b463b7cad7435d2484e8c9ce5d63585b7dfc339 100755
--- a/caosdb-server/scripting/bin/loan_management/confirm_loan.py
+++ b/caosdb-server/scripting/bin/loan_management/confirm_loan.py
@@ -25,19 +25,24 @@ from __future__ import absolute_import
 import caosdb as db
 from caosadvancedtools.serverside.helper import get_timestamp, print_success
 
-from container_loan import (CONTAINER, CONTAINER_BORROWED, F_LOAN, LENT, S_LENT,
-                            S_LOAN_ACCEPTED, assert_loan_state, get_borrower_names,
-                            get_loan, main, set_property)
+from box_loan import (BOX, BOX_BORROWED, DESTINATION, F_LOAN, LENT, S_LENT,
+                      S_LOAN_ACCEPTED, assert_loan_state, get_borrower_names,
+                      get_loan, main, set_location, set_property)
 
 
-def _set_lent_container(loan):
-    """Set the container version to HEAD.
+def _set_lent_box(loan):
+    """Set the box version to HEAD.
 
-    This stores the version of the container when it was delivered to the borrower.
+    This stores the version of the box when it was delivered to the borrower.
     """
-    container_prop = loan.get_property(CONTAINER)
-    container_prop.name = CONTAINER_BORROWED
-    container_prop.value = str(container_prop.value) + "@HEAD"
+    box_prop = loan.get_property(BOX)
+    box_prop.name = BOX_BORROWED
+    box_prop.value = str(box_prop.value) + "@HEAD"
+
+
+def set_loan_location(loan):
+    """Set the location of the box to the return location of the loan.  """
+    set_location(loan, DESTINATION)
 
 
 def _confirm_loan(data):
@@ -47,7 +52,10 @@ def _confirm_loan(data):
 
     # This changes the state from "loan_accepted" to "lent".
     set_property(loan, LENT, get_timestamp())
-    _set_lent_container(loan)
+    _set_lent_box(loan)
+
+    # updates the box location
+    set_loan_location(loan)
 
     # To be sure that it worked:
     assert_loan_state(loan, S_LENT)
@@ -67,11 +75,15 @@ def confirm_loan(data):
     loan = _confirm_loan(data)
     fn, ln = get_borrower_names(loan)
     loan = get_loan(data[F_LOAN])
-    container_id = loan.get_property(CONTAINER_BORROWED).value.split("@")[0]
+    box_id = loan.get_property(BOX_BORROWED).value.split("@")[0]
     print_success('Thank you for confirming the loan request by {fn} {ln}.<br>'
+                  'The Location of the Box was updated. '
+                  '<a href="/Entity/{bid}" title="Reload this page.">Reload</a> '
+                  'to view the new Location.<br>'
                   'You can also checkout the new loan state '
                   '<a href="{loan}" title="Go to the confirmed loan '
-                  'record.">here</a>'.format(fn=fn, ln=ln, loan=loan.id))
+                  'record.">here</a>'.format(fn=fn, ln=ln, loan=loan.id,
+                                             bid=box_id))
 
     return 0
 
diff --git a/caosdb-server/scripting/bin/loan_management/manual_return.py b/caosdb-server/scripting/bin/loan_management/manual_return.py
index 68ff990feb3fd4c993acc5740bcf47cb2ba22159..9aa7e83c3f3210ad719d41a0b1aa00896e7e5aca 100755
--- a/caosdb-server/scripting/bin/loan_management/manual_return.py
+++ b/caosdb-server/scripting/bin/loan_management/manual_return.py
@@ -18,36 +18,41 @@
 #
 #
 """
-Manually return a container.
+Manually return a box.
 """
 from __future__ import absolute_import
 
 import caosdb as db
 from caosadvancedtools.serverside.helper import get_timestamp, print_success
 
-from container_loan import (CONTAINER, CONTAINER_BORROWED, CONTAINER_RETURNED,
-                            CONTENT, F_LOAN, RETURNED, S_RETURN_ACCEPTED,
-                            S_RETURNED, assert_loan_state, get_borrower_names,
-                            get_loan, main, set_property)
+from box_loan import (BOX, BOX_BORROWED, BOX_RETURNED, CONTENT, F_LOAN,
+                      RETURNED, RETURNLOCATION, S_RETURN_ACCEPTED, S_RETURNED,
+                      assert_loan_state, get_borrower_names, get_loan, main,
+                      set_location, set_property)
 
 
-def _set_returned_container(loan):
-    """Add a `Container (returned)` property to the loan.
+def _set_returned_box(loan):
+    """Add a `Box (returned)` property to the loan.
 
-    This stores the version of the container that was returned by a borrower.
+    This stores the version of the box that was returned by a borrower.
     """
-    container_id = loan.get_property(CONTAINER_BORROWED).value.split("@")[0]
-    loan.add_property(property=CONTAINER,
-                      name=CONTAINER_RETURNED,
-                      value=container_id + "@HEAD")
+    box_id = loan.get_property(BOX_BORROWED).value.split("@")[0]
+    loan.add_property(property=BOX,
+                      name=BOX_RETURNED,
+                      value=box_id + "@HEAD")
+
+
+def set_return_location(loan):
+    """Set the location of the box to the return location of the loan.  """
+    set_location(loan, RETURNLOCATION)
 
 
 def set_content(loan):
-    """Set the content to the container to the one given in the loan.  """
-    container_id = loan.get_property(CONTAINER_BORROWED).value.split("@")[0]
-    container = db.Record(id=container_id).retrieve()
-    set_property(container, CONTENT, loan.get_property(CONTENT).value)
-    container.update()
+    """Set the content to the box to the one given in the loan.  """
+    box_id = loan.get_property(BOX_BORROWED).value.split("@")[0]
+    box = db.Record(id=box_id).retrieve()
+    set_property(box, CONTENT, loan.get_property(CONTENT).value)
+    box.update()
 
 
 def _manual_return(data):
@@ -59,11 +64,16 @@ def _manual_return(data):
     set_property(loan, RETURNED, get_timestamp())
     set_property(loan, RETURNED, get_timestamp())
 
+    # updates the box location and content
+    # *currently this is not wanted*
+    # set_return_location(loan)
+    # set_content(loan)
+
     # To be sure that it worked:
     assert_loan_state(loan, S_RETURNED)
 
-    # add returned container
-    _set_returned_container(loan)
+    # add returned box
+    _set_returned_box(loan)
 
     db.Container().extend([
         loan
@@ -73,16 +83,19 @@ def _manual_return(data):
 
 
 def manual_return(data):
-    """Return a container from a borrower.
+    """Return a box from a borrower.
 
     I.e. update the `Loan` Record and add the `returned` Property.
     """
     loan = _manual_return(data)
     fn, ln = get_borrower_names(loan)
     loan = get_loan(data[F_LOAN])
+    box_id = loan.get_property(BOX_BORROWED).value.split("@")[0]
 
-    print_success('The container borrowed by {fn} {ln} '.format(fn=fn, ln=ln)
-                  + 'has been returned.<br>')
+    print_success('The box borrowed by {fn} {ln} '.format(fn=fn, ln=ln)
+                  + 'has been returned and the Box Location has been updated.'
+                  '<a href="/Entity/{bid}" title="Reload this page.">Reload</a> '
+                  'to view the new Location.<br>'.format(bid=box_id))
 
     return 0
 
diff --git a/caosdb-server/scripting/bin/loan_management/reject_return_request.py b/caosdb-server/scripting/bin/loan_management/reject_return_request.py
index 6809f1fc73ee5167dad33778a818616e6ff30b53..0d8227edc96ec1482d30d44448dfa1788fafac7a 100755
--- a/caosdb-server/scripting/bin/loan_management/reject_return_request.py
+++ b/caosdb-server/scripting/bin/loan_management/reject_return_request.py
@@ -23,9 +23,9 @@ Reject a return request.
 from __future__ import absolute_import
 import caosdb as db
 from caosadvancedtools.serverside.helper import print_success
-from container_loan import (main, get_loan, F_LOAN, assert_loan_state,
-                            S_RETURN_REQUESTED, RETURN_REQUESTED, S_LENT,
-                            get_borrower_names)
+from box_loan import (main, get_loan, F_LOAN, assert_loan_state,
+                         S_RETURN_REQUESTED, RETURN_REQUESTED, S_LENT,
+                         get_borrower_names)
 
 
 def _reject_return_request(data):
diff --git a/caosdb-server/scripting/bin/loan_management/request_loan.py b/caosdb-server/scripting/bin/loan_management/request_loan.py
index 486f3e328349500c25d25b895a741d93895147d0..93714405aa3332def925695eeadc2d4ceb21ebe0 100755
--- a/caosdb-server/scripting/bin/loan_management/request_loan.py
+++ b/caosdb-server/scripting/bin/loan_management/request_loan.py
@@ -25,25 +25,27 @@ from __future__ import absolute_import
 import caosdb as db
 from caosadvancedtools.serverside.helper import get_timestamp, print_success
 
-from container_loan import (BORROWER, CONTAINER, COMMENT, EXHAUST_CONTENTS,
-                            EXPECTED_RETURN, F_CONTAINER, F_COMMENT, F_EMAIL,
-                            F_EXHAUST_CONTENTS, F_EXPECTED_RETURN_DATE,
-                            F_FIRST_NAME, F_LAST_NAME, FIRST_NAME, LAST_NAME,
-                            LOAN, LOAN_REQUESTED, assert_date_in_future,
-                            assert_key_in_data, get_container, get_person, main,
-                            send_loan_request_mail)
+from box_loan import (BORROWER, BOX, COMMENT, DESTINATION, EXHAUST_CONTENTS,
+                      EXPECTED_RETURN, F_BOX, F_COMMENT, F_DESTINATION,
+                      F_EMAIL, F_EXHAUST_CONTENTS, F_EXPECTED_RETURN_DATE,
+                      F_FIRST_NAME, F_LAST_NAME, FIRST_NAME, LAST_NAME, LOAN,
+                      LOAN_REQUESTED, assert_date_in_future,
+                      assert_key_in_data, get_box, get_person, main,
+                      send_loan_request_mail)
 
 
-def create_loan(container, borrower, expected_return, exhaust_contents, comment):
+def create_loan(box, borrower, expected_return, exhaust_contents, comment,
+                destination):
     """ Create a new loan record. """
 
     loan = db.Record().add_parent(LOAN)
 
-    loan.add_property(CONTAINER, container)
+    loan.add_property(BOX, box)
     loan.add_property(BORROWER, borrower)
     loan.add_property(EXPECTED_RETURN, expected_return)
     loan.add_property(EXHAUST_CONTENTS, exhaust_contents)
     loan.add_property(COMMENT, comment)
+    loan.add_property(DESTINATION, destination)
     loan.add_property(LOAN_REQUESTED, get_timestamp())
 
     return loan
@@ -51,8 +53,9 @@ def create_loan(container, borrower, expected_return, exhaust_contents, comment)
 
 _OBLIGATORY = [
     F_EXPECTED_RETURN_DATE,
-    F_CONTAINER,
+    F_BOX,
     F_COMMENT,
+    F_DESTINATION,
     F_EMAIL,
     F_LAST_NAME,
     F_FIRST_NAME,
@@ -77,22 +80,23 @@ def _check_data(data):
 def _issue_loan_request(data):
     """ Insert a loan record a insert/update a person record. """
     data = _check_data(data)
-    container = get_container(data[F_CONTAINER])
+    box = get_box(data[F_BOX])
     borrower = get_person(firstname=data[F_FIRST_NAME],
                           lastname=data[F_LAST_NAME],
                           email=data[F_EMAIL])
-    loan = create_loan(container=data[F_CONTAINER],
+    loan = create_loan(box=data[F_BOX],
                        borrower=borrower,
                        expected_return=data[F_EXPECTED_RETURN_DATE],
                        exhaust_contents=data[F_EXHAUST_CONTENTS],
-                       comment=data[F_COMMENT])
+                       comment=data[F_COMMENT],
+                       destination=data[F_DESTINATION])
     c = db.Container().extend([
         borrower,
         loan
     ])
     c.insert()
 
-    return borrower, loan, container
+    return borrower, loan, box
 
 
 def issue_loan_request(data):
@@ -103,8 +107,9 @@ def issue_loan_request(data):
         * borrower
         * expectedReturn
         * exhaustContents
-        * Container
+        * Box
         * comment
+        * destination
 
     The borrower is a Person Record, with firstName, lastName and email,
     identified by either email, oder firstName+lastName.
diff --git a/caosdb-server/scripting/bin/loan_management/request_return.py b/caosdb-server/scripting/bin/loan_management/request_return.py
index 778f5d0fce689d3ab189c0ec78e391884c52787f..d64e72e49c7cbcf51d6277d2d8d3ca34b1c81838 100755
--- a/caosdb-server/scripting/bin/loan_management/request_return.py
+++ b/caosdb-server/scripting/bin/loan_management/request_return.py
@@ -28,19 +28,20 @@ from __future__ import absolute_import
 
 from caosadvancedtools.serverside.helper import get_timestamp, print_success
 
-from container_loan import (BORROWER, COMMENT, CONTENT, EXPECTED_RETURN, F_COMMENT,
-                            F_EMAIL, F_EXPECTED_RETURN_DATE,
-                            F_FIRST_NAME, F_LAST_NAME, F_LOAN, FIRST_NAME, LAST_NAME,
-                            RETURN_REQUESTED, S_LENT,
-                            assert_date_in_future, assert_key_in_data,
-                            assert_loan_state, get_loan, get_person, main,
-                            send_return_request_mail, set_property)
+from box_loan import (BORROWER, COMMENT, CONTENT, EXPECTED_RETURN, F_COMMENT,
+                      F_CURRENT_LOCATION, F_EMAIL, F_EXPECTED_RETURN_DATE,
+                      F_FIRST_NAME, F_LAST_NAME, F_LOAN, FIRST_NAME, LAST_NAME,
+                      RETURN_REQUESTED, RETURNLOCATION, S_LENT,
+                      assert_date_in_future, assert_key_in_data,
+                      assert_loan_state, get_loan, get_person, main,
+                      send_return_request_mail, set_property)
 
 
 def _check_data(data):
     assert_key_in_data(data, F_EXPECTED_RETURN_DATE)
     assert_key_in_data(data, F_LOAN)
     assert_key_in_data(data, F_COMMENT)
+    assert_key_in_data(data, F_CURRENT_LOCATION)
 
     assert_date_in_future(
         data[F_EXPECTED_RETURN_DATE],
@@ -60,6 +61,7 @@ def _issue_return_request(data):
     set_property(loan, BORROWER, returner.id)
     set_property(loan, EXPECTED_RETURN, data[F_EXPECTED_RETURN_DATE])
     set_property(loan, CONTENT, data[F_COMMENT])
+    set_property(loan, RETURNLOCATION, data[F_CURRENT_LOCATION])
 
     loan.update()
 
diff --git a/caosdb-server/scripting/bin/test/loan_management/box_loan.py b/caosdb-server/scripting/bin/test/loan_management/box_loan.py
new file mode 120000
index 0000000000000000000000000000000000000000..034b4c7dfca3b7d5c0e6ac80ad830c176658934a
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/box_loan.py
@@ -0,0 +1 @@
+../../loan_management/box_loan.py
\ No newline at end of file
diff --git a/caosdb-server/scripting/bin/test/loan_management/manual_return.py b/caosdb-server/scripting/bin/test/loan_management/manual_return.py
new file mode 120000
index 0000000000000000000000000000000000000000..f0eab4f92842389daf8a57e71480f8238d93e421
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/manual_return.py
@@ -0,0 +1 @@
+../../loan_management/manual_return.py
\ No newline at end of file
diff --git a/caosdb-server/scripting/bin/test/loan_management/request_loan.py b/caosdb-server/scripting/bin/test/loan_management/request_loan.py
new file mode 120000
index 0000000000000000000000000000000000000000..0c060509fbb552f9e92d8b890acbbdb1db3e2e7c
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/request_loan.py
@@ -0,0 +1 @@
+../../loan_management/request_loan.py
\ No newline at end of file
diff --git a/caosdb-server/scripting/bin/test/loan_management/request_loan_form.json b/caosdb-server/scripting/bin/test/loan_management/request_loan_form.json
new file mode 100644
index 0000000000000000000000000000000000000000..3db881151c2bf48b006a98cfcd90609fcf7d7c8b
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/request_loan_form.json
@@ -0,0 +1,12 @@
+{
+    "loan": 12345,
+    "box": 2345,
+    "first_name": "Anna",
+    "last_name": "Lytik",
+    "email": "a.lytik@example.com",
+    "expected_return_date": "2020-12-24",
+    "exhaust_contents": "true",
+    "comment": "this is a comment",
+    "destination": "blablabla destination",
+    "current_location": "blublublub"
+}
diff --git a/caosdb-server/scripting/bin/test/loan_management/request_return.py b/caosdb-server/scripting/bin/test/loan_management/request_return.py
new file mode 120000
index 0000000000000000000000000000000000000000..b080e7193350a231c118aa9d493966ca5ffe45d8
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/request_return.py
@@ -0,0 +1 @@
+../../loan_management/request_return.py
\ No newline at end of file
diff --git a/caosdb-server/scripting/bin/test/loan_management/test_box_loan.py b/caosdb-server/scripting/bin/test/loan_management/test_box_loan.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1b17f253e8014b855a9462d3e8d3dc30cc7e1dc
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/test_box_loan.py
@@ -0,0 +1,99 @@
+from os.path import abspath, dirname, join
+from pytest import raises
+from caosdb import get_connection, configure_connection
+from caosdb.connection.mockup import (MockUpServerConnection, MockUpResponse)
+from box_loan import (_caller, create_person, query_person, get_person,
+                         EMAIL, FIRST_NAME, LAST_NAME, PERSON,
+                         assert_date_in_future, DataError, EmailPatternError,
+                         assert_email_pattern)
+
+
+def setup():
+    configure_connection(url="unittests", username="testuser",
+                         password_method="plain",
+                         password="testpassword", timeout=200,
+                         implementation=MockUpServerConnection)
+
+
+def get_data_example():
+    return abspath(join(dirname(__file__), "request_loan_form.json"))
+
+
+def test_caller():
+    args = [get_data_example()]
+
+    def test_func(data):
+        assert data["box"] == 2345, "should contain the data from json"
+        return 1337
+
+    assert _caller(test_func, args) == 1337
+
+
+def test_create_person():
+    p = create_person("anna", "lytik", "a@b.com")
+    assert p.get_parents()[0].name == PERSON.name
+    assert p.get_property(FIRST_NAME.name).value == "anna"
+    assert p.get_property(LAST_NAME.name).value == "lytik"
+    assert p.get_property(EMAIL.name).value == "a@b.com"
+
+
+def test_query_person():
+    connection = get_connection()
+    entities = ('<Response><Query results="1"/>'
+                '<RecordType id="1234"/></Response>')
+
+    def query_resource(**kwargs):
+        query = kwargs["path"].split("query=")[1]
+        assert query.startswith("FIND%20RECORD%20" + PERSON.name)
+        return MockUpResponse(200, {}, entities)
+    connection._delegate_connection.resources.append(query_resource)
+
+    p = query_person("petri", "schale", "c@d.com")
+    assert p.id == 1234
+
+
+def test_get_person_with_update():
+    connection = get_connection()
+    person_xml = (
+        '<Response>{query}'
+        '<Record id="1234">'
+        '<Property name="email">{email}</Property>'
+        '</Record>'
+        '</Response>')
+
+    def query_resource(**kwargs):
+        if kwargs["method"] == "GET":
+            return MockUpResponse(200, {},
+                                  person_xml.format(
+                                      query='<Query results="1"/>',
+                                      email="old@email"))
+        else:
+            return MockUpResponse(200, {},
+                                  person_xml.format(
+                                      query='',
+                                      email="new@email"))
+    connection._delegate_connection.resources.append(query_resource)
+
+    p = get_person("firstname", None, "old@email")
+    assert p.get_property(EMAIL.name).value == "new@email"
+
+
+def test_create_person_with_wrong_email_pattern():
+    with raises(EmailPatternError):
+        assert_email_pattern("@asdf")
+    with raises(EmailPatternError):
+        assert_email_pattern("asdf")
+    with raises(EmailPatternError):
+        assert_email_pattern("asdfa.de")
+    with raises(EmailPatternError):
+        assert_email_pattern("sdfg@sdfg")
+
+    # the following shoudl be ok
+    assert_email_pattern("a@b.da")
+    assert_email_pattern("\"#\"@รถ.de")
+
+
+def test_assert_date_in_future():
+    assert assert_date_in_future("2050-01-01") is None
+    with raises(DataError):
+        assert_date_in_future("1971-01-01")
diff --git a/caosdb-server/scripting/bin/test/loan_management/test_manual_return.py b/caosdb-server/scripting/bin/test/loan_management/test_manual_return.py
new file mode 100644
index 0000000000000000000000000000000000000000..790575c73acc1c8d4fa5bb66f37c49d84b6845a3
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/test_manual_return.py
@@ -0,0 +1,18 @@
+from caosdb import Record
+from box_loan import BOX, BOX_RETURNED, BOX_BORROWED
+from manual_return import _set_returned_box
+
+
+def test_set_returned_box():
+    loan = Record()
+    loan.add_property(BOX, name=BOX_BORROWED, value="1234@abcd")
+
+    assert len(loan.get_properties()) == 1
+    assert loan.get_property(BOX_BORROWED).value == "1234@abcd"
+    assert loan.get_property(BOX_RETURNED) is None
+
+    _set_returned_box(loan)
+
+    assert len(loan.get_properties()) == 2
+    assert loan.get_property(BOX_BORROWED).value == "1234@abcd"
+    assert loan.get_property(BOX_RETURNED).value == "1234@HEAD"
diff --git a/caosdb-server/scripting/bin/test/loan_management/test_request_loan.py b/caosdb-server/scripting/bin/test/loan_management/test_request_loan.py
new file mode 100644
index 0000000000000000000000000000000000000000..d13537bd954ed4aa9d21be36785ee7d27ab235a7
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/test_request_loan.py
@@ -0,0 +1,102 @@
+from os.path import abspath, dirname, join
+from pytest import raises
+from caosdb import get_connection, configure_connection, Record
+from caosdb.connection.mockup import (MockUpServerConnection, MockUpResponse)
+from caosadvancedtools.serverside.helper import get_data
+from box_loan import (PERSON, FIRST_NAME, EMAIL, BOX, BORROWER,
+                         EXPECTED_RETURN, EXHAUST_CONTENTS, COMMENT,
+                         DESTINATION, F_FIRST_NAME, F_EMAIL,
+                         F_EXPECTED_RETURN_DATE, DataError, BOX_NUMBER)
+from request_loan import (create_loan, _issue_loan_request)
+
+
+def setup():
+    configure_connection(url="unittests", username="testuser",
+                         password_method="plain",
+                         password="testpassword", timeout=200,
+                         implementation=MockUpServerConnection)
+
+
+def get_data_example():
+    return abspath(join(dirname(__file__), "request_loan_form.json"))
+
+
+def test_issue_loan_request_with_wrong_return_date():
+    data = get_data(get_data_example())
+    data[F_EXPECTED_RETURN_DATE] = "1983-02-03"
+    with raises(DataError):
+        _issue_loan_request(data)
+
+
+def test_create_loan():
+    borrower = Record(name="Person1")
+    l = create_loan(1234,
+                    borrower,
+                    "2020-03-23",
+                    False,
+                    "blablabla",
+                    "my office")
+    assert l.get_property(BOX.name).value == 1234
+    assert l.get_property(BORROWER.name).value == borrower
+    assert l.get_property(EXPECTED_RETURN.name).value == "2020-03-23"
+    assert l.get_property(EXHAUST_CONTENTS.name).value == False
+    assert l.get_property(COMMENT.name).value == "blablabla"
+    assert l.get_property(DESTINATION.name).value == "my office"
+
+
+def test_issue_loan_request():
+    data = get_data(get_data_example())
+    person_xml = (
+        '<Response>{{query}}'
+        '<Record id="1234">'
+        '<Property name="{FN}">{FIRST_NAME}</Property>'
+        '<Property name="{EMAIL}">{{email}}</Property>'
+        '</Record>'
+        '</Response>').format(FN=FIRST_NAME.name, EMAIL=EMAIL.name,
+                              FIRST_NAME=data[F_FIRST_NAME])
+    box_xml = (
+        '<Response>{{query}}'
+        '<Record id="2345">'
+        '<Property name="{BN}">{BOXNUM}</Property>'
+        '</Record>'
+        '</Response>').format(BN=BOX_NUMBER.name, BOXNUM="0815")
+
+    def query_resource(**kwargs):
+        if kwargs["method"] == "GET" and BOX.name in kwargs["path"]:
+            query = kwargs["path"].split("query=")[1]
+            assert query.startswith("FIND%20RECORD%20" + BOX.name)
+            return MockUpResponse(200, {},
+                                  box_xml.format(
+                                      query='<Query results="1"/>'))
+        if kwargs["method"] == "GET" and PERSON.name in kwargs["path"]:
+            query = kwargs["path"].split("query=")[1]
+            assert query.startswith("FIND%20RECORD%20" + PERSON.name)
+            return MockUpResponse(200, {},
+                                  person_xml.format(
+                                      query='<Query results="1"/>',
+                                      email="old@email"))
+        elif kwargs["method"] == "PUT":
+            assert data[F_EMAIL] in kwargs["body"].decode("utf-8")
+            return MockUpResponse(200, {},
+                                  person_xml.format(
+                                      query='',
+                                      email=data[F_EMAIL]))
+        else:
+            assert "" in kwargs["body"].decode("utf-8")
+            body = kwargs["body"].decode(
+                "utf-8").replace('"-1"', '"4567"').replace("Insert", "Response")
+            return MockUpResponse(200, {}, body)
+
+    connection = get_connection()
+    connection._delegate_connection.resources.append(query_resource)
+
+    borrower, loan, box = _issue_loan_request(data)
+
+    assert str(loan.id) == "4567"
+    assert str(loan.get_property(BOX).value) == "2345"
+    assert str(loan.get_property(BORROWER).value) == str(borrower.id)
+    assert str(borrower.id) == "1234"
+    assert borrower.get_property(EMAIL).value == data[F_EMAIL]
+    assert borrower.get_property(FIRST_NAME).value == data[F_FIRST_NAME]
+    assert str(box.id) == "2345"
+    assert box.get_property(BOX_NUMBER).value == "0815"
diff --git a/caosdb-server/scripting/bin/test/loan_management/test_request_return.py b/caosdb-server/scripting/bin/test/loan_management/test_request_return.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa7f52c7379ec9e8066740573ecdb0289413af82
--- /dev/null
+++ b/caosdb-server/scripting/bin/test/loan_management/test_request_return.py
@@ -0,0 +1,134 @@
+from os.path import abspath, dirname, join
+from pytest import raises
+from caosdb import get_connection, configure_connection
+from caosdb.connection.mockup import (MockUpServerConnection, MockUpResponse)
+from caosadvancedtools.serverside.helper import get_data
+from box_loan import (FIRST_NAME, EMAIL, LAST_NAME, F_FIRST_NAME,
+                         F_LAST_NAME, F_EMAIL, EXPECTED_RETURN, LENT,
+                         RETURN_REQUESTED, PERSON, BORROWER, BOX,
+                         LOAN_REQUESTED, StateError, F_EXPECTED_RETURN_DATE,
+                         DataError, LOAN)
+from request_return import get_loan, _issue_return_request
+
+
+def setup():
+    configure_connection(url="unittests", username="testuser",
+                         password_method="plain",
+                         password="testpassword", timeout=200,
+                         implementation=MockUpServerConnection)
+
+
+def get_data_example():
+    return abspath(join(dirname(__file__), "request_loan_form.json"))
+
+
+def append_resource(resource):
+    connection = get_connection()
+    connection._delegate_connection.resources.append(resource)
+
+
+def test_get_loan():
+    entities = '<Response><Query results="1"/><Record id="1234"/></Response>'
+
+    def resource(**kwargs):
+        assert "RECORD%20Loan%20WITH%20ID%20%3D%201234" in kwargs["path"]
+        return MockUpResponse(200, {}, entities)
+    append_resource(resource)
+
+    loan = get_loan(1234)
+    assert loan.id == 1234
+
+
+def test_return_request_with_wrong_return_date():
+    data = get_data(get_data_example())
+    data[F_EXPECTED_RETURN_DATE] = "1983-02-03"
+    with raises(DataError):
+        _issue_return_request(data)
+
+    data[F_EXPECTED_RETURN_DATE] = "asdf"
+    with raises(DataError):
+        _issue_return_request(data)
+
+    data[F_EXPECTED_RETURN_DATE] = ""
+    with raises(DataError):
+        _issue_return_request(data)
+
+    del data[F_EXPECTED_RETURN_DATE]
+    with raises(DataError):
+        _issue_return_request(data)
+
+
+def test_return_request_with_wrong_loan_states():
+    data = get_data(get_data_example())
+    loan_xml = (
+        '<Response><Query results="1"/><Record id="12345">'
+        '<Parent name="{LO}"/>'
+        '<Property name="{ER}">1985-05-21</Property>'
+        '<Property name="{BOX}">2345</Property>'
+        '<Property name="{BOR}">1234</Property>'
+        '<Property name="{L_REQ}">2020-03-02</Property>'
+        '</Record></Response>').format(ER=EXPECTED_RETURN.name,
+                                       BOX=BOX.name, BOR=BORROWER.name,
+                                       L_REQ=LOAN_REQUESTED.name,
+                                       LO=LOAN.name)
+
+    def resource(**kwargs):
+        return MockUpResponse(200, {}, loan_xml)
+    append_resource(resource)
+
+    with raises(StateError):
+        _issue_return_request(data)
+
+
+def test_issue_return_request():
+    data = get_data(get_data_example())
+    person_xml = (
+        '<Response><Query results="1"/>'
+        '<Record id="1234">'
+        '<Property name="{FN}">{FIRST_NAME}</Property>'
+        '<Property name="{LN}">{LAST_NAME}</Property>'
+        '<Property name="{EM}">{EMAIL}</Property>'
+        '</Record>'
+        '</Response>').format(FN=FIRST_NAME.name, EM=EMAIL.name,
+                              LN=LAST_NAME.name, FIRST_NAME=data[F_FIRST_NAME],
+                              LAST_NAME=data[F_LAST_NAME], EMAIL=data[F_EMAIL])
+    loan_xml = (
+        '<Response><Query results="1"/><Record id="12345">'
+        '<Parent name="{LO}"/>'
+        '<Property name="{ER}">1985-05-21</Property>'
+        '<Property name="{BOX}">2345</Property>'
+        '<Property name="{BOR}">1234</Property>'
+        '<Property name="{LENT}">2020-03-02</Property>'
+        '{{RR}}'
+        '</Record></Response>').format(ER=EXPECTED_RETURN.name, BOX=BOX.name,
+                                       BOR=BORROWER.name, LENT=LENT.name,
+                                       LO=LOAN.name)
+
+    def resource(**kwargs):
+        if kwargs["method"] == "GET":
+            if "12345" in kwargs["path"]:
+                # retrieve loan
+                return MockUpResponse(200, {},
+                                      loan_xml.format(RR=""))
+
+            query = kwargs["path"].split("query=")[1]
+            assert query.startswith("FIND%20RECORD%20" + PERSON.name)
+            return MockUpResponse(200, {}, person_xml)
+        elif kwargs["method"] == "PUT":
+            assert RETURN_REQUESTED.name in kwargs["body"].decode("utf-8")
+            p = '<Property name="{RR}">asdf</Property>'.format(
+                RR=RETURN_REQUESTED.name)
+            return MockUpResponse(200, {}, loan_xml.format(RR=p))
+
+    append_resource(resource)
+
+    returner, loan = _issue_return_request(data)
+
+    assert loan.id == 12345
+    assert loan.get_property(BOX.name).value == "2345"
+    assert loan.get_property(BORROWER.name).value == str(returner.id)
+    assert loan.get_property(RETURN_REQUESTED.name).value == "asdf"
+
+    assert returner.id == 1234
+    assert returner.get_property(EMAIL.name).value == data[F_EMAIL]
+    assert returner.get_property(EMAIL.name).value == data[F_EMAIL]