Docker & docker-compose: Install on Jessie (Memo)

A script for Docker & Docker-compose

Script to run with sudo/su 

#!/bin/bash
apt-get install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
apt-get update
apt-get install -y docker-ce
apt-get install -y python-pip
pip install docker-compose

Odoo : using RPC to transform “SaleOrder”

Reference document

The Bible, as I call it, is in xml workflow files. For “Sale Order”:

addons/sale/sale_workflow.xml

Retrieve an object

To retrieve a “sale order” object based on its id using odoorpc:

odoo = odoorpc.ODOO(host, port=port)
odoo.login(db, username, passwd)
SaleOrder = odoo.env['sale.order']
sale_order = SaleOrder.browse(sale_order_id)

Change a “sale order” state

  • Transform a quotation ‘draft’ to ‘sent’:
    sale_order.write({'state':'sent'})

[To be continued…]

Useful links

Odoo 8 – Useful modules & docker

List of useful modules for Odoo 8

  • product_uom_change_fix : fix an issue when changung a product UOM
  • sale_layout: change sales layout : you can have section, sub-total…
    • by default, sections are sorted by sequence, and id.
    • if you need to sort them by create order (newest first), just modify the file “sale_layout/models/sale_layout.py”; under “class SaleLayoutCategory”, and set “_order”:
      _order = 'create_date desc, sequence, id'
  • odoo-web-print-preview: preview the pdf directly in  your browser
  • report_custom_filename: by default, in Odoo, PDF files have no a fancy filename. This module solves this issue as PDF now takes the invoice reference as filename for example. Warning: incompatible with “odoo-web-print-preview
  • account_invoice_tax_auto_update: with this module, taxes are automatically updated when an invoice/… is validated.

Docker-Compose and Odoo 8

Here is my docker-compose.yml file. Please note that I use an external folder (data) to store multiples things:

  • data/config: configuration file (openerp-server.conf)
  • data/db : database
  • data/addons: addons…
version: '2'
services:
  web:
    image: odoo:8.0
    depends_on:
      - db
    ports:
      - "8069:8069"
    volumes:
      - odoo-web-data:/var/lib/odoo
      - ./data/addons:/mnt/extra-addons
  db:
    image: postgres:latest
    environment:
      - POSTGRES_PASSWORD=odoo
      - POSTGRES_USER=odoo
      - PGDATA=/var/lib/postgresql/data/pgdata
   volumes:
      - ./data/db:/var/lib/postgresql/data/pgdata
volumes:
  odoo-web-data:

 

Odoo 11 on Docker

For quite a while, I’ve been a big fan of Docker, and especially docker-compose. I’ve put mostly all my projects into a “docker”, from development to production.

Recently, I’ve been interested by Odoo 11 (I think I’ve almost installed all the versions since openerp 5.x). I managed to easily deploy Odoo 11 official docker image (https://hub.docker.com/_/odoo/), but I got an error as soon as I switched to French langage. I don’t understand why Odoo didn’t manage to update their official Odoo 11 docker image as it is not even ready for development or testing.

So, it took me, let’s say, 2 minutes, to build my own Dockerfile based on latest Odoo 11 nighty build. To pull it:
docker push gesloc/odoo11:latest

My repo is public and Odoo 11 build is under: gesloc/odoo11:latest

Here is an example for docker-compose (replace “.” by ” “)

version: '2'
services:
..web:
....image: gesloc/odoo11:latest
....depends_on:
......- db
....ports:
......- "8069:8069"
..db:
....image: postgres:latest
....environment:
......- POSTGRES_PASSWORD=odoo
......- POSTGRES_USER=odoo
......- PGDATA=/var/lib/postgresql/data/pgdata

Right now, the core image is based on debian:stretch.
Soon, I’ll do the Dockerfile based on Alpine

Note: Github with Odoo Dockers’s

EDIT (Nov 23rd): it is now available on Odoo Docker (but Odoo 8 disappears)

ExtJS 6 : Multiline cell within a grid

In one app, some messages were displayed into a grid, quite a common stuff.
However, long messages were stripped and I needed to display the whole message.

Here is the approach:
1) Add the following style to your css/scss

