enhanced loan management: added note field to loan creation and email templates

This commit is contained in:
2026-02-20 12:14:56 +01:00
parent a8dab549af
commit ee54d51f8b
3 changed files with 73 additions and 35 deletions

View File

@@ -22,7 +22,7 @@ export const getItemsFromDatabaseV2 = async () => {
export const getLoanByCodeV2 = async (loan_code) => { export const getLoanByCodeV2 = async (loan_code) => {
const [result] = await pool.query( const [result] = await pool.query(
"SELECT username, returned_date, take_date, lockers FROM loans WHERE loan_code = ?;", "SELECT username, returned_date, take_date, lockers FROM loans WHERE loan_code = ?;",
[loan_code] [loan_code],
); );
if (result.length > 0) { if (result.length > 0) {
return { success: true, data: result[0] }; return { success: true, data: result[0] };
@@ -33,7 +33,7 @@ export const getLoanByCodeV2 = async (loan_code) => {
export const changeInSafeStateV2 = async (itemId) => { export const changeInSafeStateV2 = async (itemId) => {
const [result] = await pool.query( const [result] = await pool.query(
"UPDATE items SET in_safe = NOT in_safe WHERE id = ?", "UPDATE items SET in_safe = NOT in_safe WHERE id = ?",
[itemId] [itemId],
); );
if (result.affectedRows > 0) { if (result.affectedRows > 0) {
return { success: true }; return { success: true };
@@ -42,47 +42,48 @@ export const changeInSafeStateV2 = async (itemId) => {
}; };
export const setReturnDateV2 = async (loanCode) => { export const setReturnDateV2 = async (loanCode) => {
const [items] = await pool.query( try {
"SELECT loaned_items_id FROM loans WHERE loan_code = ?", const [items] = await pool.query(
[loanCode] "SELECT loaned_items_id, username FROM loans WHERE loan_code = ?",
); [loanCode],
);
const [owner] = await pool.query( if (items.length === 0) return { success: false };
"SELECT username FROM loans WHERE loan_code = ?",
[loanCode]
);
if (items.length === 0) return { success: false }; const itemIds = Array.isArray(items[0].loaned_items_id)
? items[0].loaned_items_id
: JSON.parse(items[0].loaned_items_id || "[]");
const itemIds = Array.isArray(items[0].loaned_items_id) const [result] = await pool.query(
? items[0].loaned_items_id "UPDATE loans SET returned_date = NOW() WHERE loan_code = ? AND returned_date IS NULL",
: JSON.parse(items[0].loaned_items_id || "[]"); [loanCode],
);
const [setItemStates] = await pool.query( if (result.affectedRows === 0) return { success: false };
"UPDATE items SET in_safe = 1, currently_borrowing = NULL, last_borrowed_person = (?) WHERE id IN (?)",
[owner[0].username, itemIds]
);
const [result] = await pool.query( if (itemIds.length > 0) {
"UPDATE loans SET returned_date = NOW() WHERE loan_code = ?", await pool.query(
[loanCode] "UPDATE items SET in_safe = 1, currently_borrowing = NULL, last_borrowed_person = ? WHERE id IN (?)",
); [items[0].username, itemIds],
);
}
if (result.affectedRows > 0 && setItemStates.affectedRows > 0) { return { success: true, data: { returned: true } };
return { success: true }; } catch (error) {
console.error("setReturnDateV2 error:", error);
return { success: false };
} }
return { success: false };
}; };
export const setTakeDateV2 = async (loanCode) => { export const setTakeDateV2 = async (loanCode) => {
const [items] = await pool.query( const [items] = await pool.query(
"SELECT loaned_items_id FROM loans WHERE loan_code = ?", "SELECT loaned_items_id FROM loans WHERE loan_code = ?",
[loanCode] [loanCode],
); );
const [owner] = await pool.query( const [owner] = await pool.query(
"SELECT username FROM loans WHERE loan_code = ?", "SELECT username FROM loans WHERE loan_code = ?",
[loanCode] [loanCode],
); );
if (items.length === 0) return { success: false }; if (items.length === 0) return { success: false };
@@ -93,12 +94,12 @@ export const setTakeDateV2 = async (loanCode) => {
const [setItemStates] = await pool.query( const [setItemStates] = await pool.query(
"UPDATE items SET in_safe = 0, currently_borrowing = (?) WHERE id IN (?)", "UPDATE items SET in_safe = 0, currently_borrowing = (?) WHERE id IN (?)",
[owner[0].username, itemIds] [owner[0].username, itemIds],
); );
const [result] = await pool.query( const [result] = await pool.query(
"UPDATE loans SET take_date = NOW() WHERE loan_code = ?", "UPDATE loans SET take_date = NOW() WHERE loan_code = ?",
[loanCode] [loanCode],
); );
if (result.affectedRows > 0 && setItemStates.affectedRows > 0) { if (result.affectedRows > 0 && setItemStates.affectedRows > 0) {
@@ -118,12 +119,12 @@ export const getAllLoansV2 = async () => {
export const openDoor = async (doorKey) => { export const openDoor = async (doorKey) => {
const [result] = await pool.query( const [result] = await pool.query(
"SELECT safe_nr, id FROM items WHERE door_key = ?;", "SELECT safe_nr, id FROM items WHERE door_key = ?;",
[doorKey] [doorKey],
); );
if (result.length > 0) { if (result.length > 0) {
const [changeItemSate] = await pool.query( const [changeItemSate] = await pool.query(
"UPDATE items SET in_safe = NOT in_safe WHERE id = ?", "UPDATE items SET in_safe = NOT in_safe WHERE id = ?",
[result[0].id] [result[0].id],
); );
if (changeItemSate.affectedRows > 0) { if (changeItemSate.affectedRows > 0) {
return { success: true, data: result[0] }; return { success: true, data: result[0] };

View File

@@ -62,6 +62,7 @@ router.post("/createLoan", authenticate, async (req, res) => {
mailInfo.data.start_date, mailInfo.data.start_date,
mailInfo.data.end_date, mailInfo.data.end_date,
mailInfo.data.created_at, mailInfo.data.created_at,
mailInfo.data.note,
); );
return res.status(201).json({ return res.status(201).json({
message: "Loan created successfully", message: "Loan created successfully",

View File

@@ -34,7 +34,14 @@ const formatDateTime = (value) => {
return "N/A"; return "N/A";
}; };
function buildLoanEmail({ user, items, startDate, endDate, createdDate }) { function buildLoanEmail({
user,
items,
startDate,
endDate,
createdDate,
note,
}) {
const brand = process.env.MAIL_BRAND_COLOR || "#0ea5e9"; const brand = process.env.MAIL_BRAND_COLOR || "#0ea5e9";
const itemsList = const itemsList =
Array.isArray(items) && items.length Array.isArray(items) && items.length
@@ -116,6 +123,12 @@ function buildLoanEmail({ user, items, startDate, endDate, createdDate }) {
createdDate, createdDate,
)}</td> )}</td>
</tr> </tr>
<tr>
<td style="padding:10px 14px; color:#6b7280; vertical-align:top;">Notiz</td>
<td style="padding:10px 14px; font-weight:600; color:#111827;">${
note || "Keine Notiz"
}</td>
</tr>
</tbody> </tbody>
</table> </table>
<p style="margin:22px 0 0 0; font-size:14px;"> <p style="margin:22px 0 0 0; font-size:14px;">
@@ -134,7 +147,14 @@ function buildLoanEmail({ user, items, startDate, endDate, createdDate }) {
</html>`; </html>`;
} }
function buildLoanEmailText({ user, items, startDate, endDate, createdDate }) { function buildLoanEmailText({
user,
items,
startDate,
endDate,
createdDate,
note,
}) {
const itemsText = const itemsText =
Array.isArray(items) && items.length ? items.join(", ") : "N/A"; Array.isArray(items) && items.length ? items.join(", ") : "N/A";
return [ return [
@@ -145,10 +165,18 @@ function buildLoanEmailText({ user, items, startDate, endDate, createdDate }) {
`Start: ${formatDateTime(startDate)}`, `Start: ${formatDateTime(startDate)}`,
`Ende: ${formatDateTime(endDate)}`, `Ende: ${formatDateTime(endDate)}`,
`Erstellt am: ${formatDateTime(createdDate)}`, `Erstellt am: ${formatDateTime(createdDate)}`,
`Notiz: ${note || "Keine Notiz"}`,
].join("\n"); ].join("\n");
} }
export function sendMailLoan(user, items, startDate, endDate, createdDate) { export function sendMailLoan(
user,
items,
startDate,
endDate,
createdDate,
note,
) {
const transporter = nodemailer.createTransport({ const transporter = nodemailer.createTransport({
host: process.env.MAIL_HOST, host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT, port: process.env.MAIL_PORT,
@@ -170,8 +198,16 @@ export function sendMailLoan(user, items, startDate, endDate, createdDate) {
startDate, startDate,
endDate, endDate,
createdDate, createdDate,
note,
}),
html: buildLoanEmail({
user,
items,
startDate,
endDate,
createdDate,
note,
}), }),
html: buildLoanEmail({ user, items, startDate, endDate, createdDate }),
}); });
console.log("Loan message sent:", info.messageId); console.log("Loan message sent:", info.messageId);