Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request/Discussion] App Links for automatically adding transactions to Cashew #127

Closed
HenryWu01 opened this issue Jan 21, 2024 · 36 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request

Comments

@HenryWu01
Copy link

Thanks you for developing such an nice budget management application. I would like to request an API for adding bills, enabling “Cashew” to bypass the need for in-app support for automatic bill recording. Third-party applications can take on the responsibility of implementing methods to extract bill information from payment apps, either through reading program data or OCR, and subsequently calling the “Cashew” API to add the extracted information to the bills. This approach would facilitate “automated” bill recording.

I believe the most suitable method for this purpose would be to implement a URI scheme. Since this feature is exclusively for adding records, there are no significant concerns regarding data leakage. “Cashew” can enhance security and control by implementing measures such as “API keys”, “rate limiting”, and an “application allow list” to thwart any potential malicious software or behaviors.

A popular app in China named “钱迹” (Qianji) already offers a feature like this.

Below is a sample URI scheme:

cashew://addbill?type=0&amount=123.4&account=Account&category=Category&subcategory=Subcategory&time=2023-10-29T00:00:00Z&remark=Sample
Name Description
type Type of transaction (e.g., expense, income, transfer, etc.)
amount Transaction amount
account Account book
category Transaction category
subcategory Transaction subcategory
time Transaction time
remark Transaction remark
@HenryWu01 HenryWu01 added the enhancement New feature or request label Jan 21, 2024
@jameskokoska
Copy link
Owner

Somewhat duplicate of #99

Since Cashew is a server less application and all data is stored on device, there is no API connection that can be created. Cashew does not connect to any application specific server for getting user data and therefore cannot receive requests.

@jameskokoska jameskokoska closed this as not planned Won't fix, can't repro, duplicate, stale Jan 21, 2024
@HenryWu01
Copy link
Author

I'm sorry I did not clearly explain this feature. This feature propose an URI scheme that allows third-party applications to add bill into Cashew. It's not about editing or exporting, just inserting bills using URI Scheme

@jameskokoska
Copy link
Owner

jameskokoska commented Jan 21, 2024

As I mentioned, Cashew does not have any backend server to connect to. It's a server-less application.

Edit: After looking into it more, it seems like a server-less solution is possible with deep linking (not app linking). I can look into adding this in the future, however I'm going to keep this issue closed as I have no immediate plans as of now. I find this is a really niche feature.

@HenryWu01
Copy link
Author

Thank you for considering this feature. Yes, it is possible with the serverless app through deep-linking (URI scheme). That's what I am saying about the feature. Provice some kind of URI scheme or deep linking so other application can call it to add bill into Cashew. Sorry for the unclear description of the feature

@jameskokoska
Copy link
Owner

Added in 5.2.3+328
Documentation here: https://github.com/jameskokoska/Cashew/tree/main?tab=readme-ov-file#app-links

@HenryWu01
Copy link
Author

Added in 5.2.3+328 Documentation here: https://github.com/jameskokoska/Cashew/tree/main?tab=readme-ov-file#app-links

Thank you so much! With this feature implemented, Cashew can be so powerful to use. Thank you for taking consideration of this feature and implementing it!

@ngocanhtve
Copy link

ngocanhtve commented Mar 7, 2024

Added in 5.2.3+328 Documentation here: https://github.com/jameskokoska/Cashew/tree/main?tab=readme-ov-file#app-links

Thank you so much! With this feature implemented, Cashew can be so powerful to use. Thank you for taking consideration of this feature and implementing it!

How to use this feature?

@jameskokoska
Copy link
Owner

Added in 5.2.3+328 Documentation here: https://github.com/jameskokoska/Cashew/tree/main?tab=readme-ov-file#app-links

Thank you so much! With this feature implemented, Cashew can be so powerful to use. Thank you for taking consideration of this feature and implementing it!

How to use this feature?

The documentation has some examples of its usage! Please see the README

@ngocanhtve
Copy link

ngocanhtve commented Mar 7, 2024

The documentation has some examples

Read it but don't understand how it works. Can't imagine how it would work. Can @HenryWu01 illustrate?

@tiniwings
Copy link

