Salah satu fitur Odoo adalah multi database. Dalam satu domain anda dapat menggunakan berapapun jumlah database, asalkan server anda mampu menanganinya. Tiap database ini bisa anda install module yang berbeda dengan fungsi dan tujuan yang berbeda pula.
Misal database 1 untuk perusahaan utama anda. Database 2 untuk training karyawan baru. Database 3 untuk pengembangan fitur baru. Database 4 untuk perusahaan anda yang lain dan sebagainya. Jika anda ingin pindah-pindah database pun gampang. Tidak perlu ubah konfigurasi atau restart server. Cukup klik-klik saja.
Informasi database yang digunakan user disimpan dalam session. Jika user pertama kali membuka Odoo dan informasi database yang digunakan belum ada di session, user akan diarahkan ke halaman Database Selector untuk memilih database.
Hal ini bisa jadi problem jika anda menginstall module website atau anda menyediakan API di program Odoo anda. Masak orang mau membuka website tidak diarahkan ke Home Page atau halaman Shoping tapi disuruh memilih database. Ini akan membingunakan.
Begitu pula jika anda menyediakan API yang bisa diakses dari luar. Hal ini akan menyebabkan error atau mungkin data yang tidak valid, karena Odoo tidak tahu anda mau akse API dari database mana.
Lalu adakah solusi untuk menyelesaikan masalah ini ?
Gunakan dbfilter
Ini adalah solusi yang disarankan oleh Odoo. Dbfilter digunakan untuk mengatur database mana saja yang bisa diakses oleh user. Dbfilter ini banyak cara penggunaanya. Tapi cara yang paling make sense menurut saya adalah kombinasi dengan subdomain.
Ubah file configuration anda (biasanya di /etc/odoo-server.conf) dan tambahkan kode berikut. Kemudian restart service Odoo.
dbfilter=%d
Maksud kode diatas adalah Odoo akan memfilter database mana saja yang bisa diakses user berdasarkan domain / subdomain yang diinputkan user pada browser.
Misal user mengakses http://training.domain-anda.com. Maka user hanya bisa mengakses database dengan prefix training saja. Misal training.bulan_satu, training.bulan_dua dan sebagainya. Database lain tidak bisa diakses.
Jadi jika anda menggunakan dbfilter seperti diatas, rumus nama database anda adalah sebagai berikut nama_subdomain_sebagai_prefix.teks_bebas. Database yang diakses dari website utama (misal http://domain-anda.com) tidak perlu prefix, cukup teks bebas saja.
Saya sarankan gunakan satu domain satu database, agar user tidak perlu pilih database lagi. Kalau perlu override controller /web/database/selector.
Ubah file http.py
Cara ini bukan yang secara resmi disarankan oleh Odoo. Tapi karena Odoo adalah open source, boleh dong kita otak-atik sesuai keinginan kita.
Di file http.py inilah kode untuk mengecek apakah di session user sudah memilih database atau belum, jika belum diarahkan ke halaman /web/database/selector. Di komputer saya file ini terletak di /odoo/odoo-server/odoo/http.py. Di komputer anda mungkin letaknya berbeda. Perhatikan class Root terutama di method dispatch
def dispatch(self, environ, start_response): """ Performs the actual WSGI dispatching for the application. """ try: httprequest = werkzeug.wrappers.Request(environ) httprequest.app = self httprequest.parameter_storage_class = werkzeug.datastructures.ImmutableOrderedMultiDict threading.current_thread().url = httprequest.url threading.current_thread().query_count = 0 threading.current_thread().query_time = 0 threading.current_thread().perf_t0 = time.time() explicit_session = self.setup_session(httprequest) self.setup_db(httprequest) self.setup_lang(httprequest) request = self.get_request(httprequest) def _dispatch_nodb(): try: func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match() except werkzeug.exceptions.HTTPException as e: return request._handle_exception(e) request.set_handler(func, arguments, "none") result = request.dispatch() return result with request: # ===PERHATIKAN KODE DI BAWAH ==== db = request.session.db # ===PERHATIKAN KODE DI ATAS ==== if db: try: odoo.registry(db).check_signaling() with odoo.tools.mute_logger('odoo.sql_db'): ir_http = request.registry['ir.http'] except (AttributeError, psycopg2.OperationalError, psycopg2.ProgrammingError): # psycopg2 error or attribute error while constructing # the registry. That means either # - the database probably does not exists anymore # - the database is corrupted # - the database version doesnt match the server version # Log the user out and fall back to nodb request.session.logout() # If requesting /web this will loop if request.httprequest.path == '/web': result = werkzeug.utils.redirect('/web/database/selector') else: result = _dispatch_nodb() else: result = ir_http._dispatch() else: result = _dispatch_nodb() response = self.get_response(httprequest, result, explicit_session) return response(environ, start_response) except werkzeug.exceptions.HTTPException as e: return e(environ, start_response)
Lalu perhatikan perubahannya pada kode dibawah ini
def dispatch(self, environ, start_response): """ Performs the actual WSGI dispatching for the application. """ try: httprequest = werkzeug.wrappers.Request(environ) httprequest.app = self httprequest.parameter_storage_class = werkzeug.datastructures.ImmutableOrderedMultiDict threading.current_thread().url = httprequest.url threading.current_thread().query_count = 0 threading.current_thread().query_time = 0 threading.current_thread().perf_t0 = time.time() explicit_session = self.setup_session(httprequest) self.setup_db(httprequest) self.setup_lang(httprequest) request = self.get_request(httprequest) def _dispatch_nodb(): try: func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match() except werkzeug.exceptions.HTTPException as e: return request._handle_exception(e) request.set_handler(func, arguments, "none") result = request.dispatch() return result with request: # ===PERHATIKAN KODE DI BAWAH ==== if request.params.get('default_db_name'): request.session.update({'db': request.params.get('default_db_name')}) else: if not request.session.db: request.session.update({'db': 'test'}) db = request.session.db # ===PERHATIKAN KODE DI ATAS ==== if db: try: odoo.registry(db).check_signaling() with odoo.tools.mute_logger('odoo.sql_db'): ir_http = request.registry['ir.http'] except (AttributeError, psycopg2.OperationalError, psycopg2.ProgrammingError): # psycopg2 error or attribute error while constructing # the registry. That means either # - the database probably does not exists anymore # - the database is corrupted # - the database version doesnt match the server version # Log the user out and fall back to nodb request.session.logout() # If requesting /web this will loop if request.httprequest.path == '/web': result = werkzeug.utils.redirect('/web/database/selector') else: result = _dispatch_nodb() else: result = ir_http._dispatch() else: result = _dispatch_nodb() response = self.get_response(httprequest, result, explicit_session) return response(environ, start_response) except werkzeug.exceptions.HTTPException as e: return e(environ, start_response)
Idenya adalah jika user memasukkan parameter default_db_name pada url (misal http://domain-anda.com?default_db_name=database_satu) maka session akan kita update, sehingga user akan diarahkan ke database yang sesuai. Jika tidak memasukkan parameter default_db_name kita cek user sudah memilih database sebelumnya atau belum, jika belum kita harcode agar diarahakan ke database tertentu. Selebihnya default Odoo.
Ralat
Ternyata Odoo sudah ada fitur untuk menset default database seperti diatas dengan cara seperti ini http://domain-anda.com?db=database_satu. Jadi kita tidak perlu membaca parameter defautl_db_name lagi. Cukup check apakah database yang dipilih oleh user sudah ada di session atau belum. Berikut ini kodenya
def dispatch(self, environ, start_response): """ Performs the actual WSGI dispatching for the application. """ try: httprequest = werkzeug.wrappers.Request(environ) httprequest.app = self httprequest.parameter_storage_class = werkzeug.datastructures.ImmutableOrderedMultiDict threading.current_thread().url = httprequest.url threading.current_thread().query_count = 0 threading.current_thread().query_time = 0 threading.current_thread().perf_t0 = time.time() explicit_session = self.setup_session(httprequest) self.setup_db(httprequest) self.setup_lang(httprequest) request = self.get_request(httprequest) def _dispatch_nodb(): try: func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match() except werkzeug.exceptions.HTTPException as e: return request._handle_exception(e) request.set_handler(func, arguments, "none") result = request.dispatch() return result with request: # ===PERHATIKAN KODE DI BAWAH ==== if not request.session.db and not request.params.get('db'): request.session.update({'db': 'test'}) db = request.session.db # ===PERHATIKAN KODE DI ATAS ==== if db: try: odoo.registry(db).check_signaling() with odoo.tools.mute_logger('odoo.sql_db'): ir_http = request.registry['ir.http'] except (AttributeError, psycopg2.OperationalError, psycopg2.ProgrammingError): # psycopg2 error or attribute error while constructing # the registry. That means either # - the database probably does not exists anymore # - the database is corrupted # - the database version doesnt match the server version # Log the user out and fall back to nodb request.session.logout() # If requesting /web this will loop if request.httprequest.path == '/web': result = werkzeug.utils.redirect('/web/database/selector') else: result = _dispatch_nodb() else: result = ir_http._dispatch() else: result = _dispatch_nodb() response = self.get_response(httprequest, result, explicit_session) return response(environ, start_response) except werkzeug.exceptions.HTTPException as e: return e(environ, start_response)