Tryton vs OpenERP
Tryton vs OpenERP
TUL2011 © Cédric Krier CC-by-SA-3.0
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
No coding style
- Code Review which looks like testing
-
Custom YAML
- Tryton
- PEP8
- Code Review
- Standard Unittest + Scenario
Code Quality Example
Which one do you want to read every day?
OpenERP Unittest
13 tests
54% coverage
Tryton Unittest
310 tests
69% coverage
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
Tryton vs OpenERP
TUL2011 © Cédric Krier CC-by-SA-3.0
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
No coding style
- Code Review which looks like testing
Custom YAML
- Tryton
- PEP8
- Code Review
- Standard Unittest + Scenario
Code Quality Example
Which one do you want to read every day?
OpenERP Unittest
13 tests
54% coverage
Tryton Unittest
310 tests
69% coverage
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