Project introduction
Repository
https://github.com/boxwise/boxwise_WMS
What is Boxwise?
As stated in project's README file, Boxwise is a web-app, which makes it easy for organisations to source, store and distribute donated goods to people in need in a fair and dignified way.
How it works (in a nutshell)?
Handing out the donations can get very hectic. And especially without proper warehouse management tool. That's why Drop in the Ocean NGO implemented so called DropAppin several of its camps. It helps coordinators to sort and easily store all incoming boxes full of donations based on clothes size, clothes type and gender in the "big warehouse". It also tracks which clothes types are being asked for the most and therefore can coodinators react accordingly and bring to the camp more pieces of particular items. App also grants every camp resident (refugee) X amount of "drops" every moth which a "virtual currency" used to buy clothes from the donations. This is very important as this gives refugees the control over what they wear and how they identify themselves. It's a very important psycho-social activity which they lost!
Why did I join the project?
During my 12 days of volunteering in Greece this January in Drop in the Ocean(DiH) Skaramagas camp, I've been using DropApp daily and realized how amazing this tool is. I got to know it was developed by former volunteers last year and I contacted them on Facebook. During a quick Google Hangouts we had, they explained me the issues of the application (unscalability -> every camp needs their own web server and tech person) and the reason why Boxwise was created. It's basically a DropApp 2.0. Better, more stable and scalable version ( hopefully ;) ).


Tech talk
Odoo
We are using the open source ERP system called Odoo as the base for Boxwise. It's a modular system which allows to add various modules into the environment and there are already several modules which address the exact same area - warehouse management.
Sounds great right? The only problem is, the whole team which is currently 4 people have almost zero experience in Odoo. Ok, let's be honest..not almost zero...zero :D
Anyway, let's not lose more time and get into the nitty-gritty. My task was:
New Feature - generate packages in bulk
- My pull request: HERE
- Detailed task description: Feature request #9
- Language: Python, XML
- Commits: 6
- Additions: 64 (cumulative commit by commit - 100)
- Deletions: 2 (cumulative commit by commit - 40)
- Time spent: good 12 hours!! (don't laugh, first time Odoo user here, I've read at least 70 pages of Odoo Essensials book to get required knowledge how to do this + we still didn't have a debugger last week)
Usecase of the new feature: We're using GitHub issues as a list of feature requests as well, so you the more detailed description can be found in the link above. It's a crucial feature used by coordinators (warehouse volunteers) daily. Donation boxes don't come one by one but in bulks. Each box gets labeled by unique QR label which leads to form where coordinator fills parameters of items in the box (gender, size, clothes type, items count). Generating these packages (QR codes/labels) in bulk saves ton of time daily! For better understanding, watch the Youtube video linked above :)

Ok, I guess GIF makes up for thousand of various workflows and schemes right? Well then, here you go, the process in the old DropApp (Javascript + PHP) which I recreated in Boxwise (Odoo + XML + Python)

And my implementation in Odoo for Boxwise :) Ohhh I love it :D

Implementation & Code
Step 1: How to register python classes in Odoo
3 minutes into it, I knew I'm screwed. I had no idea where and how to start. Hans has managed to add the "Generate QR labels" option to menu with XML (which I later changed) and then passed it to me. I needed a way how to get input from user back to server side. Googling..googling...and then I've found this 380 pages long PDF :D What a nice weekend ahead of me :) Eventually, I started to make some microsteps..
from . import wizards
from . import generate_qr_count_wizard
Till now it all makes sense. Standard python right? But creating the class (so called model) has some specific Odoo rules . It has to inherit from model.Model class or some other submodels..Eventually, my dummy class "Book" was in and I could move on :)
Step 2: Get user input, trigger server action & change menu item from Hans
After I've managed to link my dummy test model (class) to Odoo, it was time to create some real models. User popup (simple alert in Javascript) is called wizard in Odoo. It can be implemented with a class which has to have a TransientModel as a superclass.
class QrGenerateWizard(models.TransientModel):
_name = 'boxwise_wms.qr.generate.wizard'
_description = 'Number of QR codes to be generated'
number = fields.Char(string='Number of labels', required=True, default=0)
Details are in commit #7031f2301d0eab437f33aff54521847a23b67eb5
Step 3: Submit wizard and generate packages
This one was pretty straightforward as I already knew a bit about Odoo wizards at this point. Method annotated by @api.multi with the same name as the wizard button was needed.
< footer>
< button name="mass_generate" type="object" string="Generate"
class="oe_highlight"/>
< button special="cancel" string="Cancel"/>
< /footer>
@api.multi
def mass_generate(self):
_logger.debug('Starting batch QR codes generation')
package_model = self.env['stock.quant.package']
number_of_packages = int(self.number)
created_packages = []
for _ in range(number_of_packages):
created_packages.append(package_model.create({}))
Details are in commit #e03800020918c00dd4bcf0b16c3c6239004fbdee
Step 4: Navigate back to packages tree view
It's little bit counterintuitive (at least for me) but the way navigation from server is done in Odoo is that you basically just return the act_window action with result model set to packages. The same one which is bound to menu item. Return is called from method which generates packages (obviously). If Odoo model method starts with underscore, it's private. It looks like this:
return self._open_packages_list()
@api.model
def _open_packages_list(self):
return {
'type':'ir.actions.act_window',
'res_model':'stock.quant.package',
'view_type':'list',
'view_mode':'list',
'target':'current'
}
Details are in commit #e03800020918c00dd4bcf0b16c3c6239004fbdee
Step 5: Cleanup according to Odoo best practices
Nothing special here. I've replaced camelCasing to snake_casing which is the good practice in all Odoo modules for common variables.
Details are in commit #d9adbdfec3f90c340fb340280abfb594488be084
Bonus commit: Removing unneeded table header alignment
This one came pretty handy as I was struggling with Odoo for couple of hours at this point and then I've noticed this completely random right alignment CSS which had nothing to do there :) Boom, delete :) Finally something to commit haha :D
Details are in commit #0d5ba1dd19009f294aa772214777112f86eb0b34

Next steps for Boxwise team
- Continue implementing basic DropApp functionality into Boxwise for the next 2 weeks
- In two weeks, Hans and James are flying over to Athens to test our first version in local warehouse in Pampiraiki
- Month of development
- Flying back to Greece from 3rd to 8th April and hopefully implement Boxwise in one of Drop in the Ocean camps. I'm flying this time as well :)