From 3196debe172b3b1d87c7dd541738f56212d3d4ac Mon Sep 17 00:00:00 2001
From: Dominik Hebeler <dominik@suma-ev.de>
Date: Mon, 14 Nov 2022 14:20:10 +0100
Subject: [PATCH] loading purchase data from stored order

---
 pass/app/Order.js                | 62 ++++++++++++++++++++++++++------
 pass/resources/js/checkout.js    |  8 +++--
 pass/routes/checkout/checkout.js |  2 +-
 pass/routes/checkout/paypal.js   | 61 +++++++++++++++++++++++++------
 4 files changed, 107 insertions(+), 26 deletions(-)

diff --git a/pass/app/Order.js b/pass/app/Order.js
index 8390709..93fa3b6 100644
--- a/pass/app/Order.js
+++ b/pass/app/Order.js
@@ -5,6 +5,11 @@ class Order {
   static get STORAGE_KEY_PREFIX() {
     return "order_";
   }
+
+  static get PURCHASE_TAX_AMOUNT() {
+    return 0.07;
+  }
+
   static get PURCHASE_STORAGE_TIME_MONTHS() {
     return 6;
   }
@@ -30,6 +35,7 @@ class Order {
   #price_per_unit;
   #encrypted_sales_receipts;
   #payment_completed;
+  #payment_method_link; // Stores a link to an entry of the payment methods payment i.e. PayPal order id
 
   /**
    * Data populated by context
@@ -44,10 +50,10 @@ class Order {
     price_per_unit,
     encrypted_sales_receipts
   ) {
-    this.#order_id = order_id;
-    this.#amount = amount;
-    this.#unit_size = unit_size;
-    this.#price_per_unit = price_per_unit;
+    this.#order_id = parseInt(order_id);
+    this.#amount = parseInt(amount);
+    this.#unit_size = parseInt(unit_size);
+    this.#price_per_unit = parseFloat(price_per_unit);
     this.#encrypted_sales_receipts = encrypted_sales_receipts;
 
     this.#payment_completed = false;
@@ -59,15 +65,48 @@ class Order {
     });
   }
 
+  set_create_mode(create_mode) {
+    this.#create_mode = create_mode;
+  }
+
+  getAmount() {
+    return this.#amount;
+  }
+
+  getPricePerUnit() {
+    return this.#price_per_unit;
+  }
+
+  setPaymentMethodLink(payment_method_link) {
+    this.#payment_method_link = payment_method_link;
+  }
+
   static async LOAD_ORDER_FROM_ID(order_id) {
-    let Redis = require("ioredis");
-    let redis_client = new Redis({
-      host: config.get("redis.host"),
-    });
+    return new Promise((resolve, reject) => {
+      let Redis = require("ioredis");
+      let redis_client = new Redis({
+        host: config.get("redis.host"),
+      });
 
-    let redis_key = Order.STORAGE_KEY_PREFIX + order_id;
-    let order_data = await redis_client.hgetall(redis_key);
-    console.log(order_data);
+      let redis_key = Order.STORAGE_KEY_PREFIX + order_id;
+      redis_client.hgetall(redis_key).then((order_data) => {
+        if (Object.keys(order_data).length === 0) {
+          return reject("Could not find Order in our database!");
+        }
+        let loaded_order = new Order(
+          order_data.order_id,
+          order_data.amount,
+          order_data.unit_size,
+          order_data.price_per_unit,
+          order_data.encrypted_sales_receipts
+        );
+        if (order_data.payment_method_link) {
+          loaded_order.setPaymentMethodLink(order_data.payment_method_link);
+        }
+        loaded_order.set_create_mode(false);
+        resolve(loaded_order);
+      });
+    });
   }
 
   async save() {
@@ -93,6 +132,7 @@ class Order {
         price_per_unit: this.#price_per_unit,
         encrypted_sales_receipts: this.#encrypted_sales_receipts,
         payment_completed: this.#payment_completed,
+        payment_method_link: this.#payment_method_link,
       })
       .then((result) => {
         this.#create_mode = false;
diff --git a/pass/resources/js/checkout.js b/pass/resources/js/checkout.js
index 12266d9..1d4b654 100644
--- a/pass/resources/js/checkout.js
+++ b/pass/resources/js/checkout.js
@@ -61,9 +61,11 @@ function execute_payment_paypal(e) {
               body: JSON.stringify({
                 order_id: document.querySelector("input[name=order_id]").value,
                 amount: document.querySelector("input[name=amount]").value,
-                unit_size: document.querySelector("input[name=unit_size]"),
-                price_per_unit:
-                  document.querySelector("input[name=price]").value,
+                unit_size: document.querySelector("input[name=unit_size]")
+                  .value,
+                price_per_unit: document.querySelector(
+                  "input[name=price_per_unit]"
+                ).value,
                 public_key_n: document.querySelector("input[name=public_key_n]")
                   .value,
                 public_key_e: document.querySelector("input[name=public_key_e]")
diff --git a/pass/routes/checkout/checkout.js b/pass/routes/checkout/checkout.js
index 6e295ca..e71c0df 100644
--- a/pass/routes/checkout/checkout.js
+++ b/pass/routes/checkout/checkout.js
@@ -57,7 +57,7 @@ router.get(
 router.use(
   "/payment/order",
   body("amount")
-    .isInt({ min: 1, max: 4 })
+    .isInt({ min: 1, max: 12 })
     .withMessage("Invalid amount submitted")
     .toInt(),
   body("unit_size").isIn(["100", "250"]).toInt(),
diff --git a/pass/routes/checkout/paypal.js b/pass/routes/checkout/paypal.js
index b2b2451..a25d26b 100644
--- a/pass/routes/checkout/paypal.js
+++ b/pass/routes/checkout/paypal.js
@@ -2,6 +2,7 @@ var express = require("express");
 var router = express.Router();
 
 const config = require("config");
+const Order = require("../../app/Order.js");
 
 const CLIENT_ID = config.get("payments.paypal.testing.client_id");
 const APP_SECRET = config.get("payments.paypal.testing.secret");
@@ -9,9 +10,13 @@ const base = "https://api-m.sandbox.paypal.com";
 
 /* Client initiates payment */
 router.post("/", async (req, res, next) => {
-  // All Submitted data is verified at this point
-  const order = await createOrder(req);
-  res.json(order);
+  Order.LOAD_ORDER_FROM_ID(req.body.order_id)
+    .then((order) => {
+      createOrder(order).then((order_result) => res.json(order_result));
+    })
+    .catch((error) => {
+      return res.status(400).json({ errors: [{ msg: error }] });
+    });
 });
 
 module.exports = router;
@@ -24,10 +29,17 @@ module.exports = router;
 
 // use the orders api to create an order
 
-async function createOrder(req) {
+async function createOrder(loaded_order) {
+  console.log(loaded_order);
   const accessToken = await generateAccessToken();
 
   const url = `${base}/v2/checkout/orders`;
+  let tax_amount_per_unit = (
+    loaded_order.getPricePerUnit().toFixed(2) * Order.PURCHASE_TAX_AMOUNT
+  ).toFixed(2);
+  let item_amount_per_unit = (
+    loaded_order.getPricePerUnit().toFixed(2) - tax_amount_per_unit
+  ).toFixed(2);
 
   let order = {
     intent: "CAPTURE",
@@ -37,13 +49,39 @@ async function createOrder(req) {
         description: "MetaGer Pass Einkauf",
         amount: {
           currency_code: "EUR",
-          value: req.body.price.toFixed(2),
+          value:
+            item_amount_per_unit * loaded_order.getAmount() +
+            tax_amount_per_unit * loaded_order.getAmount(),
+          breakdown: {
+            item_total: {
+              currency_code: "EUR",
+              value: (item_amount_per_unit * loaded_order.getAmount()).toFixed(
+                2
+              ),
+            },
+            tax_total: {
+              currency_code: "EUR",
+              value: (tax_amount_per_unit * loaded_order.getAmount()).toFixed(
+                2
+              ),
+            },
+          },
         },
         items: [
           {
-            name: "MetaGer Pass: Suchanfragen (100x)",
-            quantity: 1,
-            unit_amount: 0,
+            name: "MetaGer Pass: Suchanfragen (250x)",
+            quantity: loaded_order.getAmount(),
+            unit_amount: {
+              currency_code: "EUR",
+              value: item_amount_per_unit,
+            },
+            tax: {
+              currency_code: "EUR",
+              value: tax_amount_per_unit,
+            },
+            category: "DIGITAL_GOODS",
+            description:
+              "MetaGer Pass Suchanfragen zur Nutzung der Suchmaschine MetaGer",
           },
         ],
       },
@@ -53,7 +91,6 @@ async function createOrder(req) {
       shipping_preference: "NO_SHIPPING",
     },
   };
-  console.log(order.purchase_units[0].amount);
 
   const response = await fetch(url, {
     method: "post",
@@ -67,8 +104,10 @@ async function createOrder(req) {
   });
 
   const data = await response.json();
-
-  return data;
+  loaded_order.setPaymentMethodLink({ id: data.id });
+  return loaded_order.save().then(() => {
+    return data;
+  });
 }
 
 // use the orders api to capture payment for an order
-- 
GitLab