
Day 1 is in the books, and this year’s Hackathon is shaping up to be as good as any. There are 11 teams competing, but only the top 3 teams will win a prize to take home. 3rd place will take home a Blue Yeti microphone package including a boom arm and filter. 2nd place will receive an Oculus VR bundle. 1st place will win a powerful mini-projector, their names added to the trophy, and a presenting spot at one of the developer sessions to showcase their project.
Saturday Morning
For me, the day started with a visit to the Terrace Café for a ham and cheese omelet for breakfast. Then down to meeting area to check in and find a spot to wait and talk with friends arriving for the event. One of my teammates and I got in some planning time to hash out some of the finer points of our project. Registration opened to print badges at around 10:30 am, and we were able to move down to the Bandol meeting room by 11:00. While more friends arrived, so did a lunch of sandwiches and salad to provide sustenance for the day.
And So It Begins…
Leading up to 2:00 pm, everyone gathered in assigned teams and began setting up for the event. Some teams began at 2:00, and others waited for the opening remarks. Our last teammate arrived around 3:00, but we had already begun assessing needs vs. skills and started coding.
Our team, Team Theta, had selected a project to intercept file attachments into Acumatica to alert an admin to NSFW image uploads, scan for viruses, resize certain files, and apply an AI generated description of the image into Comments in the File Maintenance screen. We used an API called Cloudmersive for the AI/ML applied to the attachments. While we leverage 4 features of the API, Cloudmersive contains an extensive library of additional features that we wouldn’t have time to showcase.
We wanted to inject our code by way of a graph extension to create a place to hook our AI/ML via API and react according to the results. Our goal was to ensure it would monitor all upload via standard Acumatica browser forms, the Acumatica mobile app, and via independent software leveraging web services. The free license of the API has strict limitations of 800 calls per month, 3.5 MB file size, and a processing rate of 1 call per second. Even so, we quickly built enough of the solution to be capable of a demo of “something”. By dinner, we had met most of our objectives entirely. This afforded us the opportunity to not only HAVE all the major pieces of the project from everyone but also to be able to share some of what we learned with each other.
One of our teammates had come from South Africa. By the time dinner rolled around at 6:30, he was wearing out fast. While he had arrived on Thursday, the extreme time difference from his 22 hours of flight time was just too much to overcome, and he provided his code before heading off to bed. Fortunately, he was able to complete his entire objective first, which is a stand alone windows application that can bulk upload all the files in a folder into a custom screen of Acumatica to await movement to the appropriate object. (This aids in data migrations for ISV’s and customers alike when migrating from a legacy system.) The result we hoped to achieve was successful. Even coming from a stand alone web services based application, the same protections and utilities we implemented for file attachments were applied!
One of the most important parts of the Hackathon is making connections and learning, and we had plenty of opportunities for that. We ran into a problem getting the web services call to create our record and return the correct key value to make the secondary call that actually completes the upload. A highly respected web services expert from another team stepped in and helped us identify that since we were not displaying the key field on intermittent data collection screen, web services didn’t know how to tell us what record had been created and just kept throwing us to the first one. A quick adjustment to the screen, and magic! This just goes to show that even though we are competing, the primary goal is to help each other to succeed, not just in our Hackathon projects, but in our endeavors even after Summit. (I have a lot of personal experience with community developer doing just that!)
With 2 of the 3 desired sources tested, it was time to ensure that attachments via the Acumatica mobile app achieved the same results. Since the mobile app is not configured to show the Stocked Items (IN202500) screen, we had to first add a basic screen to the mobile app. Since this is something I’ve done several times, and due to the ease of configuration for the mobile app, this only took a few minutes. We tested taking a photo from an iPhone in the room directly in the attachments of a stocked item, and the upload began. The upload seemed to be taking an awfully long time, and then I remembered that we were making multiple calls to the API, all with a rate limit of 1 call per second. Just as I Started to panic that it wasn’t going to work, it completed. With baited breath, we went back to Acumatica to look at the new file attachment and… success!
We have a non-developer on the team (as all teams do) who knows how to setup notifications and send them via business events tied to monitoring data entry through a GI. While I thought I knew where the comment was that she would monitor on file uploads based on the object UploadFile that I was working with in the code, it turns out the comments were blank in the GI. This put us in a small state of panic to find out where the comments were, but we located them in UploadFileRevision which allowed her to complete the business event. From there, we were able to learn together that the notification template used by the business event is included in the customization project when you add the business event. With the business event and related GI attached to a new customization project, as well as a file search modification she had setup, we were ready to combine it with the other parts of our project and test. And as our luck held out so far, it worked first try!
Tying Up Loose Ends
With dinner behind us and our code looking good, one thing was starting to concern me. Our API calls are capped at 800 per month, and we seemed to be gaining momentum to use them up. With our presentation coming up on Sunday, we couldn’t afford for the API to reach its max. However, changing the API key would be a pain in the neck because it was hard coded. To fix this, one of our developers who worked with web services but standard screen in Acumatica worked with me to create a setup DAC, graph, and screen to make the API key user enterable. Once setup, we needed adjust the code to lookup that key and pass it into the methods that make the API calls.
By now, the room was beginning to thin out, and so was my ability for intelligent thought. Quite some time back, I had switched from preferring PXSelect to preferring the FBQL SelectFrom syntax. However, I spent a good 15-20 minutes trying to figure out why my screen was complaining that the primary view could not be found. After a while, it hit me that I had forgotten to add .view to the end of my SelectFrom, which means I didn’t actually setup view. This annoying little mistake still passes the “it compiled” test, but it didn’t make it to the “it works” test! LOL
Wrapping Up for the Night
At this point, 3 other teams were left in the room, and curiosity got the best of me. I checked in with each team to see if they minded sharing what they were doing, and I reciprocated. After all, none of us were going to change our projects at this point! One team was doing something that was in a similar space to ours as it related to attachments. As I understood it, they were working to allow dropping a file on a cloud drive and having their project poll it to put it into Acumatica. Very cool idea, indeed. The second team mentioned they had come across one of my blog posts related to the universal (or global) search in their research phase, which I gotta say was pretty cool to hear I was helping in some small way without even knowing it. They were working to make universal search easier to configure without having to painfully configure it within the DAC. They were running into a problem in the bowels of the code, which honestly was deeper than I had ever looked. As much as I hate the pain of configuring universal search, I REALLY hope they get that finished so it can be easier for all of us. The third team was working on something related in part to objects such as user defined fields, but it sounded like it went far beyond that. They had a child graph that wasn’t populating a smart panel on open, and it sounded like a problem I had once. I found my customization (which I had not yet finished when I set it aside) and started looking at layout properties in the ASPX and refresh related lines of code in the graph. I found a layout property in mine that they had not set, and it seemed to get them one step closer to their solution at least. Again, it seemed like it was going to be a pretty cool solution, and they had been affected by another long distance traveler who had to head to bed early. I hope the succeed in finishing for the presentation.
And Now… Sleep!
With that, it was far too late for me, and bed was calling. I started this post before bed, but I just couldn’t finish it until I had some rest. I’ll set this on a delay to post automatically while I’m at day 2, hopefully after presentations have completed. My next post will be about Hackathon Day 2… the day of presentations and prizes. Good luck to us all!
Happy Coding