Rukhhhhh's Pet Projects

Hey there, I'm your friendly neighborhood Cyber-Man

Download as .zip Download as .tar.gz View on GitHub

iOS Financial Tracker

I came up with this Financial Tracker as I got tired of manually logging my daily expenses into a sheet. I thought that the best quality of life improvement would be to be able to run a logging script using the iPhone Shortcuts app. The input will be the Action button in iPhone 15 & above. This project is not documented in full; the full capability consists of it exporting each sheet at the end of each month to an annual expense tracker.

Table of Contents

iOS Shortcuts

Using the shortcuts app and a little bit of research, I came up with a script that runs when activated with the action button.

〔0〕 Text
Sharukh Khan

〔1〕 Choose from Menu
• MenuPrompt: Expense or Income:\u{space}
• MenuItems: [Expense,
Income]

〔2〕 Menu Item Expense

〔3〕 Text »
expense

〔4〕 Set Variable expenditure to 〔3 Text〕

〔5〕 Choose from Menu
• MenuPrompt: Category:\u{space}
• MenuItems: [Transportation,
Food,
Entertainment,
Bills,
Gifts,
Personal,
Health,
Travel,
Miscellaneous\u{space}]

〔6〕 Menu Item Transportation

〔7〕 Text »
Transportation

〔8〕 Set Variable category to 〔7 Text〕

〔9〕 Menu Item Food

〔10〕 Text »
Food

〔11〕 Set Variable category to 〔10 Text〕

〔12〕 Menu Item Entertainment

〔13〕 Text »
Entertainment

〔14〕 Set Variable category to 〔13 Text〕

〔15〕 Menu Item Bills

〔16〕 Text »
Bills

〔17〕 Set Variable category to 〔16 Text〕

〔18〕 Menu Item Gifts

〔19〕 Text »
Gifts

〔20〕 Set Variable category to 〔19 Text〕

〔21〕 Menu Item Personal

〔22〕 Text »
Personal

〔23〕 Set Variable category to 〔22 Text〕

〔24〕 Menu Item Health

〔25〕 Text »
Health

〔26〕 Set Variable category to 〔25 Text〕

〔27〕 Menu Item Travel

〔28〕 Text »
Travel

〔29〕 Set Variable category to 〔28 Text〕

〔30〕 Menu Item Miscellaneous\u{space}

〔31〕 Text »
Other

〔32〕 Set Variable category to 〔31 Text〕

〔33〕 End Menu

〔34〕 Menu Item Income ▵2

〔35〕 Text »
income

〔36〕 Set Variable expenditure to 〔35 Text〕

〔37〕 Choose from Menu
• MenuPrompt: Select:\u{space}
• MenuItems: [Savings,
Salary,
PayNow / Bank Transfer,
Deposit,
Bonus,
Other]

〔38〕 Menu Item Savings

〔39〕 Text »
Savings

〔40〕 Set Variable category to 〔39 Text〕

〔41〕 Menu Item Salary

〔42〕 Text »
Salary

〔43〕 Set Variable category to 〔42 Text〕

〔44〕 Menu Item PayNow / Bank Transfer

〔45〕 Text »
PayNow

〔46〕 Set Variable category to 〔45 Text〕

〔47〕 Menu Item Deposit

〔48〕 Text »

〔49〕 Set Variable category to 〔48 Text〕

〔50〕 Menu Item Bonus

〔51〕 Text »
Bonus

〔52〕 Set Variable category to 〔51 Text〕

〔53〕 Menu Item Other

〔54〕 Text »
Other

〔55〕 Set Variable category to 〔54 Text〕

〔56〕 End Menu

〔57〕 End Menu ▵34

〔58〕 Ask for Number Input »
• AskActionAllowsNegativeNumbers: false
• AskActionPrompt: Amount?

〔59〕 Set Variable amount to 〔58 Ask for Input〕

〔60〕 If 〔expenditure〕 is income

〔61〕 If Any are true 〔category〕 is Savings 〔category〕 is Salary 〔category〕 is Bonus

〔62〕 Text »
Bank%20Transfer

〔63〕 Set Variable account to 〔62 Text〕

〔64〕 End If

〔65〕 If 〔category〕 is PayNow

〔66〕 Text »
PayNow

〔67〕 Set Variable account to 〔66 Text〕

〔68〕 End If

〔69〕 If 〔category〕 is Deposit

〔70〕 Text »
Cash

〔71〕 Set Variable account to 〔70 Text〕

〔72〕 End If

〔73〕 If 〔category〕 is Other

〔74〕 Choose from Menu
• MenuPrompt: Mode:\u{space}
• MenuItems: [PayNow,
Bank Transfer,
Cash]