The documentation has some examples

Read it but don't understand how it works. Can't imagine how it would work. Can @HenryWu01 illustrate?

Hi, I am using this applink feature with Tasker integration to automate my credit card transactions.

Below are some sreps at high level, implementation is more customized based on individual usage.

  1. In Tasker you can read the incoming sms notification from bank/credit card and split the information into multiple parts like Amount, Category..
  2. In Tasker there is an option to trigger custom URL with specified app.
  3. Using the split information we create the custom Cashew applink with amount, category information and trigger that link from Tasker whenever we receive transaction sms/notification.
  4. The URL will automatically opens cashew app creates a transaction.

I would like to use this opportunity to thank @HenryWu01 and @jameskokoska for this feature, as this is the biggest reason I have moved to Cashew app for budgeting. 🙏

@jameskokoska
Copy link
Owner

@tiniwings I'm glad you made good use out of this feature :)

Similar to Tasker, a free alternative - Automate (https://play.google.com/store/apps/details?id=com.llamalab.automate) can do a similar workflow. Here's a proof of concept flow for those interested: Screenshot_20240609_100634_Automate.png

@HappyBear-btc

This comment has been minimized.

@jameskokoska

This comment has been minimized.

@HappyBear-btc

This comment has been minimized.

@jameskokoska
Copy link
Owner

Just thought I would throw this in here for fun. Linking Cashew's App Link API with Google Gemini AI has a lot of potential!

Screen_Recording_20240704_003032_Automate.mp4

@jameskokoska jameskokoska added the documentation Improvements or additions to documentation label Jul 4, 2024
@jameskokoska jameskokoska changed the title [Feature Request] API (URI Scheme) for adding bills to Cashew [Feature Request/Discussion] App Links for automatically adding transactions to Cashew Jul 4, 2024
@Akv2021
Copy link

Akv2021 commented Jul 29, 2024

@jameskokoska
Didn't get the part how you're proposing to use Google Gemini AI above.
Also, Would you mind sharing the automator script which can act as a reference since the current documentation doesn't talk about any sample script which extracts the data from incoming message & posts to cashew URI.

@RoshanJ20
Copy link

RoshanJ20 commented Aug 9, 2024

@Akv2021 @jameskokoska
So, i tried making a flow for this feature on Automate. I can link it up here. The app package can be changed according to your required banking app. You may also need to change the regex pattern (I used https://regex101.com/ ). I have also defaulted to Shopping coz why not. Have Fun!

Download here:https://drive.google.com/file/d/1aPjvzjKtXM-ng0p1j_4x5KCyjsxSqdVi/view?usp=sharing

@MaazAhmad360
Copy link

@jameskokoska can we get an App Link for transfer between accounts?
Apart from that really love the already added app links!

@pietroMonta42

This comment has been minimized.

@Midoogm
Copy link

Midoogm commented Oct 2, 2024

I got it done with Tasker
Simply
[Detect any new sms
Check it's content for key words
If it's a message from my bank then
-look for an amount (using regex)
-Use that amount number and place it in the Link App
-open that link]

It doesn't currently change the catagory or adds notes, but it's doable, if used another function to look for a specific word and based on it it will know what catagory and note to add

@jankogasic
Copy link

Does anyone know how to do it on iOS? I can extract info with Shorcuts app, but how do I trigger App Links? When I execute URL with Chrome app, it doesn't work.

@jameskokoska
Copy link
Owner

Official Siri shortcut implementation is coming, but in the meantime the README has working examples of App Links that work on iOS.

@jankogasic
Copy link

jankogasic commented Oct 8, 2024

I tested all 4 example URLs on both Chrome and Safari and it opens https://cashewapp.web.app/ web page with 404 error. Do I need to enable some option in iOS settings or it should work out of the box?

iOS version 18.0.1
Cashew version 5.4.2

@D3478
Copy link

D3478 commented Nov 29, 2024

Official Siri shortcut implementation is coming, but in the meantime the README has working examples of App Links that work on iOS.

Is it still planned and will be implemented?

@jameskokoska
Copy link
Owner

Yes, I actually have it in a working build just needs to be tested. Haven’t had much time to test this release as it has many new features.
IMG_1654

@D3478
Copy link

D3478 commented Nov 29, 2024

Yes, I actually have it in a working build just needs to be tested. Haven’t had much time to test this release as it has many new features. IMG_1654

This is amazing ,, any plans to push it on testflight

@adrianjael
Copy link

Hey how about everyone, I come to make my little contribution, I don't know programming or anything related but I like to learn and solve problems, a week ago I switched to cashew, and With the help of chat gpt, I made an automation to add the transactions, in my case with Gmail which is where I get the messages from my banks, whether I send or receive, even consumption of my cards, I made a script so that if a new email arrived and it was from my bank, I executed the automation to find the date in the email, values, name, category etc, and with webhook I sent it to my cell phone with MacroDroid, and I also added it to a google spreadsheet to have 2 backups

A video of how it works works perfectly here.

screen-recording-20241201-162828-gmail_dy12rypS.mp4

@dr-msr
Copy link

dr-msr commented Dec 2, 2024

Receipt Tracker With ChatGPT and Cashew Integration

  1. You can use any AI provider (ChatGPT, Perplexity, Claude etc) that supports vision/ocr.

  2. Use the prompt below or set is as system prompt :

You are a Receipt Tracker. Whenever I upload a receipt, you will extract the following information :

Title.
Amount. If negative, put negative sign to it.
Date. Use getCommonDateFormats() supported format.
Account. Select the most accurate from the Account list below. If not found, prompt the user.
Categories. Select the most accurate category from the list below. If not found, prompt the user.

[Accounts]
... (list your account here) ...

[Categories]
... (list your categories here) ...

You will ask user to verify the information. If the user has verified the information, modify the URL below :

https://cashewapp.web.app/addTransactionRoute?amount={amount}&title={title}&date={date}

And return the modified URL to the user as a clickable link.
  1. Modify the URL accordingly. In this template, I use the /addTransactionRoute

  2. You can also modify the prompt to skip verification and straight away generate the link required.

@Akv2021
Copy link

Akv2021 commented Dec 4, 2024

Hey @adrianjael ,
Thanks, you're right. Apart from SMS, email can also be source of transactions.
Could you share your script for reference similar to this SMS script ? https://drive.google.com/file/d/1aPjvzjKtXM-ng0p1j_4x5KCyjsxSqdVi/view?usp=sharing

@Akv2021
Copy link

Akv2021 commented Dec 4, 2024

@dr-msr In case of ChatGPT/Claude creating a link from receipt, wouldn't you always need to scan the receipts through AI app ? It might not be preferred from privacy point of view.

  • How is the account mapping part handled when receipt contains account no (eg xxx123) but app has different account name (eg ABC bank)
  • Wouldn't it be better if the OCR logic can be added as a part of Cashew itself or a separate app/script ?

@dr-msr
Copy link

dr-msr commented Dec 4, 2024

@dr-msr In case of ChatGPT/Claude creating a link from receipt, wouldn't you always need to scan the receipts through AI app ? It might not be preferred from privacy point of view.

  • How is the account mapping part handled when receipt contains account no (eg xxx123) but app has different account name (eg ABC bank)
  • Wouldn't it be better if the OCR logic can be added as a part of Cashew itself or a separate app/script ?

Thank you, for the interesting point of view.

  1. the prompt provided as an example. you can use any LLM capable of vision/image handling, including local one (if privacy is an issue). downside could be higher technical requirement, higher latency, reduced accuracy.

  2. two levels - from the prompt level, the AI will be asking the user to verify the extracted record from the receipt. user has the chance to correct/make changes. second is at the cashew level, by using addTransactionRoute, user can change/modify it once again in Cashew before the transaction is recorded.

  • the limitation right now is that whenever a new account/category is added, user has to manually edit/adjust the prompt. if cashew can provide a get API (getAccount, getCategory, getSubcategory), this integration can be seamless.
  1. Yes, i believe this will be a great feature considering many money-management app has receipt scanner tool build in, and to use AI as tool for OCR will provide a better context/extraction.,

the App Links API that Cashew implemented is a very easy to adapt with a myriad of external softwares/automation tools.

@adrianjael
Copy link

Ey@adrianjaelGracias , tienes razón. Además de los SMS, el correo electrónico también puede ser una fuente de transacciones. ¿Podrías compartir tu script como referencia, similar a este script de SMS? https://drive.google.com/file/d/1aPjvzjKtXM-ng0p1j_4x5KCyjsxSqdVi/view?usp=sharing

Aqui el scritp de google:

`// Ready to store pending data
var datosPendientes = [];

function procesarCorreos() {
  var hoja = SpreadsheetApp.openById("google sheet ID").getSheetByName("Transactions");
  
  // Search for unread emails containing "Source account: XXXXXX" or "Credited account: XXXXXX"
  var query = 'is:unread ("Cuenta de origen: XXXXXX" OR "Cuenta acreditada: XXXXXX")';
  
  // Please verify the query before making it.
  Logger.log('Consulta de búsqueda: ' + query);
  
  var correos = GmailApp.search(query);
  Logger.log('Número de correos encontrados: ' + correos.length);
  
  // Process each email individually
  correos.forEach(function(thread) {
    var mensajes = thread.getMessages(); // Get messages from each thread

    mensajes.forEach(function(mensaje) {
      if (mensaje.isUnread()) { // Only process unread emails
        var idCorreo = mensaje.getId();
        var cuerpoHTML = mensaje.getBody();
        var cuerpoTexto = mensaje.getPlainBody();
        
        // Log mail body for debugging
        Logger.log(`Correo ID ${idCorreo} - Cuerpo del correo: ` + cuerpoTexto);

        // Check if the email has already been processed
        if (esCorreoProcesado(idCorreo, hoja)) {
          Logger.log('Correo ya procesado, omitiendo...');
          return; // If it has already been processed, skip this email
        }

        // Sanitizar cuerpo de texto, reemplazando saltos de línea y caracteres especiales
        var cuerpoTextoSanitizado = cuerpoTexto.replace(/\r?\n|\r/g, " ").replace(/\*/g, "").replace(/\s+/g, " ").trim();

        // Buscar las palabras clave en el texto
        var fecha = extraerFecha(cuerpoTextoSanitizado);
        var cuentaOrigen = extraerCuenta(cuerpoTextoSanitizado, "Cuenta de origen");
        var cuentaAcreditada = extraerCuenta(cuerpoTextoSanitizado, "Cuenta acreditada");
        var nombreBeneficiario = extraerNombreBeneficiario(cuerpoTextoSanitizado);
        var monto = extraerMonto(cuerpoTextoSanitizado);
        var concepto = extraerConcepto(cuerpoTextoSanitizado);
        
        Logger.log('Fecha: ' + fecha);
        Logger.log('Cuenta Origen: ' + cuentaOrigen);
        Logger.log('Cuenta Acreditada: ' + cuentaAcreditada);
        Logger.log('Nombre Beneficiario: ' + nombreBeneficiario);
        Logger.log('Monto: ' + monto);
        Logger.log('Concepto: ' + concepto);
        
        // Verificar si la cuenta de origen o acreditada es la que buscamos y procesar los datos
        if (cuentaOrigen === "XXXXXX1176" || cuentaAcreditada === "XXXXXX1176") {
          // Determinar si el monto debe ser negativo o positivo
          var montoFinal = (cuentaAcreditada === "XXXXXX1176") ? monto : -monto;
          
          // Formatear la fecha a mm/dd/yyyy
          var fechaFormateada = formatFecha(fecha);
          
          // Guardar en la hoja de cálculo en las columnas adecuadas
          var fila = [
            "", // Columna A (vacía para mantenerla sin uso)
            fechaFormateada, // Columna B: Fecha (formateada a mm/dd/yyyy)
            montoFinal, // Columna C: Monto (positivo si cuenta acreditada)
            concepto || "sin especificar", // Columna D: Concepto
            obtenerConceptoAntesDeNumero(cuerpoTextoSanitizado), // Columna E: Concepto antes del "0"
            nombreBeneficiario, // Columna F: Nombre del beneficiario
            "Importaciones", // Columna G con valor "Importaciones"
            idCorreo // Columna H: ID del correo para evitar duplicados
          ];
          
          Logger.log('Guardando en hoja de cálculo: ' + fila);
          hoja.appendRow(fila); // Guardar los datos en la hoja
          
          // Intentar enviar los datos al Webhook de MacroDroid
          var datos = {
            "fecha": fechaFormateada,
            "monto": montoFinal,
            "concepto": concepto || "sin especificar",
            "conceptoAntesDelNumero": obtenerConceptoAntesDeNumero(cuerpoTextoSanitizado),
            "nombreBeneficiario": nombreBeneficiario,
            "tipo": "Importaciones", // Puedes modificarlo si es necesario
            "idCorreo": idCorreo
          };
          
          if (!enviarDatosAlWebhook(datos)) {
            datosPendientes.push(datos); // Si no se pudo enviar, guardar en pendientes
          }
        }

        // Marcar el correo como leído
        mensaje.markRead();
      }
    });
  });
  
  // Procesar datos pendientes, si los hay
  procesarDatosPendientes();
}

// Función para verificar si el correo ya fue procesado
function esCorreoProcesado(idCorreo, hoja) {
  var rango = hoja.getRange(2, 8, hoja.getLastRow(), 1); // Columna H (ID del correo)
  var ids = rango.getValues();
  
  Logger.log('Verificando si el correo ya fue procesado...');
  
  for (var i = 0; i < ids.length; i++) {
    if (ids[i][0] === idCorreo) {
      Logger.log('Correo ya procesado: ' + idCorreo);
      return true; // El correo ya fue procesado
    }
  }
  return false; // El correo no fue procesado
}

// Función para enviar datos al Webhook
function enviarDatosAlWebhook(datos) {
  var url = "https://webhook.com/cashew";
  
  var opciones = {
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify(datos)
  };
  
  try {
    UrlFetchApp.fetch(url, opciones);
    Logger.log('Datos enviados al Webhook: ' + JSON.stringify(datos));
    return true;  // Datos enviados correctamente
  } catch (error) {
    Logger.log('Error al enviar los datos: ' + error.message);
    return false;  // Error al enviar
  }
}

// Función para procesar los datos pendientes
function procesarDatosPendientes() {
  if (datosPendientes.length > 0) {
    datosPendientes.forEach(function(datos) {
      if (!enviarDatosAlWebhook(datos)) {
        Logger.log("No se pudo enviar los datos, se quedarán pendientes.");
      } else {
        // Pausar 5 segundos entre los envíos
        Utilities.sleep(5000);
      }
    });
    datosPendientes = []; // Limpiar los datos pendientes
  }
}

// Funciones auxiliares
function extraerFecha(texto) {
  var fechaRegex = /Fecha:\s*(\d{2}\/\d{2}\/\d{4})/;
  var fecha = texto.match(fechaRegex);
  return fecha ? fecha[1] : "";
}

function extraerCuenta(texto, tipoCuenta) {
  var cuentaRegex = new RegExp("\\*?" + tipoCuenta + ":\\s*([A-Z0-9]+)");
  var cuenta = texto.match(cuentaRegex);
  return cuenta ? cuenta[1] : "";
}

function extraerNombreBeneficiario(texto) {
  var nombreRegex = /Nombre del beneficiario:\s*([\w\s]+)(?=\s*Monto|$)/;
  var nombre = texto.match(nombreRegex);
  return nombre ? nombre[1].trim() : "";
}

function extraerMonto(texto) {
  var montoRegex = /Monto:\s*USD\s*(\d+(\.\d{2})?)/;
  var monto = texto.match(montoRegex);
  return monto ? parseFloat(monto[1]) : 0;
}

function extraerConcepto(texto) {
  var conceptoRegex = /Concepto:\s*.*?0\s*(.*?)(?=\s*Número de documento:)/;
  var concepto = texto.match(conceptoRegex);
  return concepto ? concepto[1].trim() : "";
}

function obtenerConceptoAntesDeNumero(texto) {
  var conceptoRegex = /Concepto:\s*(.*?)(\d+)/;
  var concepto = texto.match(conceptoRegex);
  return concepto ? concepto[1].trim() : "";
}

function formatFecha(fecha) {
  var partesFecha = fecha.split('/');
  if (partesFecha.length === 3) {
    var dia = partesFecha[0];
    var mes = partesFecha[1];
    var año = partesFecha[2];
    return mes + '/' + dia + '/' + año;
  }
  return fecha;
}
`

I don't know English so I used the translator to write the message, that is the code I've been testing for 2 weeks now and I make many bank transactions and it records them perfectly,

The only problem I have is the categories, the default link I use is category and if I write a subcategory the application doesn't record it, it asks you to choose the category manually because it doesn't exist since it's a subcategory, if the url using category automatically knew if it was a subcategory it would be perfect,

and I created a separate account in cashew so that all the transactions are recorded there, then at night I move the records to the corresponding accounts, I could make it do it automatically but I'm testing it and I don't want it to damage my records of the important accounts.

In Macrodroid or Automate it's simple, you just receive the webhook and open it with the cashew url with the data received,

you can use chatgpt to help you modify the code, that's practically how I created it.

@Akv2021
Copy link

Akv2021 commented Dec 6, 2024

Thanks @adrianjael,
I was expecting the Automate/Macrodroid itself to contain the email parsing logic. But was able to move the transactions from email to spreadsheet.

  1. The webhook url "https://webhook.com/cashew" is not a valid URL, how do you post the transactions ?
  2. If you use the webapp route "https://budget-track.web.app/" then shouldn't it be clicked manually after logging in on web app ? Can't think how it'd find the user since there's no such parameter in the URL itself.
  3. How do you use the "Concept Before Number", "Imports" & even "Beneficiary Name" fields ?

I've managed to tweek the script to create a single API URL with all transactions of the day. Need to add a way also automate the transactions only received on sms & not mail.

@adrianjael
Copy link

adrianjael commented Dec 8, 2024

Gracias@adrianjaelEsperaba que Automate/Macrodroid contuviera la lógica de análisis de correo electrónico, pero pude trasladar las transacciones del correo electrónico a la hoja de cálculo.

  1. La URL del webhook " https://webhook.com/cashew " no es una URL válida, ¿cómo se publican las transacciones?
  2. Si utiliza la ruta de la aplicación web " https://budget-track.web.app/ ", ¿no debería hacer clic en ella manualmente después de iniciar sesión en la aplicación web? No se me ocurre cómo encontraría al usuario, ya que no existe dicho parámetro en la URL.
  3. ¿Cómo se utilizan los campos “Concepto antes del número”, “Importaciones” e incluso “Nombre del beneficiario”?

He logrado modificar el script para crear una única URL de API con todas las transacciones del día. También es necesario agregar una forma de automatizar las transacciones que solo se reciben por SMS y no por correo electrónico.

    • The URL is invalid because you need to change it to the MacroDroid/automate URL. To connect the Webhook.

2.- It does not find the user as it makes a webhook call and MacroDroid receives the request and proceeds by saving it in values. Then generate the URL by adding the values and open the browser with the URL, the application automatically opens and I added the transfers.

3.- The concept before the number, Imports, name of the beneficiary, is data that I need to be added with the transfer. In my bank it allows me to add a description of the transfer I do, there I detail everything so that it separates it, I include category and title.

Example, in detail I write, payment of food 0 meal. The script detects the parameter and writes the title all the words before the 0 and category everything that goes after the 0, so it knows that you payment of food It's the title and meal is the category.

Imports, it is added manually which is a Cashew account where transfers are added, you can change it to the name of your account in Cashew.

I'm sorry if I don't explain it well, I'm using the translator, but I recommend you copy the code paste it into chatgpt and ask it to explain it to you. I'm sure he'll explain how the code works better.....

You can write to me on telegram @mrnothing_pro and I will try to explain it better.

@D3478
Copy link

D3478 commented Dec 24, 2024

Hi can this not be done without opening cashew app and let the transaction be added in background just like how ios shortcuts work?

@D3478
Copy link

D3478 commented Dec 24, 2024

Or as a tasker plugin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

No branches or pull requests