diff --git a/pass/app/pdf/OrderReceipt.js b/pass/app/pdf/OrderReceipt.js index 513aacbc2895e38bfc752c21717fbbefbb8edbda..2a5534f1b4780c7d934e6893f40e796afcb5d329 100644 --- a/pass/app/pdf/OrderReceipt.js +++ b/pass/app/pdf/OrderReceipt.js @@ -24,15 +24,15 @@ class OrderReceipt { .fontSize(10); // The header with logo and line - doc.image("public/images/metager.png", letter_left_margin, 20, { + doc.image("public/images/metager.png", letter_left_margin, 30, { height: 20, }); - doc.image("public/images/suma-ev.png", 400, 22, { + doc.image("public/images/suma-ev.png", 400, 32, { height: 18, }); doc - .moveTo(letter_left_margin, 50) - .lineTo(OrderReceipt.CM_TO_POINTS(21, false) - letter_right_margin, 50) + .moveTo(letter_left_margin, 60) + .lineTo(OrderReceipt.CM_TO_POINTS(21, false) - letter_right_margin, 60) .strokeColor("#515151") .stroke(); @@ -51,7 +51,7 @@ class OrderReceipt { */ // General Information doc - .fontSize(10) + .fontSize(12) .text( "Bestellnummer: ", OrderReceipt.CM_TO_POINTS(21 - 8.5, false), @@ -96,16 +96,16 @@ class OrderReceipt { doc .moveTo( OrderReceipt.CM_TO_POINTS(2.5, false), - OrderReceipt.CM_TO_POINTS(12.5, true) + OrderReceipt.CM_TO_POINTS(12.6, true) ) .lineTo( OrderReceipt.CM_TO_POINTS(21 - 2, false), - OrderReceipt.CM_TO_POINTS(12.5, true) + OrderReceipt.CM_TO_POINTS(12.6, true) ) .strokeColor("#ff7f00") .stroke(); doc - .fontSize(10) + .fontSize(12) .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf") .text( "Auftragsbestätigung " + order.getOrderID(), @@ -147,12 +147,12 @@ class OrderReceipt { .text(order.getAmount() / 300, { width: OrderReceipt.CM_TO_POINTS(3.25, false), align: "right", - lineGap: 15, + lineGap: 8, }) .text("MwSt (7%)", { width: OrderReceipt.CM_TO_POINTS(3.25, false), align: "right", - lineGap: 10, + lineGap: 8, }) .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf") .text("Gesamtbetrag", { @@ -176,12 +176,12 @@ class OrderReceipt { .text(order.getNettoPrice() + " €", { width: OrderReceipt.CM_TO_POINTS(3.25, false), align: "right", - lineGap: 15, + lineGap: 8, }) .text(order.getVatAmount() + " €", { width: OrderReceipt.CM_TO_POINTS(3.25, false), align: "right", - lineGap: 10, + lineGap: 8, }) .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf") .text(order.getPrice() + " €", { @@ -191,6 +191,18 @@ class OrderReceipt { .font("public/fonts/liberation-sans/LiberationSans-Regular.ttf"); // Footer + doc + .moveTo( + OrderReceipt.CM_TO_POINTS(2.5, false), + OrderReceipt.CM_TO_POINTS(27.2, false) + ) + .lineTo( + OrderReceipt.CM_TO_POINTS(21 - 2, false), + OrderReceipt.CM_TO_POINTS(27.2, true) + ) + .strokeColor("#515151") + .stroke(); + let textbox_width = doc.widthOfString("Vorstand"); doc.fontSize(8); textbox_width = Math.max( @@ -202,7 +214,7 @@ class OrderReceipt { let x = OrderReceipt.CM_TO_POINTS(21 - 2, false) - textbox_width; doc .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf") - .text("Vorstand", x, OrderReceipt.CM_TO_POINTS(27.2, true), { + .text("Vorstand", x, OrderReceipt.CM_TO_POINTS(27.3, true), { lineBreak: false, }) .fontSize(8) @@ -227,8 +239,9 @@ class OrderReceipt { x = OrderReceipt.CM_TO_POINTS(2.5, false); doc + .fontSize(10) .font("public/fonts/liberation-sans/LiberationSans-Bold.ttf") - .text("SUMA-EV", x, OrderReceipt.CM_TO_POINTS(27.2, true), { + .text("SUMA-EV", x, OrderReceipt.CM_TO_POINTS(27.3, true), { lineBreak: false, }) .fontSize(8) diff --git a/pass/config/default.json b/pass/config/default.json index 75bd7fba4204f45ab906323ae995d9befc250844..7a4324c72283b80034aafa40b2e1a920e599d1ab 100644 --- a/pass/config/default.json +++ b/pass/config/default.json @@ -26,11 +26,9 @@ }, "payments": { "paypal": { - "development": { - "base": "https://api-m.sandbox.paypal.com", - "secret": "<INSERT_PAYPAL_APPLICATION_SECRET>", - "client_id": "<INSERT_PAYPAL_CLIENT_ID>" - } + "base": "https://api-m.sandbox.paypal.com", + "secret": "<INSERT_PAYPAL_APPLICATION_SECRET>", + "client_id": "<INSERT_PAYPAL_CLIENT_ID>" } } } \ No newline at end of file diff --git a/pass/public/styles/base.less b/pass/public/styles/base.less index e1b5f1a0d6c07e465b329f652b83946623557301..e33c56adaa5013ad3f935ad6f48eef9b3c53036d 100644 --- a/pass/public/styles/base.less +++ b/pass/public/styles/base.less @@ -51,6 +51,10 @@ html { display: none !important; } +.bold { + font-weight: bold; +} + .error { color: #ff5858; display: flex; diff --git a/pass/public/styles/orders.less b/pass/public/styles/orders.less index d12f277461086af46a88e5d839042432162dca02..e87f65320332c37473e3570373fae47620a7ed51 100644 --- a/pass/public/styles/orders.less +++ b/pass/public/styles/orders.less @@ -1,10 +1,29 @@ @import "./misc/vars.less"; #order { + padding: 1rem 0; + .breadcrumbs { + display: flex; + gap: 0.5rem; + padding: 0; + list-style-type: disclosure-closed; + font-size: clamp(0.7rem, 4w, 1rem); + li { + margin-left: 1rem; + &:first-child { + margin-left: 0; + list-style-type: none; + } + a { + color: #777; + } + } + } grid-area: content; #order-details { display: grid; grid-template-columns: 1fr 4rem 4rem; text-align: right; + padding: 2rem 0; > div { &.heading { text-align: left; @@ -41,5 +60,53 @@ filter: brightness(0) invert(1); } } + @media (max-width: 510px) { + flex-direction: column; + align-items: center; + } + } + + #invoice-form { + #invoice-form-fields { + display: grid; + gap: 1rem; + + .invoice-form-field { + display: grid; + gap: 0.5rem; + font-weight: bold; + color: #777; + font-size: 0.7rem; + place-content: center; + text-align: center; + #email { + padding: 0.5rem; + border-radius: 5px; + font-size: 0.8rem; + width: 13rem; + text-align: center; + } + #name-and-address { + padding: 0.5rem; + border-radius: 5px; + line-height: 2; + text-align: center; + width: 13rem; + } + button { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem; + img { + height: 1.2rem; + } + } + } + } + .storage-time { + font-size: 0.8rem; + text-align: center; + } } } diff --git a/pass/routes/orders.js b/pass/routes/orders.js index a8615e9522062979c5d53a7b18c8dc84be1c4a6f..b7b0360d8c818f75540512edf927597fed547895 100644 --- a/pass/routes/orders.js +++ b/pass/routes/orders.js @@ -9,7 +9,12 @@ const OrderReceipt = require("../app/pdf/OrderReceipt"); router.use("/:order_id", param("order_id").isInt(), (req, res, next) => { Order.LOAD_ORDER_FROM_ID(req.params.order_id) .then((order) => { - req.data.order = order; + req.data.css.push("/styles/orders.css"); + req.data.order = { order: order }; + req.data.order.orders_url = `/key/${req.data.key.key}/orders`; + req.data.order.order_url = `/key/${req.data.key.key}/orders/${req.params.order_id}#order`; + req.data.order.receipt_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/pdf`; + req.data.order.invoice_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/invoice#invoice-form`; next("route"); }) .catch((reason) => { @@ -18,17 +23,20 @@ router.use("/:order_id", param("order_id").isInt(), (req, res, next) => { }); router.get("/:order_id", (req, res) => { - req.data.css.push("/styles/orders.css"); - req.data.order_receipt_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/pdf`; res.render("key", req.data); }); router.get("/:order_id/pdf", (req, res) => { - let doc = OrderReceipt.CREATE_ORDER_RECEIPT(req.data.order, res); + let doc = OrderReceipt.CREATE_ORDER_RECEIPT(req.data.order.order, res); res.status(200).header({ "Content-Type": "application/pdf", }); doc.pipe(res); }); +router.get("/:order_id/invoice", (req, res) => { + req.data.order.invoice = true; + res.render("key", req.data); +}); + module.exports = router; diff --git a/pass/views/orders/order.ejs b/pass/views/orders/order.ejs index 9ff51b28c7755d4188a9ae546c3011b217cbe384..bacb85f78f79445dcc2d542f6f2bfa0ef7199a15 100644 --- a/pass/views/orders/order.ejs +++ b/pass/views/orders/order.ejs @@ -1,28 +1,65 @@ <div id="order"> - <h2>Ihre Bestellung Nr. <%= order.getOrderID() %></h2> + <%_ if(!order.invoice) { _%> + <h2>Ihre Bestellung Nr. <%= order.order.getOrderID() %></h2> + <ul class="breadcrumbs"> + <li><a href="<%= order.orders_url %>">Bestellungen</a></li> + <li><%= order.order.getOrderID() %></li> + </ul> <div id="order-details"> <div class="heading item">Bestelldetails</div> <div class="heading count">Anzahl</div> <div class="heading price">Preis</div> <div class="item">MetaGer Schlüssel: Suchanfragen (300x)</div> - <div class="count"><%= order.getAmount() / 300 %></div> - <div class="price"><%= order.getNettoPrice() %> €</div> - <div class="item">MwSt. (<%= order.getVat() %> %)</div> + <div class="count"><%= order.order.getAmount() / 300 %></div> + <div class="price"><%= order.order.getNettoPrice() %> €</div> + <div class="item">MwSt. (<%= order.order.getVat() %> %)</div> <div class="count"></div> - <div class="price"><%= order.getVatAmount() %> €</div> + <div class="price"><%= order.order.getVatAmount() %> €</div> <div class="item sum">Gesamtbetrag</div> <div class="count"></div> - <div class="price"><%= order.getPrice() %> €</div> + <div class="price"><%= order.order.getPrice() %> €</div> </div> <h3>Vielen Dank für Ihren Einkauf!</h3> <div id="order-buttons"> - <a href="<%= order_receipt_url %>" target="_blank" class="button"> + <a href="<%= order.receipt_url %>" target="_blank" class="button"> <img src="/images/download.svg" alt="" /> <span>Auftragsbestätigung herunterladen</span> </a> - <a href="#" class="button"> + <a href="<%= order.invoice_url %>" class="button"> <img src="/images/invoice.svg" alt="" /> <span>Rechnung beantragen</span> </a> </div> + <%_ } else { _%> + <form action="POST" id="invoice-form"> + <h2>Rechnung</h2> + <ul class="breadcrumbs"> + <li><a href="<%= order.orders_url %>">Bestellungen</a></li> + <li><a href="<%= order.order_url %>"><%= order.order.getOrderID() %></a></li> + <li>Rechnung</li> + </ul> + <p> + Wenn Sie eine Rechnung benötigen, tragen Sie bitte Ihre Rechnungsdaten in das nachfolgende Formular ein. Wir benötigen von Ihnen dafür Ihren vollständigen Namen, Ihre postalische Anschrift und Ihre E-Mail Adresse um Ihnen die Rechnung zuzustellen. + </p> + <div id="invoice-form-fields"> + <div class="invoice-form-field"> + <label for="email">E-Mail*</label> + <input type="email" name="email" id="email" placeholder="test@example.com" required> + </div> + <div class="invoice-form-field"> + <label for="name-and-address">Name & Anschrift*</label> + <textarea name="name-and-address" id="name-and-address" cols="30" rows="4" placeholder="Max Mustermann Mustergasse 3 30159 Musterstadt Deutschland" required></textarea> + </div> + <div class="invoice-form-field"> + <button type="submit" class="button"> + <img src="/images/invoice.svg" alt="" /> + <span>Rechnung beantragen</span> + </button> + </div> + </div> + <p class="storage-time"> + Wir sind rechtlich dazu verpflichtet einmal ausgestellte Rechnungen <span class="bold">10 Jahre</span> lang aufzubewahren. Da eine Rechnung auf Sie persönlich ausgestellt sein muss, enthält sie zwangsläufig personenbeziehbare Daten (Name, Anschrift, E-Mail). + </p> + </form> + <%_ } _%> </div> \ No newline at end of file