〔75〕 Menu Item PayNow

〔76〕 Text »
PayNow

〔77〕 Set Variable account to 〔76 Text〕

〔78〕 Menu Item Bank Transfer

〔79〕 Text »
Bank Transfer

〔80〕 Set Variable account to 〔79 Text〕

〔81〕 Menu Item Cash

〔82〕 Text »
Cash

〔83〕 Set Variable account to 〔82 Text〕

〔84〕 End Menu

〔85〕 End If ▵73

〔86〕 Otherwise ▵60

〔87〕 Choose from Menu
• MenuPrompt: Payment Mode:\u{space}
• MenuItems: [NetsQR,
PayNow,
Visa,
Cash]

〔88〕 Menu Item NetsQR

〔89〕 Text »
NetsQR

〔90〕 Set Variable account to 〔89 Text〕

〔91〕 Menu Item PayNow

〔92〕 Text »
PayNow

〔93〕 Set Variable account to 〔92 Text〕

〔94〕 Menu Item Visa

〔95〕 Text »
Visa

〔96〕 Set Variable account to 〔95 Text〕

〔97〕 Menu Item Cash

〔98〕 Text »
Cash

〔99〕 Set Variable account to 〔98 Text〕

〔100〕 End Menu

〔101〕 End If ▵86

〔102〕 Ask for Text Input »
• AskActionPrompt: Description:\u{space}
• AskActionDefaultAnswer: 

〔103〕 Get Text from 〔102 Ask for Input〕 »

〔104〕 URL Encode 〔103 Text〕 »

〔105〕 Set Variable detail to 〔104 URL Encoded Text〕

〔106〕 Text »
REDACTED ON PURPOSE

〔107〕 Set Variable webappid to 〔106 Text〕

〔108〕 Text »
https://script.google.com/macros/s/〔webappid〕/exec?amount=〔amount as Text〕&expenditure=〔expenditure〕&account=〔account as Text〕&category=〔category as Text〕&detail=〔detail〕

〔109〕 Get URLs from 〔108 Text〕 »

〔110〕 Get Contents of URL 〔109 URLs〕 »
• Advanced: true
• HTTPHeaders: {}
• ShowHeaders: true
• HTTPMethod: GET

〔111〕 Show Result
〔110 Contents of URL〕

〔112〕 Vibrate Device
• VibrateHapticType: Up Direction

Google Sheets

Next, we write an Apps Script that will handle the data passed to the API.

var spreadsheet = SpreadsheetApp.openById("REDACTED ON PURPOSE");

function doGet(e) {
  try {
    var amount = e.parameters.amount[0]; 
    var mode = e.parameters.expenditure[0].toLowerCase();
    var account = e.parameters.account[0];
    var category = e.parameters.category[0];
    var detail = e.parameters.detail[0];
    var now = new Date();
    var date = Utilities.formatDate(now, "GMT+8", "dd/MM/yyyy");

    var sheetName = "Transactions";
    var sheet = spreadsheet.getSheetByName(sheetName);
    if (!sheet) {
      throw new Error("Sheet not found");
    }

    var startRow = 5;
    var rowToWrite;


    function findFirstEmptyRow(sheet, startRow, column) {
    var lastRow = sheet.getLastRow();
    if (lastRow < startRow) {
      return startRow;
    }
    var numRows = lastRow - startRow + 1;
    var values = sheet.getRange(startRow, column, numRows, 1).getValues();

    for (var i = 0; i < values.length; i++) {
      if (!values[i][0]) { // empty cell found
        return startRow + i;
      }
    }
    return lastRow + 1;
    }

    if (mode === "expense") {
      rowToWrite = findFirstEmptyRow(sheet, startRow, 2); // Column B = 2
      sheet.getRange(rowToWrite, 2, 1, 5).setValues([[date, amount, detail, category, account]]);
      return ContentService.createTextOutput("Success! Expense row added.");
    } else if (mode === "income") {
      rowToWrite = findFirstEmptyRow(sheet, startRow, 8); // Column H = 8
      sheet.getRange(rowToWrite, 8, 1, 5).setValues([[date, amount, detail, category, account]]);
      return ContentService.createTextOutput("Success! Income row added.");
    } else {
      return ContentService.createTextOutput("Mode not handled: " + mode);
    }

  } catch (error) {
    Logger.log(error);
    return ContentService.createTextOutput("Error: " + error.message);
  }
}

Examples

We can see that the sheet gets populated accordingly. With automation, this sheet gets exported monthly to an annual expenses tracker for tracking on a bigger scale pulling from multiple sources (not just iOS Shortcuts).