Tryton vs OpenERP

Tryton vs OpenERP

Author: Cédric Krier
Date: 2011-11-11

Project Organisation

  • OpenERP
    • OpenERP SA
    • Partnership contract
    • Loyalty to OpenERP SA
  • Tryton
    • Meritocratie
    • Community
    • Free-speach

Licenses

  • OpenERP
    • GPL-2 -> GPL-3 -> AGPL-3
    • Other Licenses from embeded libraries
    • AGPL-3 + Exception (not clear)
  • Tryton
    • GPL-3
    • LGPL-3 (proteus)

Maintenance

  • OpenERP
    • 4.5 years (for 3 LT series + 1 series)
  • Tryton
    • 2.5 years (for 5 series)

Release Cycle

  • OpenERP
    • every 6 months (But still waiting 6.1 since September)
  • Tryton
    • every 6 months

Release Policy

  • OpenERP
    • Minor: no new features (database update needed)
    • Major: without migration
  • Tryton
    • Minor: no API, XML change (no database update)
    • Major: migration included

Packaging

  • OpenERP
    • 1 big archive
    • Windows exe
    • .deb
  • Tryton
    • Python Packages for each modules
    • Windows exe for client
    • MacOS for client (beta)
    • In many major OSS UNIX

Code Quality

  • OpenERP
  • Tryton
    • PEP8
    • Code Review
    • Standard Unittest + Scenario

Code Quality Example

Which one do you want to read every day?

comparison_sale.png

OpenERP Unittest

13 tests

openerp_unittest.png

54% coverage

openerp_coverage.png

Tryton Unittest

310 tests

tryton_unittest.png

69% coverage

tryton_coverage.png

Usability

  • Autodetect protocol
  • Show only valid database
  • Keyboard only
  • Search limit: 80 -> 1000
  • Mark for deletion
  • Editable Tree
  • Window Manager
  • Remember column width
  • Remember tree state
  • Direct Print or Email

Business Design

  • OpenERP
    • Full-feature
    • Default value
  • Tryton
    • KISS
    • Configuration (Singleton)
    • 1 module for 1 concept
    • Works on line instead of document

Sale

  • No procurement (based on draft stock move)
  • Only sale create the invoice (not the picking)
  • Shipment 2 steps (storage -> output -> customer)
  • Manage shipment and invoice exception
  • Show by default <1 year old

Shipment

  • Inventory doesn't depend on confirmation date
  • Store cost price and unit price on each move

Account

  • Use tax lines for many tax code or amount
    • instead of duplicate move lines

Purchase

  • No shipment created
    • Move lines to fill in shipment
  • Manage shipment and invoice exception

  • Show by default <1 year old

Coding

  • OpenERP
    • method(self, cr, uid, ids, context=None)
    • self.pool
  • Tryton
    • method(self, ids)
    • Transaction
    • Pool

Models

  • OpenERP
    • osv - Model
    • osv_memory - TransientModel
    • osv_abstract - AbstractModel (never used)
  • Tryton
    • ModelView
    • ModelSQL (ModelStorage)

Fields

  • OpenERP
    • float -> float
    • date -> string
    • datetime -> string
  • Tryton
    • Float -> float
    • Numeric -> Decimal
    • Date -> datetime.date
    • DateTime -> datetime.datetime
    • One2One

OpenERP - Function fields

  • use address method
  • store
def _amount_all(self, cr, uid, ids, field_name, arg, context=None):
    res = {}
    for order in self.browse(cr, uid, ids, context=context):
        ...
    return res

OpenERP - Function fields

'amount_total': fields.function(_amount_all, digits_compute= dp.get_precision('Sale Price'), string='Total',
    store = {
        'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
        'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
    },
    multi='sums', help="The total amount."),

Tryton - Function fields

  • use method name
total_amount = fields.Function(fields.Numeric('Total',
        digits=(16, Eval('currency_digits', 2)),
        depends=['currency_digits']), 'get_total_amount')

def get_total_amount(self, ids, name):
    result = {}
    for sale in self.browse(ids):
        ...
    return result

OpenERP on_change - Definition

  • in view
  • in xml -> not extensible
<field name="partner_id"
    on_change="onchange_partner_id(partner_id)"
    domain="[('customer','=',True)]"
    context="{'search_default_customer':1}"
    required="1"/>

OpenERP on_change - Method

  • position values
  • return new domain, new context, warning and new fields value
def onchange_partner_id(self, cr, uid, ids, part):
    if not part:
        return {'value': {'partner_invoice_id': False, 'partner_shipping_id': False, 'partner_order_id': False, 'payment_term': False, 'fiscal_position': False}}

    addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['delivery', 'invoice', 'contact'])
    part = self.pool.get('res.partner').browse(cr, uid, part)
    ...
    return {'value': val}

Tryton on_change - Definition

  • on field
  • extensible
party = fields.Many2One('party.party', 'Party',
    required=True, select=1, states={
        'readonly': Eval('state') != 'draft',
        }, on_change=['party', 'payment_term'],
    depends=['state'])

Tryton on_change - Method

  • fixed name
  • 1 dict with values
  • return only fields value to change
def on_change_party(self, values):
    party_obj = Pool().get('party.party')
    res = {}
    if values.get('party'):
        party = party_obj.browse(values['party'])
    ...
    return res

OpenERP Digits

  • Fixed per field
'amount_total': fields.function(_amount_all,
    digits_compute= dp.get_precision('Sale Price'), string='Total',
    store = {
        'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 10),
        'sale.order.line': (_get_order, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10),
    },
    multi='sums', help="The total amount."),

Tryton Digits

  • Dynamic
  • PYSON
currency_digits = fields.Function(fields.Integer('Currency Digits',
    on_change_with=['currency']), 'get_function_fields')
total_amount = fields.Function(fields.Numeric('Total',
        digits=(16, Eval('currency_digits', 2)),
        depends=['currency_digits']), 'get_total_amount')

Security

  • OpenERP
    • Password stored in clear text by default
    • Rules and Model Access (CRWU)
    • Field Access on view
  • Tryton
    • Password encrypted (SHA-1)
    • Rules and Model Access (CRWD)
    • Field Access (tested also server side)
    • Domain and digits validated server side

Data Loading

  • OpenERP
    • XML
    • csv
    • SQL
    • YAML
  • Tryton
    • XML (readonly by default)

Report Engine

  • OpenERP
    • RML
    • HTML
    • makohtml
    • odt
    • Webkit
  • Tryton
    • Relatorio

Wizard

  • OpenERP
    • wizard.interface
    • osv_memory
  • Tryton
    • Wizard (To be improved for 2.4)

Not for Tryton

  • logging notification
  • group by -> board communication
  • gettext-like without context

Thanks