Introduction
We start simple, ey? Why do I need to create this app? Well, the reason is simple, to make the process of manual upload invoice photo, manual renaming and manual append of values into the spreadsheet become simple, straightforward and automatic. It will become very tedious when you need to process, let’s say 10 pieces of invoices and receipts daily. You wouldn’t have much time to do this repetitively, eh? For me, I won’t, it is simply tedious process and the time saved for chaining all of these process will slowly accumulate. (Although maybe my dad won’t care that much as this is the current and the only way of managing his own taxes and save the records as reference, but surely… there is much simpler way.)
The rabbit hole and the process.
At first, it might seem a very simple process, just upload the photo, save into the folder, append the value user requested and voila, case-close. So surely this category of app will be publically, but no. It either simplify one of the 3 processes, or combine 2 processes into 1. I am a lazy man and no I would only like to perform 1 operation instead of 3 operations, that’s ridiculous. So here we go, with the assist of AI tools (of course, is AI again, no AI? it would took months.), I was able to pull this out, which you take photo or select the photo from gallery, choose the category and choose the date, the filename will automatically generated based on the category and the date chosen, then during the upload process, it will add photo into the google drive, with the filename, and new folder correspond to the category, then it will also append the values into the spreadsheet generated by the app.
A preview of the overall algorithm for the app
Address about other OCR implementation in the prototype.
I do in fact add the OCR feature, and it is simple as calling google-ml-kit
and using tflite
. But it does not work as I expect, which i ditched this feature at the end of the project. Maybe I will implement a better solution after someday
Problems
As this is my first time working with flutter and dart, I personally don’t know much about the duo other than knowing it is widely accepted as the way to go of building an app that support multiple platforms. I haven’t work much with javascript and java before, therefore the syntax looks abit odd to me compared to python and C++. It took me a while to learn these syntax and the functions.
One of the major roadblocks I encounter is how do I exactly use the API to be able build communication between the app itself and the google’s apps I need to use. Seriously, this is the first time I also work with cloud computing and at first glance, it looks confusing as there are alot of choices and selections for me to choose. I had no idea which should I choose but it took me a while to get to the tab or section I would need to.
*Ah... Finally. These are the ones I am looking for :D.
Once i get further than enabling the API required (including Google Drive and Google Sheets), the next step is adding OAuth2.0 Client, which ironically enough, I don’t read the manuals provided by Google, and took me some times to realise I need to key in the commands prior to the command provided on-screen. And finally, not done yet. I would need to enter the emails for testing purpose only as this is not a verified app by Google.
The next major roadblock I encounter is the longway of debugging and long hours of frustrations to implement the features. Funnily enough, these lines of codes:
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async => false,
child: const AlertDialog(
content: Row(
children: [
CircularProgressIndicator(),
SizedBox(width: 16),
Expanded(child: Text("Uploading and updating sheet...")),
],
),
),
),
);
took me a while to implement, which is just freeze the entire screen and inform the user the uploading process is ongoing, and prevent further click of “Upload Receipt” button, which will upload more than 1 same file. Same as the process of uploading the file to the google drive, with the help of AI tools, then I could pull this feature off, or else it would took months to implement this, with the process of extract metadata from the file:
final metadata = {
'name': fileName,
'parents': [folderId],
};
final boundary = '----flutter_upload_boundary';
final body = <int>[];
// Part 1: Metadata (JSON)
body.addAll(utf8.encode('--$boundary\r\n'));
body.addAll(utf8.encode('Content-Type: application/json; charset=UTF-8\r\n\r\n'));
body.addAll(utf8.encode(jsonEncode(metadata)));
body.addAll(utf8.encode('\r\n'));
// Part 2: Binary File Data
body.addAll(utf8.encode('--$boundary\r\n'));
body.addAll(utf8.encode('Content-Type: $mimeType\r\n\r\n'));
body.addAll(fileBytes);
body.addAll(utf8.encode('\r\n--$boundary--\r\n'));
final uploadRes = await http.post(
uri,
headers: {
HttpHeaders.authorizationHeader: "Bearer $token",
"Content-Type": "multipart/related; boundary=$boundary",
},
body: Uint8List.fromList(body),
);
To be honest, without AI, I wouldn’t even know this is the way to extract metadata and upload to google drive, get good kids
The homerun
When it works, don’t touch it It took me few weeks to finally bring it all together, not only I could take photo directly from the app, select the category I want, choose the date, enter the amount and click upload, voila! It upload to the folder created by their own and append the values into spreadsheet where I could view in app as well! (Albeit it only display the last upload of the category, non-selectable unfortunately.)
Sample of setting up the receipt I would like to upload.
It create a new folder named as the category i chose, and add inside the file.
It also append the basic values in the correspond category inside the spreadsheet created by their own.
Conclusion
In short, it literally solve the problem of where I previously need to do all the 3 steps, now just into 1 step. Of course, there are numerous improvements and fixes could be done including adding back OCR feature to read the invoice number, adding support of file upload as part of the “E-invoice” feature, and perhaps maybe automatically obtain the e-invoice from the megacorperation with custom API? It all sounds cool and fun, but at the end, it atleast solve the core problem of doing all of these manually. (Still manually, but less manual work :D)
#Fork my work? Note: I hardly update the work I done, it done its own job great, perhaps an update will drop only if I need such feature and share it to you guys, via the repo of course.
Update: 1.1 My dad: Why there isn’t an option for me to change the language to chinese? Me: Okay, here you go.
Ey, we got a language selection now! (Official repo only support 3 of them.)
The "Receipt Uploader" UI layout but in Bahasa Malaysia language.
The "Receipt Uploader" UI layout but in Simplified Chinese language.
Note: Others could add their own language by creating new .arb
, modify the .yaml
file to add new language code, and add selection of the language code in main.dart
file