.multiline-row {
  overflow: auto !important;
  white-space: normal !important;
  text-overflow: ellipsis;
  display: block;
}

2) Define a rendered for the multiline cell. For example, here is my column declaration ( I prefer to use a span instead of a div )

, columns: [
        {
            xtype: 'gridcolumn', align: 'left'
            , dataIndex: 'message_content', flex: 3, text: 'Msg'
            , renderer: function (value, metaData, record, rowIndex) {
                return '' + value + '';
        }
]

And that’s pretty all!

Apache 2.4 and WebSockets (ws/wss) with Wildfly 9

I had worked on WebSockets, embedded within a J2EE (Hibernate, …) app under Wildfly. For multiple purposes, some servers I deployed the app run both Nginx or Apache2. Pxoxying both app and websocket with Nginx was quite easy and quick (I’ll detailed the configuration in another post, one day soon), but definitively, I struggle couple of hours with Apache 2.4.

I will NOT cover Socket.IO configuration for Apache 2.4, this is not the point; I focus entirely on real WebSockets.

How does it work with Apache 2.4:

  1. Enable proxy modules:
    a2enmod proxy proxy_http proxy_wstunnel
  2. If “/app” is the wildfly endpoint for your application server under wildfly, and “/app/ws” is the one for websocket (still under wildfly), add the following lines in the VirtualHost configuration (http or https):
    # Please respect the order, otherwise, it won't work
    # the WebSocket Proxying
    ProxyRequests Off
    ProxyPass "/app/ws" "ws://localhost:3000/app/ws"
    # the common app proxying
    ProxyPass "/app" "http://localhost:3000/app"
    ProxyPassReverse "/app" "http://localhost:8080/app"
  3. Reload Apache 2.4 configuration
    service apache2 reload

That’s it, it should work.

Angular 2 with REST-Backend

I’ve recently started a project based on Angular 2 for the front-end, and with a full-REST/Webservices backend.

While doing some devs for the front, as many of us, I used the famous “ng serve” to get a fresh compiled-over-the-time GUI. However, to serve the backend, I faced a very classic “CORS” issue (you know, this cross-over reference blockout form your browser, even with localhost as your server).

So, in that case, 2 ways:
– Allow CORS (whatever the way)
– Use the “ng serve” as a proxy for your backend.

The 2nd option is very simple to setup:
1) Create a proxy.conf.json file at the root of your angular2 app with the following content

{
  "/api": {  /** the root-path for your backend **/
     "target": "http://localhost:8080",   /** your REST-backend access **/
     "secure": false
  }
}

2) Serve through “ng serve” with the following command-line

ng serve --proxy proxy.conf.json

And that’s all….

OSX: install Node JS and npm in 5 mins

Prerequisites

Couple of prerequisites:

Install Node and npm

Once Homebrew is installed, it is very simple:

brew install node

That’s all….

If needed, to upgrade/update node

# update Homebrew
brew update
# update Node / Npm
brew upgrade node

and finally, to check current versions of Node JS/npm

node -v
npm -v

— END —

ExtJS 5/6 : FileField/FileUploadFile : reading data

Introduction

I have a “filefield” or “fileuploadfield” in ExtJS, and I’d like to read directly its content directly into the browser, when user selects a file.

It is useful when you’d like to display an image for example, as soon as the user selects it.

How To Proceed

First of all, you need to declare the “filefield” with a listener on “change” event. For example:

{
    xtype: 'filefield'
    ,fieldLabel: "File: "
    ,labelWidth: 70
    ,anchor: '100%'
    ,buttonOnly: true // hide text field below button
    ,buttonText: "Select a picture"
    ,listeners: {
        'change':  'onMediaChange'
    }
}

and in the Controller, the handler:

onMediaChange: function(widget, value, eOpts ) {
  var files = event.target.files
      self = this; // the controller
  if (!files || files.length == 0) return; // make sure we got something
  // Let's read content as file
  var reader = new FileReader();
  reader.onload = function (e) {
    // image content is in e.target.result
    // we can then put it into img.src, for example
    self.lookupReference('myImg').setSrc(e.target.result);
  };
  reader.readAsDataURL(files[0]);
}

and that’s it!