Wave Reconciliation-Reviewed

Adding Ability to see reviewed transactions on the reconciliation page

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Wave Reconciliation-Reviewed
// @description  Adding Ability to see reviewed transactions on the reconciliation page
// @author       Seth Parrish
// @namespace    https://sethp.cc
// @version      0.5
// @icon         https://raw.githubusercontent.com/xthexder/wide-github/master/icon.png
// @homepageURL  https://greasyfork.org/en/scripts/394287-wave-reconciliation-reviewed
// @supportURL   https://greasyfork.org/en/scripts/394287-wave-reconciliation-reviewed
// @match        https://next.waveapps.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_addStyle
// @license      GPL-3.0-only
// ==/UserScript==
"use strict";

// Global Vars & Storage Object
// var d = document
// var b = d.body
var DBNAME = "reviewed_db";
var db = GM_getValue(DBNAME) || [];
console.log("DB:", db);

// Add GM DB deletion option
GM_registerMenuCommand("Clear Stored Data", () => {
  var shouldClear = confirm(
    'Do you want to clear the "seen" reviewed transactions? (this will not effect data in wave)'
  );
  if (shouldClear) {
    db = [];
    GM_setValue(DBNAME, db);
    GM_deleteValue(DBNAME);
    console.log("DB:", db);
  }
});

// Add 'unmatch all' button
GM_registerMenuCommand("Unmatch All Transactions on screen", () => {
  var shouldGo = confirm(
    "Do you want to unmatch all the transactions currently on the page?"
  );
  if (shouldGo) {
    var className = "account-recv2__reconciliation__table__matched-icon--true";
    var icons = Array.from(document.getElementsByClassName(className));
    icons.forEach(function (x) {
      x.click();
    });
    console.log("Finished Unmatching Transactions");
  }
});

// Find transaction from reconciliaton
var lastPicked = "";

function findTransaction() {
  if (lastPicked != "") {
    var url = window.location.href.split("account-")[0];
    window.open(url + "transactions/" + lastPicked);
  } else {
    alert("You haven't picked a transaction yet");
  }
  console.log("Looking for transaction");
}

GM_registerMenuCommand("Find Transaction", () => {
  findTransaction();
});

// Adding Custom CSS
GM_addStyle(
  ".account-recv2__reconciliation__table__reviewed--true {background: #dec9ff !important;color: #849194 !important;}"
);

// Check for Reviewed Status and add to the DB
function processLatestTransactions(res) {
  var isReviewed = (x) => Boolean(x.transaction_status.value);
  var isInDB = (x) => db.some((e) => e.transaction_guid === x.transaction_guid);
  res.latest_transactions.forEach((x) => {
    if (isReviewed(x) && !isInDB(x)) {
      db.push(x);
    }
  });
  GM_setValue(DBNAME, db);
  console.log("DB: ", db);
}

// Handle changing the status of a single transaction
function processTransactionStatusChange(res) {
  // Do not run if we are marking as reviewed (other case handles)
  if (res.transaction_status.value) {
    return;
  }
  for (var i = 0; i < db.length; i++) {
    if (db[i].transaction_guid === res.guid) {
      db.splice(i, 1);
    }
  }
  GM_setValue("reviewed_db", db);
  console.log("DB: ", db);
}

// Utility function to apply custom css to a row with matching data
function turnGreen(date, desc, price_formatted) {
  var datedRows = Array.apply(
    null,
    document.querySelectorAll(`time[datetime="${date}"]`)
  ).map(function (x) {
    return x.parentNode.parentElement.parentElement.parentElement.parentElement;
  });
  if (datedRows.length === 0) {
    return;
  }
  var el = datedRows.find(function (x) {
    var txt = x.textContent; // Eg. "Nov 29, 2019Steam Games$13.90$1,568.22"
    return (
      txt.includes(date.split("-")[0]) &&
      txt.includes(desc) &&
      txt.includes(price_formatted)
    );
  });
  el.className += " account-recv2__reconciliation__table__reviewed--true ";
}

// Iterate DB and apply styles
function processReconciliationPage(res) {
  // Deal with this page's transaction data
  // var matched = res.transactions.filter(x => Boolean(x.is_matched))
  db.forEach(function (x) {
    turnGreen(
      x.transaction_date,
      x.transaction_description,
      x.transaction_total.transaction.formatted_string
    );
  });
}

// HTTP Listener
(function (open) {
  XMLHttpRequest.prototype.open = function () {
    this.addEventListener(
      "readystatechange",
      function () {
        var json = this.responseText ? JSON.parse(this.responseText) : {};
        var doneAndIncludes = (x) =>
          this.readyState === 4 && this.responseURL.includes(x);

        if (doneAndIncludes("/transactions/latest/")) {
          // Check for a finished request dealing with latest transactions
          processLatestTransactions(json);
        } else if (doneAndIncludes("/transactions/status/")) {
          // Check for a finished request, marking a transaction as "un-reviewed"
          processTransactionStatusChange(json);
        } else if (
          doneAndIncludes("/account_reconciliation/reconciliation_by_period/")
        ) {
          // Check for a finished request dealing with reconciliation transactions
          processReconciliationPage(json);
        } else if (
          doneAndIncludes("transactions/") &&
          this.responseURL.split("/").length == 8
        ) {
          // Grab last (selected) transaction and save to variable
          lastPicked = this.responseURL.split("/")[6];
          console.log("Last Picked Updated: ", lastPicked);
        }
      },
      false
    );
    open.apply(this, arguments);
  };
})(XMLHttpRequest.prototype.open);

// Keyboard Listener
function keyPress(e) {
  // this would test for whichever key is alt and the ctrl key at the same time
  if (e.ctrlKey && e.keyCode == 18) {
    findTransaction();
  }
}

// register the handler
document.addEventListener("keydown", keyPress);

// The End :)