diff --git a/addons/account/__init__.py b/addons/account/__init__.py index 90fbdb83980..bc27e14380c 100644 --- a/addons/account/__init__.py +++ b/addons/account/__init__.py @@ -19,10 +19,10 @@ # ############################################################################## +import partner import account import installer import project -import partner import account_invoice import account_bank_statement import account_bank diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index e1b9078ec3f..86166ec0125 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -19,11 +19,11 @@ # ############################################################################## { - "name" : "eInvoicing", - "version" : "1.1", - "author" : "OpenERP SA", - "category": 'Accounting & Finance', - "description": """ + 'name' : 'eInvoicing', + 'version' : '1.1', + 'author' : 'OpenERP SA', + 'category' : 'Accounting & Finance', + 'description' : """ Accounting and Financial Management. ==================================== @@ -44,14 +44,13 @@ Creates a dashboard for accountants that includes: * Company Analysis * Graph of Treasury -The processes like maintaining of general ledger is done through the defined financial Journals (entry move line orgrouping is maintained through journal) for a particular -financial year and for preparation of vouchers there is a module named account_voucher. +The processes like maintaining of general ledger is done through the defined financial Journals (entry move line orgrouping is maintained through journal) +for a particular financial year and for preparation of vouchers there is a module named account_voucher. """, 'website': 'http://www.openerp.com', 'images' : ['images/accounts.jpeg','images/bank_statement.jpeg','images/cash_register.jpeg','images/chart_of_accounts.jpeg','images/customer_invoice.jpeg','images/journal_entries.jpeg'], - 'init_xml': [], - "depends" : ["base_setup", "product", "analytic", "process", "board", "edi"], - 'update_xml': [ + 'depends' : ['base_setup', 'product', 'analytic', 'process', 'board', 'edi'], + 'data': [ 'security/account_security.xml', 'security/ir.model.access.csv', 'account_menuitem.xml', @@ -122,12 +121,12 @@ financial year and for preparation of vouchers there is a module named account_v 'ir_sequence_view.xml', 'company_view.xml', 'board_account_view.xml', - "edi/invoice_action_data.xml", - "account_bank_view.xml", - "res_config_view.xml", - "account_pre_install.yml" + 'edi/invoice_action_data.xml', + 'account_bank_view.xml', + 'res_config_view.xml', + 'account_pre_install.yml' ], - 'demo_xml': [ + 'demo': [ 'demo/account_demo.xml', 'project/project_demo.xml', 'project/analytic_account_demo.xml', diff --git a/addons/account/account.py b/addons/account/account.py index fa30b20f2ca..907e6207380 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -582,6 +582,8 @@ class account_account(osv.osv): def name_get(self, cr, uid, ids, context=None): if not ids: return [] + if isinstance(ids, (int, long)): + ids = [ids] reads = self.read(cr, uid, ids, ['name', 'code'], context=context) res = [] for record in reads: diff --git a/addons/account/account_bank_view.xml b/addons/account/account_bank_view.xml index 4b3436c8a51..8ceb8a91885 100644 --- a/addons/account/account_bank_view.xml +++ b/addons/account/account_bank_view.xml @@ -9,7 +9,6 @@ Partner Bank Accounts - Journal res.partner.bank - form @@ -26,7 +25,6 @@ Partner Bank Accounts - Add currency on tree res.partner.bank - tree diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml index d2661674bae..c92d4eda602 100644 --- a/addons/account/account_installer.xml +++ b/addons/account/account_installer.xml @@ -3,7 +3,6 @@ account.installer.form account.installer - form
diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 064ba419ebd..7bc9ceaaf61 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1127,7 +1127,7 @@ class account_invoice(osv.osv): return map(lambda x: (0,0,x), lines) def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None): - invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id']) + invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id', 'company_id']) obj_invoice_line = self.pool.get('account.invoice.line') obj_invoice_tax = self.pool.get('account.invoice.tax') obj_journal = self.pool.get('account.journal') @@ -1175,7 +1175,7 @@ class account_invoice(osv.osv): 'name': description, }) # take the id part of the tuple returned for many2one fields - for field in ('partner_id', + for field in ('partner_id', 'company_id', 'account_id', 'currency_id', 'payment_term', 'journal_id'): invoice[field] = invoice[field] and invoice[field][0] # create the new invoice @@ -1351,11 +1351,11 @@ class account_invoice_line(osv.osv): 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), 'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), 'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."), - 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Account')), + 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')), 'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float", digits_compute= dp.get_precision('Account'), store=True), - 'quantity': fields.float('Quantity', required=True), - 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Account')), + 'quantity': fields.float('Quantity', digits_compute= dp.get_precision('Product Unit of Measure'), required=True), + 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')), 'invoice_line_tax_id': fields.many2many('account.tax', 'account_invoice_line_tax', 'invoice_line_id', 'tax_id', 'Taxes', domain=[('parent_id','=',False)]), 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'), 'company_id': fields.related('invoice_id','company_id',type='many2one',relation='res.company',string='Company', store=True, readonly=True), diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index d04030c909e..143c5514141 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -6,7 +6,6 @@ account.invoice.calendar account.invoice - calendar @@ -18,7 +17,6 @@ account.invoice.graph account.invoice - graph @@ -30,7 +28,6 @@ account.invoice.line.tree account.invoice.line - tree @@ -47,7 +44,6 @@ account.invoice.line.form account.invoice.line - form @@ -78,7 +74,6 @@ account.invoice.tax.tree account.invoice.tax - tree @@ -94,7 +89,6 @@ account.invoice.tax.form account.invoice.tax - form @@ -120,7 +114,6 @@ account.invoice.tree account.invoice - tree @@ -146,10 +139,9 @@ account.invoice.supplier.form account.invoice - form 2 - +
+ +or + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/auth_oauth/static/lib/zocial/css/zocial-regular-webfont.ttf b/addons/auth_oauth/static/lib/zocial/css/zocial-regular-webfont.ttf new file mode 100755 index 00000000000..94809d3a57f Binary files /dev/null and b/addons/auth_oauth/static/lib/zocial/css/zocial-regular-webfont.ttf differ diff --git a/addons/auth_oauth/static/lib/zocial/css/zocial-regular-webfont.woff b/addons/auth_oauth/static/lib/zocial/css/zocial-regular-webfont.woff new file mode 100755 index 00000000000..1d6c4abc9d9 Binary files /dev/null and b/addons/auth_oauth/static/lib/zocial/css/zocial-regular-webfont.woff differ diff --git a/addons/auth_oauth/static/lib/zocial/css/zocial.css b/addons/auth_oauth/static/lib/zocial/css/zocial.css new file mode 100644 index 00000000000..89fc7450631 --- /dev/null +++ b/addons/auth_oauth/static/lib/zocial/css/zocial.css @@ -0,0 +1,420 @@ +@charset "UTF-8"; + +/*! +Code written by Sam Collins (@smcllns) of www.eventasaur.us +You are free to use this work commercially +You are free to extend this work without permissions from the author (just do so tastefully eh?) +Enjoy +*/ + +/* Reference icons from font-files */ + +@font-face { + font-family: 'zocial'; + font-style: normal; + font-weight: normal; + src: url('zocial-regular-webfont.eot'); + src: url('zocial-regular-webfont.eot?#iefix') format('embedded-opentype'), + url('zocial-regular-webfont.woff') format('woff'), + url('zocial-regular-webfont.ttf') format('truetype'), + url('zocial-regular-webfont.svg#ZocialRegular') format('svg'); + unicode-range: U+0-U+10FFFF; +} + +/* Button structure */ + +.zocial, +a.zocial { + border: 1px solid #777; + border-color: rgba(0,0,0,0.2); + border-bottom-color: #333; + border-bottom-color: rgba(0,0,0,0.4); + color: #fff; + -moz-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.4), inset 0 0 0.1em rgba(255,255,255,0.9); + -webkit-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.4), inset 0 0 0.1em rgba(255,255,255,0.9); + box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.4), inset 0 0 0.1em rgba(255,255,255,0.9); + cursor: pointer; + display: inline-block; + font: bold 100%/2.1 "Lucida Grande", Tahoma, sans-serif; + padding: 0 .95em 0 0; + text-align: center; + text-decoration: none; + text-shadow: 0 1px 0 rgba(0,0,0,0.5); + white-space: nowrap; + + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + + position: relative; + + -moz-border-radius: .3em; + -webkit-border-radius: .3em; + border-radius: .3em; +} + +.zocial:before { + content: ""; + border-right: 0.075em solid rgba(0,0,0,0.1); + float: left; + font: 120%/1.65 zocial; + font-style: normal; + font-weight: normal; + margin: 0 0.5em 0 0; + padding: 0 0.5em; + text-align: center; + text-decoration: none; + text-transform: none; + + -moz-box-shadow: 0.075em 0 0 rgba(255,255,255,0.25); + -webkit-box-shadow: 0.075em 0 0 rgba(255,255,255,0.25); + box-shadow: 0.075em 0 0 rgba(255,255,255,0.25); + + -webkit-font-smoothing: antialiased; +} + +.zocial:active { + outline: none; /* outline is visible on :focus */ +} + +/* Buttons can be displayed as standalone icons by adding a class of "icon" */ + +.zocial.icon { + overflow: hidden; + max-width: 2.4em; + padding-left: 0; + padding-right: 0; + max-height: 2.15em; + white-space: nowrap; +} +.zocial.icon:before { + padding: 0; + width: 2em; + height: 2em; + + box-shadow: none; + border: none; +} + +/* Gradients */ + +.zocial { + background-image: -moz-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: -ms-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: -o-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.1)), color-stop(49%, rgba(255,255,255,.05)), color-stop(51%, rgba(0,0,0,.05)), to(rgba(0,0,0,.1))); + background-image: -webkit-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); +} + +.zocial:hover, .zocial:focus { + background-image: -moz-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: -ms-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: -o-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.15)), color-stop(49%, rgba(255,255,255,.15)), color-stop(51%, rgba(0,0,0,.1)), to(rgba(0,0,0,.15))); + background-image: -webkit-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); +} + +.zocial:active { + background-image: -moz-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: -ms-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: -o-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.1)), color-stop(30%, rgba(255,255,255,0)), color-stop(50%, transparent), to(rgba(0,0,0,.1))); + background-image: -webkit-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); +} + +/* Adjustments for light background buttons */ + +.zocial.bitcoin, +.zocial.cloudapp, +.zocial.dropbox, +.zocial.email, +.zocial.eventful, +.zocial.github, +.zocial.gmail, +.zocial.instapaper, +.zocial.itunes, +.zocial.ninetyninedesigns, +.zocial.openid, +.zocial.plancast, +.zocial.posterous, +.zocial.reddit, +.zocial.secondary, +.zocial.viadeo, +.zocial.weibo, +.zocial.wikipedia { + border: 1px solid #aaa; + border-color: rgba(0,0,0,0.3); + border-bottom-color: #777; + border-bottom-color: rgba(0,0,0,0.5); + -moz-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.7), inset 0 0 0.08em rgba(255,255,255,0.5); + -webkit-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.7), inset 0 0 0.08em rgba(255,255,255,0.5); + box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.7), inset 0 0 0.08em rgba(255,255,255,0.5); + text-shadow: 0 1px 0 rgba(255,255,255,0.8); +} + +/* :hover adjustments for light background buttons */ + +.zocial.bitcoin:focus, +.zocial.bitcoin:hover, +.zocial.dropbox:focus, +.zocial.dropbox:hover, +.zocial.email:focus, +.zocial.email:hover, +.zocial.eventful:focus, +.zocial.eventful:hover, +.zocial.github:focus, +.zocial.github:hover, +.zocial.gmail:focus, +.zocial.gmail:hover, +.zocial.instapaper:focus, +.zocial.instapaper:hover, +.zocial.itunes:focus, +.zocial.itunes:hover, +.zocial.ninetyninedesigns:focus, +.zocial.ninetyninedesigns:hover, +.zocial.openid:focus, +.zocial.openid:hover, +.zocial.plancast:focus, +.zocial.plancast:hover, +.zocial.posterous:focus, +.zocial.posterous:hover, +.zocial.reddit:focus, +.zocial.reddit:hover, +.zocial.secondary:focus, +.zocial.secondary:hover, +.zocial.twitter:focus, +.zocial.viadeo:focus, +.zocial.viadeo:hover, +.zocial.weibo:focus, +.zocial.weibo:hover, +.zocial.wikipedia:focus, +.zocial.wikipedia:hover { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.5)), color-stop(49%, rgba(255,255,255,0.2)), color-stop(51%, rgba(0,0,0,0.05)), to(rgba(0,0,0,0.15))); + background-image: -moz-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: -webkit-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: -o-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: -ms-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); +} + +/* :active adjustments for light background buttons */ + +.zocial.bitcoin:active, +.zocial.dropbox:active, +.zocial.email:active, +.zocial.eventful:active, +.zocial.github:active, +.zocial.gmail:active, +.zocial.instapaper:active, +.zocial.itunes:active, +.zocial.ninetyninedesigns:active, +.zocial.openid:active, +.zocial.plancast:active, +.zocial.posterous:active, +.zocial.reddit:active, +.zocial.secondary:active, +.zocial.viadeo:active, +.zocial.weibo:active, +.zocial.wikipedia:active { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0)), color-stop(30%, rgba(255,255,255,0)), color-stop(50%, rgba(0,0,0,0)), to(rgba(0,0,0,0.1))); + background-image: -moz-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: -webkit-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: -o-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: -ms-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); +} + +/* Button icon and color */ +/* Icon characters are stored in unicode private area */ +.zocial.amazon:before {content: "\E040";} +.zocial.android:before {content: "\E005";} +.zocial.angellist:before {content: "\E06C";} +.zocial.aol:before {content: "\E001";} +.zocial.appstore:before {content: "\E020";} +.zocial.bitcoin:before {content: "\E011"; color: #f7931a;} +.zocial.blogger:before {content: "\E021";} +.zocial.call:before {content: "\E016";} +.zocial.cal:before {content: "\E00D";} +.zocial.cart:before {content: "\E06A";} +.zocial.chrome:before {content: "\E03A";} +.zocial.cloudapp:before {content: "\E042";} +.zocial.creativecommons:before {content: "\E022";} +.zocial.delicious:before {content: "\E002";} +.zocial.digg:before {content: "\E01A";} +.zocial.disqus:before {content: "\E030";} +.zocial.dribbble:before {content: "\E023";} +.zocial.dropbox:before {content: "\E043"; color: #1f75cc;} +.zocial.email:before {content: "\E03C"; color: #312c2a;} +.zocial.eventasaurus:before {content: "\E055"; color: #9de428;} +.zocial.eventbrite:before {content: "\E05B";} +.zocial.eventful:before {content: "\E006"; color: #0066CC;} +.zocial.evernote:before {content: "\E024";} +.zocial.facebook:before {content: "\E045";} +.zocial.fivehundredpx:before {content: "\E00F"; color: #29b6ff;} +.zocial.flattr:before {content: "\E004";} +.zocial.flickr:before {content: "\E025";} +.zocial.forrst:before {content: "\E019"; color: #50894f;} +.zocial.foursquare:before {content: "\E013";} +.zocial.github:before {content: "\E046";} +.zocial.gmail:before {content: "\E04C"; color: #f00;} +.zocial.google:before {content: "\E026";} +.zocial.googleplay:before {content: "\E05E";} +.zocial.googleplus:before {content: "\E00A";} +.zocial.gowalla:before {content: "\E01F";} +.zocial.grooveshark:before {content: "\E017";} +.zocial.guest:before {content: "\E01E";} +.zocial.html5:before {content: "\E014";} +.zocial.ie:before {content: "\E015";} +.zocial.instagram:before {content: "\E06D";} +.zocial.instapaper:before {content: "\E028";} +.zocial.intensedebate:before {content: "\E05A";} +.zocial.itunes:before {content: "\E048"; color: #1a6dd2;} +.zocial.klout:before {content: "\E02A"; } +.zocial.lanyrd:before {content: "\E00C";} +.zocial.lastfm:before {content: "\E04B";} +.zocial.linkedin:before {content: "\E02B";} +.zocial.macstore:before {content: "\E03D";} +.zocial.meetup:before {content: "\E02C";} +.zocial.myspace:before {content: "\E03E";} +.zocial.ninetyninedesigns:before {content: "\E018"; color: #f50;} +.zocial.openid:before {content: "\E04E"; color: #ff921d;} +.zocial.opentable:before {content: "\E05F";} +.zocial.paypal:before {content: "\E003";} +.zocial.pinboard:before {content: "\E04D";} +.zocial.pinterest:before {content: "\E010";} +.zocial.plancast:before {content: "\E02F";} +.zocial.plurk:before {content: "\E049";} +.zocial.podcast:before {content: "\E03F";} +.zocial.posterous:before {content: "\E05D";} +.zocial.print:before {content: "\E06B";} +.zocial.quora:before {content: "\E050";} +.zocial.reddit:before {content: "\E01D"; color: red;} +.zocial.rss:before {content: "\E031";} +.zocial.scribd:before {content: "\E05C"; color: #00d5ea;} +.zocial.skype:before {content: "\E032";} +.zocial.smashing:before {content: "\E009";} +.zocial.songkick:before {content: "\E04A";} +.zocial.soundcloud:before {content: "\E052";} +.zocial.spotify:before {content: "\E01C";} +.zocial.stumbleupon:before {content: "\E00E";} +.zocial.tumblr:before {content: "\E053";} +.zocial.twitter:before {content: "\E033";} +.zocial.viadeo:before {content: "\E027"; color: #f59b20;} +.zocial.vimeo:before {content: "\E035";} +.zocial.weibo:before {content: "\E029"; color: #e6162d;} +.zocial.wikipedia:before {content: "\E00B";} +.zocial.windows:before {content: "\E036";} +.zocial.xing:before {content: "\E037"} +.zocial.wordpress:before {content: "\E056";} +.zocial.yahoo:before {content: "\E038";} +.zocial.yelp:before {content: "\E058";} +.zocial.youtube:before {content: "\E034";} + +/* Button background and text color */ + +.zocial.amazon {background-color: #ffad1d; color: #030037; text-shadow: 0 1px 0 rgba(255,255,255,0.5);} +.zocial.android {background-color: #a4c639;} +.zocial.angellist {background-color: #000;} +.zocial.aol {background-color: #f00;} +.zocial.appstore {background-color: #000;} +.zocial.bitcoin {background-color: #efefef; color: #4d4d4d;} +.zocial.blogger {background-color: #ee5a22;} +.zocial.call {background-color: #008000;} +.zocial.cal {background-color: #d63538;} +.zocial.cart {background-color: #333;} +.zocial.chrome {background-color: #006cd4;} +.zocial.cloudapp {background-color: #fff; color: #312c2a;} +.zocial.creativecommons {background-color: #000;} +.zocial.delicious {background-color: #3271cb;} +.zocial.digg {background-color: #164673;} +.zocial.disqus {background-color: #5d8aad;} +.zocial.dribbble {background-color: #ea4c89;} +.zocial.dropbox {background-color: #fff; color: #312c2a;} +.zocial.email {background-color: #f0f0eb; color: #312c2a;} +.zocial.eventasaurus {background-color: #192931; color: #fff;} +.zocial.eventbrite {background-color: #ff5616;} +.zocial.eventful {background-color: #fff; color: #47ab15;} +.zocial.evernote {background-color: #6bb130; color: #fff;} +.zocial.facebook {background-color: #4863ae;} +.zocial.fivehundredpx {background-color: #333;} +.zocial.flattr {background-color: #8aba42;} +.zocial.flickr {background-color: #ff0084;} +.zocial.forrst {background-color: #1e360d;} +.zocial.foursquare {background-color: #44a8e0;} +.zocial.github {background-color: #fbfbfb; color: #050505;} +.zocial.gmail {background-color: #efefef; color: #222;} +.zocial.google {background-color: #4e6cf7;} +.zocial.googleplay {background-color: #000;} +.zocial.googleplus {background-color: #dd4b39;} +.zocial.gowalla {background-color: #ff720a;} +.zocial.grooveshark {background-color: #111; color:#eee;} +.zocial.guest {background-color: #1b4d6d;} +.zocial.html5 {background-color: #ff3617;} +.zocial.ie {background-color: #00a1d9;} +.zocial.instapaper {background-color: #eee; color: #222;} +.zocial.instagram {background-color: #3f729b;} +.zocial.intensedebate {background-color: #0099e1;} +.zocial.klout {background-color: #e34a25;} +.zocial.itunes {background-color: #efefeb; color: #312c2a;} +.zocial.lanyrd {background-color: #2e6ac2;} +.zocial.lastfm {background-color: #dc1a23;} +.zocial.linkedin {background-color: #0083a8;} +.zocial.macstore {background-color: #007dcb} +.zocial.meetup {background-color: #ff0026;} +.zocial.myspace {background-color: #000;} +.zocial.ninetyninedesigns {background-color: #fff; color: #072243;} +.zocial.openid {background-color: #f5f5f5; color: #333;} +.zocial.opentable {background-color: #990000;} +.zocial.paypal {background-color: #fff; color: #32689a; text-shadow: 0 1px 0 rgba(255,255,255,0.5);} +.zocial.pinboard {background-color: blue;} +.zocial.pinterest {background-color: #c91618;} +.zocial.plancast {background-color: #e7ebed; color: #333;} +.zocial.plurk {background-color: #cf682f;} +.zocial.podcast {background-color: #9365ce;} +.zocial.posterous {background-color: #ffd959; color: #bc7134;} +.zocial.print {background-color: #f0f0eb; color: #222; text-shadow: 0 1px 0 rgba(255,255,255,0.8);} +.zocial.quora {background-color: #a82400;} +.zocial.reddit {background-color: #fff; color: #222;} +.zocial.rss {background-color: #ff7f25;} +.zocial.scribd {background-color: #231c1a;} +.zocial.skype {background-color: #00a2ed;} +.zocial.smashing {background-color: #ff4f27;} +.zocial.songkick {background-color: #ff0050;} +.zocial.soundcloud {background-color: #ff4500;} +.zocial.spotify {background-color: #60af00;} +.zocial.stumbleupon {background-color: #eb4924;} +.zocial.tumblr {background-color: #374a61;} +.zocial.twitter {background-color: #46c0fb;} +.zocial.viadeo {background-color: #fff; color: #000;} +.zocial.vimeo {background-color: #00a2cd;} +.zocial.weibo {background-color: #faf6f1; color: #000;} +.zocial.wikipedia {background-color: #fff; color: #000;} +.zocial.windows {background-color: #0052a4; color: #fff;} +.zocial.wordpress {background-color: #464646;} +.zocial.xing {background-color: #0A5D5E;} +.zocial.yahoo {background-color: #a200c2;} +.zocial.yelp {background-color: #e60010;} +.zocial.youtube {background-color: #f00;} + +/* +The Miscellaneous Buttons +These button have no icons and can be general purpose buttons while ensuring consistent button style +Credit to @guillermovs for suggesting +*/ + +.zocial.primary, .zocial.secondary {margin: 0.1em 0; padding: 0 1em;} +.zocial.primary:before, .zocial.secondary:before {display: none;} +.zocial.primary {background-color: #333;} +.zocial.secondary {background-color: #f0f0eb; color: #222; text-shadow: 0 1px 0 rgba(255,255,255,0.8);} + +/* Any browser-specific adjustments */ + +button:-moz-focus-inner { + border: 0; + padding: 0; +} + + diff --git a/addons/auth_oauth/static/lib/zocial/sample.html b/addons/auth_oauth/static/lib/zocial/sample.html new file mode 100644 index 00000000000..98dec554ff1 --- /dev/null +++ b/addons/auth_oauth/static/lib/zocial/sample.html @@ -0,0 +1,265 @@ + + + + + Zocial CSS3 Buttons + + + + + + + + + + + + + Sign in with Google+ + + Sign in with LinkedIn + +

The Cool Kids

+ Sync with Dropbox + Clip to Evernote + Follow me on Forrst + Sign in with Dribbble + Sign in to CloudApp + Fork me on Github + Play on Spotify + Read It Later + Follow me on Soundcloud + Follow me on Tumblr + Read on Smashing Magazine + Available on iTunes + Available on the App Store + Available on the Mac App Store + Available on Android Market + Follow me on Pinterest + Follow me on Quora + Attend on Lanyrd + +

The Not-So-Cool But Have-To-Be-Invited Kids

+ Pay with Paypal + Sign in with Amazon + Call me on Skype + Sign in with Last.fm + Write a review on Yelp + Check in with foursquare + Influence with Klout + +

The Older (but Solid) Kids

+ View on Wikipedia + Sign in with Disqus + Sign in with IntenseDebate + Sign in with Google + Sign in with Gmail + Upload to Vimeo + Read more on Scribd + Subscribe on YouTube + Sign in with WordPress + Sign in with Songkick + Sign in with Posterous + Sign in with Eventbrite + Tip with Flattr + Follow me on Plancast + + +

The Kids That Kinda Smell but Some People Don't Mind

+ Submit resume for CEO + Download Internet Explorer 5 + Report bugs with Meetup.com + Learn how-to-use OpenID + Register now for HTML6 + Chat with your parents + +

The Kids That Nobody Normally Notices

+ Sign in as guest + View Creative Commons Licence + Subscribe to RSS + Add to Chrome + +

The He's-My-Son-So-Of-Course-He's-Here Kid

+ Sign up for Eventasaurus + +

Kids By Request

+ Join me on Weibo + Sign in with Plurk + Play on Grooveshark + Post on Blogger + Sign in with Viadeo + Subscribe to this Podcast + View Portfolio on 500px + Bitcoin accepted here + View Portfolio on 99Designs + Bookmark with Pinboard + Stumble! + Find me on Myspace + Sign in with Windows Live + Find Events with Eventful + Sign in with Xing + Upload to Flickr + Sign in with Del.icio.us + Download from Google Play + Reserve with OpenTable + Digg this + Share on Reddit + Fund us on AngelList + Sign-in with Instagram + +

The Multi-Purpose Kids (Credit: Pictos Icons)

+ + Call a phone + + Add to calendar + Add to cart + Print this page + Primary action + Secondary action + + +

Icon versions of the above

+ + Sign in with Google+ + + Sign in with Google + Sign in with LinkedIn + Pay with Paypal + Sign in with Amazon + Sync with Dropbox + Clip to Evernote + Call me on Skype + Sign in as guest + Play on Spotify + Sign in with Last.fm + Sign in with Songkick + Follow me on Forrst + Sign in with Dribbble + Sign in to CloudApp + Fork me on Github + Follow me on Pinterest + Follow me on Quora + Bookmark with Pinboard + Attend on Lanyrd + Download on iTunes + Download on Android + Sign in with Disqus + Sign in with Yahoo + Upload to Vimeo + Add to Chrome + Get a new browser + Made from HTML5 + Read It Later + Read more on Scribd + View on Wikipedia + Tip with Flattr + Follow me on Tumblr + Subscribe to my Posterous + Check in with Gowalla + Check in with foursquare + Write a review on Yelp + Follow me on Soundcloud + Read on Smashing Magazine + Sign in with WordPress + Sign in with IntenseDebate + Sign in with OpenID + Sign in with Gmail + Sign in with Eventbrite + Sign in with Eventasaurus + Sign in with Meetup.com + Sign in with AIM + Follow me on Plancast + Subscribe on YouTube + Available on the Mac App Store + View Creative Commons Licence + Subscribe to RSS + Follow me on Weibo + Follow me on Plurk + Follow me on Grooveshark + Post on Blogger + Sign in with Viadeo + Subscribe to this Podcast + View Portfolio on 500px + Bitcoin accepted here + View Portfolio on 99Designs + Stumble! + Download on iTunes + Find me on Myspace + Sign in with Windows Live + Find Events with Eventful + Influence with Klout + Sign in with Xing + Upload to Flickr + Sign in with Del.icio.us + Download from Google Play + Reserve with OpenTable + Digg this + Share on Reddit + Fund us on AngelList + Sign-in with Instagram + Call a phone + + Add to calendar + Print this page + Add to cart + + + +

Thanks to @guillermovs, @kamens, @vizualover, and @leaverou for code refinements and suggestions.

+ +

Massive thanks to @drewwilson for making the multi-purpose buttons possible with his incredible Pictos icons.

+ +

See code samples at zocial.smcllns.com — ask questions to @smcllns

+ + + + + + + + diff --git a/addons/auth_oauth/static/src/js/auth_oauth.js b/addons/auth_oauth/static/src/js/auth_oauth.js new file mode 100644 index 00000000000..d63631c262d --- /dev/null +++ b/addons/auth_oauth/static/src/js/auth_oauth.js @@ -0,0 +1,62 @@ +openerp.auth_oauth = function(instance) { + var QWeb = instance.web.qweb; + + instance.web.Login = instance.web.Login.extend({ + start: function(parent, params) { + var d = this._super.apply(this, arguments); + this.$element.on('click', 'a.zocial', this.on_oauth_sign_in); + this.oauth_providers = []; + if(this.params.oauth_error === 1) { + this.do_warn("Sign up error.","Sign up is not allowed on this database."); + } else if(this.params.oauth_error === 2) { + this.do_warn("Authentication error",""); + } + return d.then(this.do_oauth_load); + }, + do_oauth_load: function() { + var db = this.$("form [name=db]").val(); + if (db) { + this.rpc("/auth_oauth/list_providers", { dbname: db }).then(this.on_oauth_loaded); + } + }, + on_oauth_loaded: function(result) { + this.oauth_providers = result; + var buttons = QWeb.render("auth_oauth.Login.button",{"widget":this}); + this.$(".oe_login_pane form ul").after(buttons); + }, + on_oauth_sign_in: function(ev) { + ev.preventDefault(); + var index = $(ev.target).data('index'); + var p = this.oauth_providers[index]; + var ret = location.protocol+"//"+location.host+"/"; + var dbname = self.$("form [name=db]").val(); + var state_object = { + d: dbname, + p: p.id + } + var state = JSON.stringify(state_object); + var params = { + response_type: 'token', + client_id: p.client_id, + redirect_uri: ret, + scope: p.scope, + state: state, + }; + var url = p.auth_endpoint + '?' + $.param(params); + window.location = url; + }, + }); + + instance.web.WebClient = instance.web.WebClient.extend({ + start: function() { + this._super.apply(this, arguments); + var params = $.deparam(window.location.hash.substring(1)); + // alert(JSON.stringify(params)); + if (params.hasOwnProperty('access_token')) { + var url = "/auth_oauth/signin" + '?' + $.param(params); + window.location = url; + } + }, + }); + +}; diff --git a/addons/auth_oauth/static/src/xml/auth_oauth.xml b/addons/auth_oauth/static/src/xml/auth_oauth.xml new file mode 100644 index 00000000000..c2693804e59 --- /dev/null +++ b/addons/auth_oauth/static/src/xml/auth_oauth.xml @@ -0,0 +1,9 @@ + + + + + +
+
+
+
diff --git a/addons/auth_openid/__openerp__.py b/addons/auth_openid/__openerp__.py index cd1a12fce7f..10c77f29965 100644 --- a/addons/auth_openid/__openerp__.py +++ b/addons/auth_openid/__openerp__.py @@ -24,23 +24,18 @@ 'name': 'OpenID Authentification', 'version': '2.0', 'category': 'Tools', - 'description': """Allow users to login through OpenID.""", + 'description': """ +Allow users to login through OpenID. +==================================== +""", 'author': 'OpenERP s.a.', 'maintainer': 'OpenERP s.a.', 'website': 'http://www.openerp.com', 'depends': ['base', 'web'], - 'data': [ - 'res_users.xml', - ], - 'js': [ - 'static/src/js/auth_openid.js', - ], - 'css': [ - 'static/src/css/openid.css', - ], - 'qweb': [ - 'static/src/xml/auth_openid.xml', - ], + 'data': ['res_users.xml'], + 'js': ['static/src/js/auth_openid.js'], + 'css': ['static/src/css/openid.css'], + 'qweb': ['static/src/xml/auth_openid.xml'], 'external_dependencies': { 'python' : ['openid'], }, diff --git a/addons/auth_openid/controllers/main.py b/addons/auth_openid/controllers/main.py index dc81730daf2..eba711dae7a 100644 --- a/addons/auth_openid/controllers/main.py +++ b/addons/auth_openid/controllers/main.py @@ -28,6 +28,7 @@ import werkzeug.urls import werkzeug.exceptions from openerp.modules.registry import RegistryManager +from openerp.addons.web.controllers.main import login_and_redirect, set_cookie_and_redirect try: import openerp.addons.web.common.http as openerpweb except ImportError: @@ -159,7 +160,7 @@ class OpenIDController(openerpweb.Controller): def process(self, req, **kw): session = getattr(req.session, 'openid_session', None) if not session: - return werkzeug.utils.redirect('/') + return set_cookie_and_redirect(req, '/') oidconsumer = consumer.Consumer(session, self._store, consumer_class=GoogleAppsAwareConsumer) @@ -168,12 +169,11 @@ class OpenIDController(openerpweb.Controller): display_identifier = info.getDisplayIdentifier() session['status'] = info.status - user_id = None if info.status == consumer.SUCCESS: dbname = session['dbname'] - with utils.cursor(dbname) as cr: - registry = RegistryManager.get(dbname) + registry = RegistryManager.get(dbname) + with registry.cursor() as cr: Modules = registry.get('ir.module.module') installed = Modules.search_count(cr, 1, ['&', ('name', '=', 'auth_openid'), ('state', '=', 'installed')]) == 1 @@ -206,10 +206,9 @@ class OpenIDController(openerpweb.Controller): # TODO fill empty fields with the ones from sreg/ax cr.commit() - req.session.authenticate(dbname, login, key, {}) + return login_and_redirect(req, dbname, login, key) - if not user_id: - session['message'] = 'This OpenID identifier is not associated to any active users' + session['message'] = 'This OpenID identifier is not associated to any active users' elif info.status == consumer.SETUP_NEEDED: session['message'] = info.setup_url @@ -223,8 +222,7 @@ class OpenIDController(openerpweb.Controller): # information in a log. session['message'] = 'Verification failed.' - fragment = '#loginerror' if not user_id else '' - return werkzeug.utils.redirect('/' + fragment) + return set_cookie_and_redirect(req, '/#action=login&loginerror=1') @openerpweb.jsonrequest def status(self, req): diff --git a/addons/auth_openid/res_users.py b/addons/auth_openid/res_users.py index 3fb8cefcbd4..9b02ce42991 100644 --- a/addons/auth_openid/res_users.py +++ b/addons/auth_openid/res_users.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2010-2011 OpenERP s.a. (). +# Copyright (C) 2010-2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -18,6 +18,7 @@ # along with this program. If not, see . # ############################################################################## +from openerp.modules.registry import RegistryManager from openerp.osv import osv, fields import openerp.exceptions import tools @@ -64,23 +65,22 @@ class res_users(osv.osv): if result: return result else: - with utils.cursor(db) as cr: + with RegistryManager.get(db).cursor() as cr: cr.execute("""UPDATE res_users - SET date=now() AT TIME ZONE 'UTC' + SET login_date=now() AT TIME ZONE 'UTC' WHERE login=%s AND openid_key=%s AND active=%s RETURNING id""", (tools.ustr(login), tools.ustr(password), True)) res = cr.fetchone() cr.commit() return res[0] if res else False - def check(self, db, uid, passwd): try: return super(res_users, self).check(db, uid, passwd) except openerp.exceptions.AccessDenied: if not passwd: raise - with utils.cursor(db) as cr: + with RegistryManager.get(db).cursor() as cr: cr.execute('''SELECT COUNT(1) FROM res_users WHERE id=%s diff --git a/addons/auth_openid/res_users.xml b/addons/auth_openid/res_users.xml index df0c31856e2..be4fbdf294b 100644 --- a/addons/auth_openid/res_users.xml +++ b/addons/auth_openid/res_users.xml @@ -4,7 +4,6 @@ res.users.form res.users - form diff --git a/addons/auth_openid/static/src/js/auth_openid.js b/addons/auth_openid/static/src/js/auth_openid.js index fd6ec01cc0f..1417bc471ce 100644 --- a/addons/auth_openid/static/src/js/auth_openid.js +++ b/addons/auth_openid/static/src/js/auth_openid.js @@ -8,7 +8,7 @@ instance.web.Login = instance.web.Login.extend({ this._super.apply(this, arguments); var self = this; - this._default_error_message = this.$element.find('.login_error_message').text(); + this._default_error_message = this.$element.find('.oe_login_error_message').text(); this.$openid_selected_button = $(); this.$openid_selected_input = $(); @@ -40,8 +40,7 @@ instance.web.Login = instance.web.Login.extend({ } }); - this._check_fragment(); - + this._check_error(); }, @@ -67,11 +66,9 @@ instance.web.Login = instance.web.Login.extend({ }, - _check_fragment: function() { + _check_error: function() { var self = this; - var fragment = jQuery.deparam.fragment(); - console.log(fragment); - if (fragment.loginerror !== undefined) { + if (this.params.loginerror !== undefined) { this.rpc('/auth_openid/login/status', {}, function(result) { if (_.contains(['success', 'failure'], result.status) && result.message) { self.do_warn('Invalid OpenID Login', result.message); @@ -132,11 +129,12 @@ instance.web.Login = instance.web.Login.extend({ do_warn: function(title, msg) { //console.warn(title, msg); - this.$element.find('.login_error_message').text(msg).show(); + this.$element.find('.oe_login_error_message').text(msg).show(); + this._super(title, msg); }, reset_error_message: function() { - this.$element.find('.login_error_message').text(this._default_error_message); + this.$element.find('.oe_login_error_message').text(this._default_error_message); } }); diff --git a/addons/auth_openid/static/src/xml/auth_openid.xml b/addons/auth_openid/static/src/xml/auth_openid.xml index 34894555668..aa61d161657 100644 --- a/addons/auth_openid/static/src/xml/auth_openid.xml +++ b/addons/auth_openid/static/src/xml/auth_openid.xml @@ -3,7 +3,7 @@ - + - - - - - - - - - - - - - - - - - - +
  • Google Apps Domain
  • @@ -54,7 +37,7 @@
    - + this.each(function() { var $i = $(this), dp = $i.find('input').attr('name'); diff --git a/addons/auth_openid/utils.py b/addons/auth_openid/utils.py index 444b5eeaa05..806198f99c2 100644 --- a/addons/auth_openid/utils.py +++ b/addons/auth_openid/utils.py @@ -1,8 +1,8 @@ #!/usr/bin/env python ############################################################################## -# +# # OpenERP, Open Source Management Solution -# Copyright (C) 2010-2011 OpenERP s.a. (). +# Copyright (C) 2010-2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -15,11 +15,9 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## -from contextlib import contextmanager -from openerp.modules.registry import RegistryManager KEY_LENGTH = 16 @@ -35,14 +33,4 @@ SREG2AX = { # from http://www.axschema.org/types/#sreg 'timezone': 'http://axschema.org/pref/timezone', } - -@contextmanager -def cursor(db): - cr = RegistryManager.get(db).db.cursor() - try: - yield cr - finally: - cr.close() - - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/auth_reset_password/__openerp__.py b/addons/auth_reset_password/__openerp__.py index 76528bbfeb8..ccf5ca53a21 100644 --- a/addons/auth_reset_password/__openerp__.py +++ b/addons/auth_reset_password/__openerp__.py @@ -1,22 +1,17 @@ { - 'name': 'Reset Password', - 'description': 'Allow users to reset their password from the login page', - 'author': 'OpenERP SA', - 'version': '1.0', - 'category': 'Authentication', - 'website': 'http://www.openerp.com', - 'installable': True, - 'depends': ['auth_anonymous', 'email_template'], - 'data': [ - 'auth_reset_password.xml', - ], - 'js': [ - 'static/src/js/reset_password.js', - ], - 'css': [ - 'static/src/css/reset_password.css', - ], - 'qweb': [ - 'static/src/xml/reset_password.xml', - ], + 'name': 'Reset Password', + 'description': """ +Allow users to reset their password from the login page. +======================================================== +""", + 'author': 'OpenERP SA', + 'version': '1.0', + 'category': 'Authentication', + 'website': 'http://www.openerp.com', + 'installable': True, + 'depends': ['auth_anonymous', 'email_template'], + 'data': ['auth_reset_password.xml'], + 'js': ['static/src/js/reset_password.js'], + 'css': ['static/src/css/reset_password.css'], + 'qweb': ['static/src/xml/reset_password.xml'], } diff --git a/addons/auth_reset_password/static/src/js/reset_password.js b/addons/auth_reset_password/static/src/js/reset_password.js index 41b48c7e59b..13cf070a548 100644 --- a/addons/auth_reset_password/static/src/js/reset_password.js +++ b/addons/auth_reset_password/static/src/js/reset_password.js @@ -31,7 +31,7 @@ openerp.auth_reset_password = function(instance) { }, do_reset_password: function(db, email) { var self = this; - instance.connection.session_authenticate(db, 'anonymous', 'anonymous', true).pipe(function () { + instance.session.session_authenticate(db, 'anonymous', 'anonymous', true).pipe(function () { var func = new instance.web.Model("res.users").get_func("send_reset_password_request"); return func(email).then(function(res) { // show message diff --git a/addons/auth_signup/__init__.py b/addons/auth_signup/__init__.py index 2e404949550..2331ae629a8 100644 --- a/addons/auth_signup/__init__.py +++ b/addons/auth_signup/__init__.py @@ -1,2 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2012-today OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see +# +############################################################################## + +import controllers import res_config -import auth_signup +import res_users diff --git a/addons/auth_signup/__openerp__.py b/addons/auth_signup/__openerp__.py index a869c623db0..5f889bfb119 100644 --- a/addons/auth_signup/__openerp__.py +++ b/addons/auth_signup/__openerp__.py @@ -1,22 +1,37 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2009-today OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see +# +############################################################################## + { - 'name': 'Signup', - 'description': 'Allow users to sign up', - 'author': 'OpenERP SA', - 'version': '1.0', - 'category': 'Authentication', - 'website': 'http://www.openerp.com', - 'installable': True, - 'depends': ['auth_anonymous', 'base_setup'], - 'data': [ - 'res_config.xml', - ], - 'js': [ - 'static/src/js/auth_signup.js', - ], - 'css': [ - 'static/src/css/auth_signup.css', - ], - 'qweb': [ - 'static/src/xml/auth_signup.xml', - ], + 'name': 'Signup', + 'description': """ +Allow users to sign up. +======================= + """, + 'author': 'OpenERP SA', + 'version': '1.0', + 'category': 'Authentication', + 'website': 'http://www.openerp.com', + 'installable': True, + 'depends': ['base_setup'], + 'data': ['res_config.xml'], + 'js': ['static/src/js/auth_signup.js'], + 'qweb': ['static/src/xml/auth_signup.xml'], } diff --git a/addons/auth_signup/auth_signup.py b/addons/auth_signup/auth_signup.py deleted file mode 100644 index ebc72b3aeac..00000000000 --- a/addons/auth_signup/auth_signup.py +++ /dev/null @@ -1,39 +0,0 @@ -from openerp.osv import osv, fields - -class res_users(osv.Model): - _inherit = 'res.users' - - _sql_constraints = [ - ('email_uniq', 'UNIQUE (user_email)', 'You can not have two users with the same email!') - ] - -class signup_signup(osv.TransientModel): - _name = 'auth.signup' - - # TODO add captcha - _columns = { - 'name': fields.char('Name', size=64), - 'email': fields.char('Email', size=64), - 'password': fields.char('Password', size=64), - } - - def create(self, cr, uid, values, context=None): - # NOTE here, invalid values raises exceptions to avoid storing - # sensitive data into the database (which then are available to anyone) - - new_user = { - 'name': values['name'], - 'login': values['email'], - 'user_email': values['email'], - 'password': values['password'], - 'active': True, - } - - user_template_id = self.pool.get('ir.config_parameter').get_param(cr, uid, 'auth.signup_template_user_id', 0) - if user_template_id: - self.pool.get('res.users').copy(cr, 1, user_template_id, new_user, context=context) - else: - self.pool.get('res.users').create(cr, 1, new_user, context=context) - - # Dont store anything - return 0 diff --git a/addons/auth_signup/controllers/__init__.py b/addons/auth_signup/controllers/__init__.py new file mode 100644 index 00000000000..e11f9ba81bb --- /dev/null +++ b/addons/auth_signup/controllers/__init__.py @@ -0,0 +1,3 @@ +import main + +# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py new file mode 100644 index 00000000000..0ed2151d12b --- /dev/null +++ b/addons/auth_signup/controllers/main.py @@ -0,0 +1,34 @@ +import logging + +import werkzeug.urls + +from openerp.modules.registry import RegistryManager +from openerp.addons.web.controllers.main import login_and_redirect +import openerp.addons.web.common.http as openerpweb + +_logger = logging.getLogger(__name__) + +class OpenIDController(openerpweb.Controller): + _cp_path = '/auth_signup' + + @openerpweb.httprequest + def signup(self, req, dbname, name, login, password): + url = '/' + registry = RegistryManager.get(dbname) + with registry.cursor() as cr: + try: + Users = registry.get('res.users') + credentials = Users.auth_signup(cr, 1, name, login, password) + cr.commit() + return login_and_redirect(req, *credentials) + except AttributeError: + # auth_signup is not installed + _logger.exception('attribute error when signup') + url = "/#action=auth_signup&error=NA" # Not Available + except Exception: + # signup error + _logger.exception('error when signup') + url = "/#action=auth_signup&error=UE" # Unexcpected Error + return werkzeug.utils.redirect(url) + +# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/auth_signup/res_config.py b/addons/auth_signup/res_config.py index 2828a2b55fd..6afd1c5b581 100644 --- a/addons/auth_signup/res_config.py +++ b/addons/auth_signup/res_config.py @@ -1,10 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2012-today OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see +# +############################################################################## + from openerp.osv import osv, fields class base_config_settings(osv.TransientModel): _inherit = 'base.config.settings' _columns = { - 'auth_signup_template_user_id': fields.many2one('res.users', 'Template user for new users created through signup') + 'auth_signup_uninvited': fields.boolean('allow public users to sign up', help="If unchecked only invited users may sign up"), + 'auth_signup_template_user_id': fields.many2one('res.users', 'Template user for new users created through signup'), } def get_default_signup(self, cr, uid, fields, context=None): diff --git a/addons/auth_signup/res_config.xml b/addons/auth_signup/res_config.xml index d30d383ecdb..49669d36618 100644 --- a/addons/auth_signup/res_config.xml +++ b/addons/auth_signup/res_config.xml @@ -6,18 +6,16 @@ base.config.settings.signup base.config.settings - form - - - + +
    + +
    +
    +
    diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py new file mode 100644 index 00000000000..1d77a3f9473 --- /dev/null +++ b/addons/auth_signup/res_users.py @@ -0,0 +1,46 @@ +import openerp +from openerp.osv import osv + +class res_users(osv.Model): + _inherit = 'res.users' + + def auth_signup_create(self, cr, uid, new_user, context=None): + # new_user: + # login + # email + # name (optional) + # partner_id (optional) + # groups (optional) + # sign (for partner_id and groups) + # + user_template_id = self.pool.get('ir.config_parameter').get_param(cr, uid, 'auth.signup_template_user_id', 0) + if user_template_id: + self.pool.get('res.users').copy(cr, 1, user_template_id, new_user, context=context) + else: + self.pool.get('res.users').create(cr, 1, new_user, context=context) + + def auth_signup(self, cr, uid, name, login, password, context=None): + r = (cr.dbname, login, password) + res = self.search(cr, uid, [("login", "=", login)]) + if res: + # Existing user + user_id = res[0] + try: + self.check(cr.dbname, user_id, password) + # Same password + except openerp.exceptions.AccessDenied: + # Different password + raise + else: + # New user + new_user = { + 'name': name, + 'login': login, + 'user_email': login, + 'password': password, + 'active': True, + } + self.auth_signup_create(cr, uid, new_user) + return r + +# diff --git a/addons/auth_signup/static/src/css/auth_signup.css b/addons/auth_signup/static/src/css/auth_signup.css deleted file mode 100644 index 1e8d7d9d8d8..00000000000 --- a/addons/auth_signup/static/src/css/auth_signup.css +++ /dev/null @@ -1,9 +0,0 @@ -.openerp .oe_login .oe_login_pane ul.oe_signup a { - color: #eeeeee; - margin: 0 8px; -} -.openerp .oe_login .oe_login_pane ul.oe_signup a:hover { - text-decoration: underline; -} - - diff --git a/addons/auth_signup/static/src/js/auth_signup.js b/addons/auth_signup/static/src/js/auth_signup.js index 7384fe1e5f5..2ab13aa7598 100644 --- a/addons/auth_signup/static/src/js/auth_signup.js +++ b/addons/auth_signup/static/src/js/auth_signup.js @@ -1,65 +1,38 @@ openerp.auth_signup = function(instance) { + instance.auth_signup = instance.auth_signup || {}; var _t = instance.web._t; instance.web.Login.include({ start: function() { var self = this; - this.$('a.oe_signup').click(function() { - var db = self.$("form [name=db]").val(); - if (!db) { - self.do_warn(_t("Login"), _t("No database selected!")); - return false; - } - - var cnx = instance.connection; - if (cnx.session_is_valid()) { - self._signup(); - } else { - cnx.session_authenticate(db, 'anonymous', 'anonymous', true).then(function() { - self._signup(); - }).fail(function(error, event) { - console.log(error); - // cannot log as anonymous or auth_signup not installed - self.do_warn(_t('Sign Up'), _.str.sprintf(_t('Signup functionnality is not available for database %s'), db), true); - }); - } + var dbname = self.$("form [name=db]").val(); + self.do_action({ + type: 'ir.actions.client', + tag: 'auth_signup.signup', + params: {'dbname': dbname}, + target: 'new', + name: 'Sign up' + }); return true; }); return this._super(); - }, - - _signup: function() { - this.do_action({ - type: 'ir.actions.client', - tag: 'auth_signup.signup', - target: 'new', - name: 'Sign up' - }); - } }); - instance.auth_signup = instance.auth_signup || {}; instance.auth_signup.Signup = instance.web.Widget.extend({ template: 'auth_signup.signup', - init: function() { - this._super.apply(this, arguments); - this.dataset = new instance.web.DataSet(this, 'auth.signup'); + init: function(parent, params) { + this.params = params; + return this._super(); }, start: function() { var self = this; - this.$('input[type=password]').change(function() { + this.$('input[name=password_confirmation]').keyup(function() { var v = $(this).val(); - var e = !_.isEmpty(v); - if (e) { - e =_.all(self.$('input[type=password]'), function(i) { - return $(i).val() === v; - }); - } var $b = self.$('button'); - if (e) { + if (_.isEmpty(v) || self.$('input[name=password]').val() === v) { $b.removeAttr('disabled'); } else { $b.attr('disabled', 'disabled'); @@ -70,36 +43,18 @@ openerp.auth_signup = function(instance) { if(ev) { ev.preventDefault(); } - var name = self.$('input[name=name]').val(); - var email = self.$('input[name=email]').val(); - var password = self.$('input[name=password]').val(); - - self.dataset.create({ - name: name, - email: email, - password: password - }, function() { - self.do_action({ - type: 'ir.actions.client', - tag: 'login', - params: { - db: instance.connection.db, - login: email, - password: password, - login_successful: function() { - self.do_action('home'); - } - } - }); - }); - return false; - + var params = { + dbname : self.params.dbname, + name: self.$('input[name=name]').val(), + login: self.$('input[name=email]').val(), + password: self.$('input[name=password]').val(), + }; + var url = "/auth_signup/signup?" + $.param(params); + window.location = url; }); - return $.when(this._super()); + return this._super(); } - }); instance.web.client_actions.add("auth_signup.signup", "instance.auth_signup.Signup"); - }; diff --git a/addons/auth_signup/static/src/xml/auth_signup.xml b/addons/auth_signup/static/src/xml/auth_signup.xml index 92343d96281..c2eec846d15 100644 --- a/addons/auth_signup/static/src/xml/auth_signup.xml +++ b/addons/auth_signup/static/src/xml/auth_signup.xml @@ -14,10 +14,10 @@
    - Name = - Email = - Password = - Confirmation = + Name =
    + Email =
    + Password =
    + Confirmation =
    diff --git a/addons/base_action_rule/__openerp__.py b/addons/base_action_rule/__openerp__.py index eff92685313..c9483f00360 100644 --- a/addons/base_action_rule/__openerp__.py +++ b/addons/base_action_rule/__openerp__.py @@ -29,21 +29,19 @@ This module allows to implement action rules for any object. Use automated actions to automatically trigger actions for various screens. -Example: A lead created by a specific user may be automatically set to a specific +**Example:** A lead created by a specific user may be automatically set to a specific sales team, or an opportunity which still has status pending after 14 days might trigger an automatic reminder email. """, 'author': 'OpenERP SA', 'website': 'http://www.openerp.com', 'depends': ['base', 'mail'], - 'init_xml': [ - 'base_action_rule_data.xml' - ], - 'update_xml': [ + 'data': [ 'base_action_rule_view.xml', 'security/ir.model.access.csv', + 'base_action_rule_data.xml' ], - 'demo_xml': [], + 'demo': [], 'installable': True, 'auto_install': False, 'certificate' : '001017908446466333429', diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 7699256985c..b6eacda63c0 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -292,7 +292,7 @@ the rule to mark CC(mail to any other person defined in actions)."), 'object_description': hasattr(obj, 'description') and obj.description or False, 'object_user': hasattr(obj, 'user_id') and (obj.user_id and obj.user_id.name) or '/', 'object_user_email': hasattr(obj, 'user_id') and (obj.user_id and \ - obj.user_id.user_email) or '/', + obj.user_id.email) or '/', 'object_user_phone': hasattr(obj, 'partner_address_id') and (obj.partner_address_id and \ obj.partner_address_id.phone) or '/', 'partner': hasattr(obj, 'partner_id') and (obj.partner_id and obj.partner_id.name) or '/', @@ -319,8 +319,8 @@ the rule to mark CC(mail to any other person defined in actions)."), mail_message = self.pool.get('mail.message') body = self.format_mail(obj, body) if not emailfrom: - if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.user_email: - emailfrom = obj.user_id.user_email + if hasattr(obj, 'user_id') and obj.user_id and obj.user_id.email: + emailfrom = obj.user_id.email name = '[%d] %s' % (obj.id, tools.ustr(obj.name)) emailfrom = tools.ustr(emailfrom) @@ -419,7 +419,7 @@ the rule to mark CC(mail to any other person defined in actions)."), emails = [] if hasattr(obj, 'user_id') and action.act_mail_to_user: if obj.user_id: - emails.append(obj.user_id.user_email) + emails.append(obj.user_id.email) if action.act_mail_to_watchers: emails += (action.act_email_cc or '').split(',') diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml index ba51b729305..0d268438a41 100644 --- a/addons/base_action_rule/base_action_rule_view.xml +++ b/addons/base_action_rule/base_action_rule_view.xml @@ -10,7 +10,6 @@ base.action.rule.form base.action.rule - form
    @@ -98,7 +97,6 @@ base.action.rule.tree base.action.rule - tree diff --git a/addons/base_calendar/__openerp__.py b/addons/base_calendar/__openerp__.py index 58f666baa0d..48ec05e2e92 100644 --- a/addons/base_calendar/__openerp__.py +++ b/addons/base_calendar/__openerp__.py @@ -20,14 +20,15 @@ ############################################################################## { - "name": "Calendar Layer", - "version": "1.0", - "depends": ["base", "base_status", "mail", "base_action_rule"], + 'name': 'Calendar Layer', + 'version': '1.0', + 'depends': ['base', 'base_status', 'mail', 'base_action_rule'], 'description': """ This is a full-featured calendar system. ======================================== It supports: +------------ - Calendar of events - Alerts (create requests) - Recurring events @@ -35,25 +36,23 @@ It supports: If you need to manage your meetings, you should install the CRM module. """, - "author": "OpenERP SA", + 'author': 'OpenERP SA', 'category': 'Hidden/Dependency', 'website': 'http://www.openerp.com', - "init_xml": [ - 'base_calendar_data.xml', - 'crm_meeting_data.xml', - ], - "demo_xml": ['crm_meeting_demo.xml'], - "update_xml": [ + 'demo': ['crm_meeting_demo.xml'], + 'data': [ 'security/calendar_security.xml', 'security/ir.model.access.csv', 'wizard/base_calendar_invite_attendee_view.xml', 'base_calendar_view.xml', 'crm_meeting_view.xml', + 'base_calendar_data.xml', + 'crm_meeting_data.xml', ], - "test" : ['test/base_calendar_test.yml'], - "installable": True, - "auto_install": False, - "certificate": "00694071962960352821", + 'test' : ['test/base_calendar_test.yml'], + 'installable': True, + 'auto_install': False, + 'certificate': '00694071962960352821', 'images': ['images/base_calendar1.jpeg','images/base_calendar2.jpeg','images/base_calendar3.jpeg','images/base_calendar4.jpeg',], } diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index b570c2ef011..be3244f8a5b 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -245,7 +245,7 @@ class calendar_attendee(osv.osv): continue else: result[id][name] = self._get_address(attdata.sent_by_uid.name, \ - attdata.sent_by_uid.user_email) + attdata.sent_by_uid.email) if name == 'cn': if attdata.user_id: @@ -289,7 +289,7 @@ class calendar_attendee(osv.osv): if name == 'language': user_obj = self.pool.get('res.users') - lang = user_obj.read(cr, uid, uid, ['context_lang'], context=context)['context_lang'] + lang = user_obj.read(cr, uid, uid, ['lang'], context=context)['lang'] result[id][name] = lang.replace('_', '-') return result @@ -434,7 +434,7 @@ property or property parameter."), if not organizer: organizer = event_obj.user_id event_org.params['CN'] = [organizer.name] - event_org.value = 'MAILTO:' + (organizer.user_email or organizer.name) + event_org.value = 'MAILTO:' + (organizer.email or organizer.name) if event_obj.alarm_id: # computes alarm data @@ -535,7 +535,7 @@ property or property parameter."), return {'value': {'email': ''}} usr_obj = self.pool.get('res.users') user = usr_obj.browse(cr, uid, user_id, *args) - return {'value': {'email': user.user_email, 'availability':user.availability}} + return {'value': {'email': user.email, 'availability':user.availability}} def do_tentative(self, cr, uid, ids, context=None, *args): """ Makes event invitation as Tentative @@ -891,9 +891,9 @@ From: """ % (alarm.name, alarm.trigger_date, alarm.description, \ alarm.user_id.name, alarm.user_id.signature) - mail_to = [alarm.user_id.user_email] + mail_to = [alarm.user_id.email] for att in alarm.attendee_ids: - mail_to.append(att.user_id.user_email) + mail_to.append(att.user_id.email) if mail_to: mail_message.schedule_with_attach(cr, uid, tools.config.get('email_from', False), @@ -947,7 +947,7 @@ class calendar_event(osv.osv): value['duration'] = duration # change start_date's time to 00:00:00 in the user's timezone user = self.pool.get('res.users').browse(cr, uid, uid) - tz = pytz.timezone(user.context_tz) if user.context_tz else pytz.utc + tz = pytz.timezone(user.tz) if user.tz else pytz.utc start = pytz.utc.localize(start).astimezone(tz) # convert start in user's timezone start = start.replace(hour=0, minute=0, second=0) # change start's time to 00:00:00 start = start.astimezone(pytz.utc) # convert start back to utc @@ -1097,8 +1097,8 @@ rule or repeating pattern of time to exclude from the recurring rule."), user_pool = self.pool.get('res.users') user = user_pool.browse(cr, uid, uid, context=context) res = user.name - if user.user_email: - res += " <%s>" %(user.user_email) + if user.email: + res += " <%s>" %(user.email) return res _defaults = { diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml index 0e12d835710..89066ce74bb 100644 --- a/addons/base_calendar/base_calendar_view.xml +++ b/addons/base_calendar/base_calendar_view.xml @@ -6,7 +6,6 @@ calendar.attendee.form calendar.attendee - form
    @@ -62,7 +61,6 @@ calendar.attendee.tree calendar.attendee - tree @@ -81,7 +79,6 @@ calendar.attendee.search calendar.attendee - search @@ -129,7 +126,6 @@ res.alarm.form res.alarm - form @@ -150,7 +146,6 @@ res.alarm.tree res.alarm - tree @@ -189,7 +184,6 @@ Event Form calendar.event - form
    @@ -363,7 +357,6 @@ Event Tree calendar.event - tree @@ -382,7 +375,6 @@ Events Calendar calendar.event - calendar @@ -398,7 +390,6 @@ Calendar Events Search calendar.event - search diff --git a/addons/base_calendar/crm_meeting_data.xml b/addons/base_calendar/crm_meeting_data.xml index 82752d1dc7d..d1cffddc403 100644 --- a/addons/base_calendar/crm_meeting_data.xml +++ b/addons/base_calendar/crm_meeting_data.xml @@ -13,7 +13,15 @@ - Phone Call + Off-site Meeting + + + + Open Discussion + + + + Feedback Meeting diff --git a/addons/base_calendar/crm_meeting_demo.xml b/addons/base_calendar/crm_meeting_demo.xml index ad88c11bb1b..6c098e2f949 100644 --- a/addons/base_calendar/crm_meeting_demo.xml +++ b/addons/base_calendar/crm_meeting_demo.xml @@ -1,79 +1,78 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Follow-up for Project proposal + Meeting to discuss project plan and hash out the details of implementation. + - - + + + open - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + Initial discussion + Discussion with partner for product. + + + + + open + + + + + + Pricing Discussion + Internal meeting for discussion for new pricing for product and services. + + + + + open + + + + + + Requirements review + + + + + open + + + + + + Changes in Designing + + + + + open + + + + + + Presentation for new Services + + + + + open diff --git a/addons/base_calendar/crm_meeting_view.xml b/addons/base_calendar/crm_meeting_view.xml index a97d2967ffa..6009251a460 100644 --- a/addons/base_calendar/crm_meeting_view.xml +++ b/addons/base_calendar/crm_meeting_view.xml @@ -45,7 +45,6 @@ Meeting Types Tree crm.meeting.type - tree @@ -68,11 +67,10 @@ CRM - Meetings Form crm.meeting - form
    - +
    @@ -117,7 +115,7 @@
    + attrs="{'readonly': [('recurrent_uid','!=',False)]}"/> @@ -173,7 +171,6 @@
    +
    +
    - + +
    @@ -83,7 +80,7 @@ - + @@ -109,14 +106,21 @@
    - - + +
    + + +
    + + + +
    - - + + @@ -124,6 +128,7 @@
    +
    @@ -133,7 +138,6 @@ hr.expense.expense.filter hr.expense.expense - search @@ -178,7 +182,6 @@ product.product.expense.form product.product - form diff --git a/addons/hr_expense/hr_expense_workflow.xml b/addons/hr_expense/hr_expense_workflow.xml index 328a07879a4..2e085071207 100644 --- a/addons/hr_expense/hr_expense_workflow.xml +++ b/addons/hr_expense/hr_expense_workflow.xml @@ -32,14 +32,6 @@ expense_accept() - - - paid - function - expense_paid() - True - - refused @@ -47,12 +39,11 @@ expense_canceled() - + - invoice - subflow - - action_invoice_create() + done + function + action_receipt_create() @@ -91,15 +82,8 @@ - - invoice - - - - - - - subflow.paid + + done diff --git a/addons/hr_expense/report/hr_expense_report.py b/addons/hr_expense/report/hr_expense_report.py index adef11f5269..72bf710ec4f 100644 --- a/addons/hr_expense/report/hr_expense_report.py +++ b/addons/hr_expense/report/hr_expense_report.py @@ -39,11 +39,10 @@ class hr_expense_report(osv.osv): 'product_id':fields.many2one('product.product', 'Product', readonly=True), 'journal_id': fields.many2one('account.journal', 'Force Journal', readonly=True), 'product_qty':fields.float('Qty', readonly=True), - 'invoiced':fields.integer('# of Invoiced Lines', readonly=True), 'employee_id': fields.many2one('hr.employee', "Employee's Name", readonly=True), 'date_confirm': fields.date('Confirmation Date', readonly=True), 'date_valid': fields.date('Validation Date', readonly=True), - 'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True), + 'voucher_id': fields.many2one('account.voucher', 'Receipt', readonly=True), 'department_id':fields.many2one('hr.department','Department', readonly=True), 'company_id':fields.many2one('res.company', 'Company', readonly=True), 'user_id':fields.many2one('res.users', 'Validation User', readonly=True), @@ -60,8 +59,7 @@ class hr_expense_report(osv.osv): ('draft', 'Draft'), ('confirm', 'Waiting confirmation'), ('accepted', 'Accepted'), - ('invoiced', 'Invoiced'), - ('paid', 'Reimbursed'), + ('done', 'Done'), ('cancelled', 'Cancelled')], 'Status', readonly=True), } @@ -78,8 +76,7 @@ class hr_expense_report(osv.osv): s.currency_id, to_date(to_char(s.date_confirm, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_confirm, to_date(to_char(s.date_valid, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_valid, - s.invoice_id, - count(s.invoice_id) as invoiced, + s.voucher_id, s.user_valid as user_id, s.department_id, to_char(date_trunc('day',s.create_date), 'YYYY') as year, @@ -109,7 +106,7 @@ class hr_expense_report(osv.osv): to_date(to_char(s.date_valid, 'dd-MM-YYYY'),'dd-MM-YYYY'), l.product_id, l.analytic_account, - s.invoice_id, + s.voucher_id, s.currency_id, s.user_valid, s.department_id, diff --git a/addons/hr_expense/report/hr_expense_report_view.xml b/addons/hr_expense/report/hr_expense_report_view.xml index 73ec45bde02..1cd1e10c5ed 100644 --- a/addons/hr_expense/report/hr_expense_report_view.xml +++ b/addons/hr_expense/report/hr_expense_report_view.xml @@ -5,15 +5,14 @@ hr.expense.report.tree hr.expense.report - tree - + - + @@ -23,7 +22,6 @@ - @@ -35,7 +33,6 @@ hr.expense.report.graph hr.expense.report - graph @@ -48,12 +45,11 @@ hr.expense.report.search hr.expense.report - search - + diff --git a/addons/hr_expense/test/expense_process.yml b/addons/hr_expense/test/expense_process.yml index 5c8a9d53f7c..eae63c460fc 100644 --- a/addons/hr_expense/test/expense_process.yml +++ b/addons/hr_expense/test/expense_process.yml @@ -17,33 +17,20 @@ !assert {model: hr.expense.expense, id: sep_expenses, severity: error, string: Expense should be in Approved state}: - state == 'accepted' - - I make Invoice for the expense. + I make Receipt for the expense. - - !python {model: hr.expense.expense}: | - self.invoice(cr, uid, [ref('sep_expenses')]) + !workflow {model: hr.expense.expense, action: done, ref: sep_expenses} - - I check invoice details. + I check receipt details. - !python {model: hr.expense.expense}: | sep_expenses = self.browse(cr, uid, ref("sep_expenses"), context=context) - assert sep_expenses.state == 'invoiced', "Expense should be in 'Invoiced' state." - assert sep_expenses.invoice_id, "Expense should have link of Invoice." - assert sep_expenses.invoice_id.currency_id == sep_expenses.currency_id,"Invoice currency is not correspond with supplier invoice currency" - assert sep_expenses.invoice_id.origin == sep_expenses.name,"Invoice origin is not correspond with supplier invoice" - assert sep_expenses.invoice_id.type == 'in_invoice', "Invoice type is not supplier invoice" - assert sep_expenses.invoice_id.amount_total == sep_expenses.amount,"Invoice total amount is not correspond with supplier invoice total" - assert len(sep_expenses.invoice_id.invoice_line) == len(sep_expenses.line_ids),"Lines of Invoice and supplier invoice Line are not correspond" - #TODO: check invoice line details with Expenses lines -- - I pay the expenses. -- - !python {model: hr.expense.expense}: | - self.expense_paid(cr, uid, [ref('sep_expenses')]) -- - I check that state of expenses is 'Paid'. -- - !assert {model: hr.expense.expense, id: sep_expenses, severity: error, string: Expense should be in Paid state}: - - state == 'paid' + assert sep_expenses.state == 'done', "Expense should be in 'Done' state." + assert sep_expenses.voucher_id, "Expense should have link of Purchase Receipt." + assert sep_expenses.voucher_id.type == 'purchase', "Receipt type is not purchase receipt." + assert sep_expenses.voucher_id.amount == sep_expenses.amount,"Receipt total amount is not correspond with expense total." + assert len(sep_expenses.voucher_id.line_dr_ids) == len(sep_expenses.line_ids),"Lines of Receipt and expense line are not correspond." + - I duplicate the expenses and cancel duplicated. - diff --git a/addons/hr_holidays/__openerp__.py b/addons/hr_holidays/__openerp__.py index 45dd9ea39a5..d5a2728c763 100644 --- a/addons/hr_holidays/__openerp__.py +++ b/addons/hr_holidays/__openerp__.py @@ -21,14 +21,14 @@ { - "name": "Leaves Management", - "version": "1.5", - "author": "OpenERP SA", - "category": "Human Resources", - "sequence": 28, - "summary": "Holidays, Allocation and Leave Requests", - "website": "http://www.openerp.com", - "description": """ + 'name': 'Leaves Management', + 'version': '1.5', + 'author': 'OpenERP SA', + 'category': 'Human Resources', + 'sequence': 28, + 'summary': 'Holidays, Allocation and Leave Requests', + 'website': 'http://www.openerp.com', + 'description': """ This module allows you to manage leaves and leave's requests. ============================================================= @@ -37,27 +37,29 @@ Implements a dashboard for human resource management that includes: * Leaves Note that: +~~~~~~~~~~ - A synchronisation with an internal agenda (use of the CRM module) is possible: in order to automatically create a case when an holiday request is accepted, you have to link the holidays status to a case section. You can setup this info and your colour preferences in - Human Resources/Configuration/Leave Type + + **Human Resources** / **Configuration** / **Leave Type** - An employee can make an ask for more off-days by making a new Allocation. It will increase his total of that leave type available (if the request is accepted). - There are two ways to print the employee's holidays: * The first will allow to choose employees by department and is used by clicking the menu item located in - Reporting/Human Resources/Leaves/Leaves by Department + **Reporting** / **Human Resources** / **Leaves** / **Leaves by Department** * The second will allow you to choose the holidays report for specific employees. Go on the list - Human Resources/Human Resources/Employees + **Human Resources** / **Human Resources** / **Employees** then select the ones you want to choose, click on the print icon and select the option 'Leaves Summary' - The wizard allows you to choose if you want to print either the Approved & Confirmed holidays or both. These states must be set up by a user from the group 'HR'. You can define these features in the security tab from the user data in - Settings/Users/Users + **Settings** / **Users** / **Users** + for example, you maybe will do it for the user 'admin'. """, 'images': ['images/hr_allocation_requests.jpeg', 'images/hr_leave_requests.jpeg', 'images/leaves_analysis.jpeg'], 'depends': ['hr', 'base_calendar', 'process', 'resource'], - 'init_xml': [], - 'update_xml': [ + 'data': [ 'security/ir.model.access.csv', 'security/ir_rule.xml', 'hr_holidays_workflow.xml', @@ -70,10 +72,10 @@ Note that: 'wizard/hr_holidays_summary_employees_view.xml', 'board_hr_holidays_view.xml', ], - 'demo_xml': ['hr_holidays_demo.xml',], + 'demo': ['hr_holidays_demo.xml',], 'test': ['test/test_hr_holiday.yml', 'test/hr_holidays_report.yml', - ], + ], 'installable': True, 'application': True, 'auto_install': False, diff --git a/addons/hr_holidays/board_hr_holidays_view.xml b/addons/hr_holidays/board_hr_holidays_view.xml index eb3b671af6b..c90ee32c396 100644 --- a/addons/hr_holidays/board_hr_holidays_view.xml +++ b/addons/hr_holidays/board_hr_holidays_view.xml @@ -15,7 +15,6 @@ board.hr.holidays.leave.month.form board.board - form diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 7eedfa54ce5..5840217d7ee 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -274,7 +274,7 @@ class hr_holidays(osv.osv): 'date': record.date_from, 'end_date': record.date_to, 'date_deadline': record.date_to, - 'state': 'done', # to block that meeting date in the calendar + 'state': 'open', # to block that meeting date in the calendar } meeting_id = meeting_obj.create(cr, uid, meeting_vals) self._create_resource_leave(cr, uid, [record], context=context) @@ -366,15 +366,11 @@ class hr_holidays(osv.osv): result[obj.id] = hr_manager_group['users'] return result - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add employee and its manager. """ - user_ids = super(hr_holidays, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - if obj.employee_id.parent_id and not obj.employee_id.parent_id.user_id.id in user_ids: - user_ids.append(obj.employee_id.parent_id.user_id.id) - return user_ids + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' and 'manager' to the monitored fields """ + res = super(hr_holidays, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + # TODO: add manager + return res + ['user_id'] def create_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml index 4469fa73fbe..711d07bbfe8 100644 --- a/addons/hr_holidays/hr_holidays_view.xml +++ b/addons/hr_holidays/hr_holidays_view.xml @@ -41,7 +41,6 @@ hr.holidays.filter hr.holidays - search @@ -77,7 +76,6 @@ Leave Request hr.holidays - calendar @@ -89,10 +87,9 @@ Leave Request hr.holidays - form 1 -
    +
    + @@ -71,15 +74,6 @@ - -
  • - - -
  • -
  • - +
    diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml new file mode 100644 index 00000000000..53c899b9569 --- /dev/null +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -0,0 +1,31 @@ + + diff --git a/addons/portal_hr_recruitment/__init__.py b/addons/mail/tests/__init__.py similarity index 79% rename from addons/portal_hr_recruitment/__init__.py rename to addons/mail/tests/__init__.py index 26c654db9dd..d63c5634cc3 100644 --- a/addons/portal_hr_recruitment/__init__.py +++ b/addons/mail/tests/__init__.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- ############################################################################## # -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (). +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -18,4 +18,10 @@ # along with this program. If not, see . # ############################################################################## +from . import test_mail +checks = [ + test_mail, +] + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py new file mode 100644 index 00000000000..0940d72c490 --- /dev/null +++ b/addons/mail/tests/test_mail.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.tests import common + +MAIL_TEMPLATE = """Return-Path: +To: {to} +Received: by mail1.openerp.com (Postfix, from userid 10002) + id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST) +From: Sylvie Lelitre +Subject: {subject} +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_Part_4200734_24778174.1344608186754" +Date: Fri, 10 Aug 2012 14:16:26 +0000 +Message-ID: <1198923581.41972151344608186760.JavaMail@agrolait.com> +{extra} +------=_Part_4200734_24778174.1344608186754 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + +Please call me as soon as possible this afternoon! + +-- +Sylvie +------=_Part_4200734_24778174.1344608186754 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + + + =20 + + =20 + =20 + +

    Please call me as soon as possible this afternoon!

    + +

    --
    + Sylvie +

    + + +------=_Part_4200734_24778174.1344608186754-- +""" + + +class test_mail(common.TransactionCase): + + def setUp(self): + super(test_mail, self).setUp() + self.ir_model = self.registry('ir.model') + self.mail_alias = self.registry('mail.alias') + self.mail_thread = self.registry('mail.thread') + self.mail_group = self.registry('mail.group') + self.res_users = self.registry('res.users') + + # groups@.. will cause the creation of new mail groups + self.mail_group_model_id = self.ir_model.search(self.cr, self.uid, [('model','=', 'mail.group')])[0] + self.mail_alias.create(self.cr, self.uid, {'alias_name': 'groups', + 'alias_model_id': self.mail_group_model_id}) + + # tech@... will append new messages to the 'tech' group + self.group_tech_id = self.mail_group.create(self.cr, self.uid, {'name': 'tech'}) + + def test_message_process(self): + # Incoming mail creates a new mail_group "frogs" + self.assertEqual(self.mail_group.search(self.cr, self.uid, [('name','=','frogs')]), []) + mail_frogs = MAIL_TEMPLATE.format(to='groups@example.com, other@gmail.com', subject='frogs', extra='') + self.mail_thread.message_process(self.cr, self.uid, None, mail_frogs) + frog_groups = self.mail_group.search(self.cr, self.uid, [('name','=','frogs')]) + self.assertTrue(len(frog_groups) == 1) + + # Previously-created group can be emailed now - it should have an implicit alias group+frogs@... + frog_group = self.mail_group.browse(self.cr, self.uid, frog_groups[0]) + group_messages = frog_group.message_ids + self.assertTrue(len(group_messages) == 1, 'New group should only have the original message') + mail_frog_news = MAIL_TEMPLATE.format(to='Friendly Frogs ', subject='news', extra='') + self.mail_thread.message_process(self.cr, self.uid, None, mail_frog_news) + frog_group.refresh() + self.assertTrue(len(frog_group.message_ids) == 2, 'Group should contain 2 messages now') + + # Even with a wrong destination, a reply should end up in the correct thread + mail_reply = MAIL_TEMPLATE.format(to='erroneous@example.com>', subject='Re: news', + extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n'%frog_group.id) + self.mail_thread.message_process(self.cr, self.uid, None, mail_reply) + frog_group.refresh() + self.assertTrue(len(frog_group.message_ids) == 3, 'Group should contain 3 messages now') + + # No model passed and no matching alias must raise + mail_spam = MAIL_TEMPLATE.format(to='noone@example.com', subject='spam', extra='') + self.assertRaises(Exception, + self.mail_thread.message_process, + self.cr, self.uid, None, mail_spam) diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index d26511464f8..fe87b7584e0 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -100,7 +100,7 @@ class mail_compose_message(osv.TransientModel): # Try to provide default email_from if not specified yet if not result.get('email_from'): current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - result['email_from'] = current_user.user_email or False + result['email_from'] = current_user.email or False return result _columns = { @@ -133,7 +133,7 @@ class mail_compose_message(osv.TransientModel): result.update({ 'model': model, 'res_id': res_id, - 'email_from': user.user_email or tools.config.get('email_from', False), + 'email_from': user.email or tools.config.get('email_from', False), 'body_html': False, 'body_text': False, 'subject': False, @@ -223,7 +223,7 @@ class mail_compose_message(osv.TransientModel): 'dest_partner_ids': dest_partner_ids, 'model': message_data.model or False, 'res_id': message_data.res_id or False, - 'email_from': current_user.user_email or message_data.email_to or False, + 'email_from': current_user.email or message_data.email_to or False, 'email_to': message_data.reply_to or message_data.email_from or False, 'email_cc': message_data.email_cc or False, 'user_id': uid, diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml index 8fa4eaa9c50..73fb03cdc28 100644 --- a/addons/mail/wizard/mail_compose_message_view.xml +++ b/addons/mail/wizard/mail_compose_message_view.xml @@ -4,7 +4,6 @@ mail.compose.message.form mail.compose.message - form @@ -41,7 +40,6 @@ mail.compose.message.form mail.compose.message 18 - form @@ -50,7 +48,7 @@ + class="oe_mail_compose_message_body_html oe_mail_compose_message_invisible"/> diff --git a/addons/marketing/__openerp__.py b/addons/marketing/__openerp__.py index 81751891e66..90f6e076cae 100644 --- a/addons/marketing/__openerp__.py +++ b/addons/marketing/__openerp__.py @@ -21,29 +21,28 @@ { - "name" : "Marketing", - "version" : "1.1", - "depends" : ["base", "base_setup"], - "author" : "OpenERP SA", - "category": 'Hidden/Dependency', - "description": """ + 'name': 'Marketing', + 'version': '1.1', + 'depends': ['base', 'base_setup'], + 'author': 'OpenERP SA', + 'category': 'Hidden/Dependency', + 'description': """ Menu for Marketing. =================== Contains the installer for marketing-related modules. """, 'website': 'http://www.openerp.com', - 'init_xml': [], - 'update_xml': [ + 'data': [ 'security/marketing_security.xml', 'security/ir.model.access.csv', 'marketing_view.xml', 'res_config_view.xml', ], - 'demo_xml': ['marketing_demo.xml'], + 'demo': ['marketing_demo.xml'], 'installable': True, 'auto_install': False, - 'certificate' : '00598574977629228189', + 'certificate': '00598574977629228189', 'images': ['images/config_marketing.jpeg'], } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/marketing/res_config_view.xml b/addons/marketing/res_config_view.xml index a759fa9c8bf..78144843f82 100644 --- a/addons/marketing/res_config_view.xml +++ b/addons/marketing/res_config_view.xml @@ -5,7 +5,6 @@ Configure Marketing marketing.config.settings - form

    diff --git a/addons/marketing_campaign/__openerp__.py b/addons/marketing_campaign/__openerp__.py index e0cf8b56439..61d5d2ada29 100644 --- a/addons/marketing_campaign/__openerp__.py +++ b/addons/marketing_campaign/__openerp__.py @@ -21,20 +21,21 @@ { - "name" : "Marketing Campaigns", - "version" : "1.1", - "depends" : ["marketing", - "document", - "email_template", - "decimal_precision" - ], - "author" : "OpenERP SA", - "category": 'Marketing', - "description": """ + 'name': 'Marketing Campaigns', + 'version': '1.1', + 'depends': ['marketing', + 'document', + 'email_template', + 'decimal_precision' + ], + 'author': 'OpenERP SA', + 'category': 'Marketing', + 'description': """ This module provides leads automation through marketing campaigns (campaigns can in fact be defined on any resource, not just CRM Leads). ========================================================================================================================================= The campaigns are dynamic and multi-channels. The process is as follows: +------------------------------------------------------------------------ * Design marketing campaigns like workflows, including email templates to send, reports to print and send by email, custom actions * Define input segments that will select the items that should enter the @@ -49,30 +50,25 @@ The campaigns are dynamic and multi-channels. The process is as follows: While the campaign runs you can of course continue to fine-tune the parameters, input segments, workflow. -Note: If you need demo data, you can install the marketing_campaign_crm_demo +**Note:** If you need demo data, you can install the marketing_campaign_crm_demo module, but this will also install the CRM application as it depends on CRM Leads. """, 'website': 'http://www.openerp.com', - 'init_xml': [], - 'update_xml': [ + 'data': [ 'marketing_campaign_view.xml', 'marketing_campaign_data.xml', 'marketing_campaign_workflow.xml', 'res_partner_view.xml', 'report/campaign_analysis_view.xml', - "security/marketing_campaign_security.xml", - "security/ir.model.access.csv" + 'security/marketing_campaign_security.xml', + 'security/ir.model.access.csv' ], - 'demo_xml': [ - 'marketing_campaign_demo.xml', - ], - 'test': [ - 'test/marketing_campaign.yml', - ], + 'demo': ['marketing_campaign_demo.xml'], + 'test': ['test/marketing_campaign.yml'], 'installable': True, 'auto_install': False, - 'certificate' : '00421723279617928365', + 'certificate': '00421723279617928365', 'images': ['images/campaign.png', 'images/campaigns.jpeg','images/email_account.jpeg','images/email_templates.jpeg','images/segments.jpeg'], } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/marketing_campaign/marketing_campaign.py b/addons/marketing_campaign/marketing_campaign.py index e268f3db5dd..bfabd2002bd 100644 --- a/addons/marketing_campaign/marketing_campaign.py +++ b/addons/marketing_campaign/marketing_campaign.py @@ -120,7 +120,7 @@ Normal - the campaign runs normally and automatically sends all emails and repor 'Status',), 'activity_ids': fields.one2many('marketing.campaign.activity', 'campaign_id', 'Activities'), - 'fixed_cost': fields.float('Fixed Cost', help="Fixed cost for running this campaign. You may also specify variable cost and revenue on each campaign activity. Cost and Revenue statistics are included in Campaign Reporting.", digits_compute=dp.get_precision('Purchase Price')), + 'fixed_cost': fields.float('Fixed Cost', help="Fixed cost for running this campaign. You may also specify variable cost and revenue on each campaign activity. Cost and Revenue statistics are included in Campaign Reporting.", digits_compute=dp.get_precision('Product Price')), } _defaults = { @@ -435,8 +435,8 @@ class marketing_campaign_activity(osv.osv): 'from_ids': fields.one2many('marketing.campaign.transition', 'activity_to_id', 'Previous Activities'), - 'variable_cost': fields.float('Variable Cost', help="Set a variable cost if you consider that every campaign item that has reached this point has entailed a certain cost. You can get cost statistics in the Reporting section", digits_compute=dp.get_precision('Purchase Price')), - 'revenue': fields.float('Revenue', help="Set an expected revenue if you consider that every campaign item that has reached this point has generated a certain revenue. You can get revenue statistics in the Reporting section", digits_compute=dp.get_precision('Sale Price')), + 'variable_cost': fields.float('Variable Cost', help="Set a variable cost if you consider that every campaign item that has reached this point has entailed a certain cost. You can get cost statistics in the Reporting section", digits_compute=dp.get_precision('Product Price')), + 'revenue': fields.float('Revenue', help="Set an expected revenue if you consider that every campaign item that has reached this point has generated a certain revenue. You can get revenue statistics in the Reporting section", digits_compute=dp.get_precision('Account')), 'signal': fields.char('Signal', size=128, help='An activity with a signal can be called programmatically. Be careful, the workitem is always created when a signal is sent'), 'keep_if_condition_not_met': fields.boolean("Don't Delete Workitems", diff --git a/addons/marketing_campaign/marketing_campaign_view.xml b/addons/marketing_campaign/marketing_campaign_view.xml index 9af709c19a5..19b9536c432 100644 --- a/addons/marketing_campaign/marketing_campaign_view.xml +++ b/addons/marketing_campaign/marketing_campaign_view.xml @@ -24,9 +24,8 @@ marketing.campaign.form marketing.campaign - form - +
    + @@ -125,7 +128,6 @@ Sales pos.order - tree @@ -142,7 +144,6 @@ pos.order.list.select pos.order - search @@ -198,7 +199,6 @@ Sale lines pos.order.line - tree @@ -215,7 +215,6 @@ Sale line pos.order.line - form
    @@ -264,7 +263,6 @@ report.trans.pos.user.form report.transaction.pos - form @@ -284,7 +282,6 @@ Sales by user report.transaction.pos - tree @@ -303,7 +300,6 @@ report.transaction.pos.calendar report.transaction.pos - calendar @@ -316,7 +312,6 @@ report.transaction.pos.graph report.transaction.pos - graph @@ -357,7 +352,6 @@ report.sales.by.user.pos.form report.sales.by.user.pos - form @@ -374,7 +368,6 @@ report.sales.by.user.pos.tree report.sales.by.user.pos - tree @@ -388,7 +381,6 @@ report.sales.by.user.pos.calendar report.sales.by.user.pos - calendar @@ -401,7 +393,6 @@ report.sales.by.user.pos.graph report.sales.by.user.pos - graph @@ -425,7 +416,6 @@ report.sales.by.user.pos.month.form report.sales.by.user.pos.month - form @@ -442,7 +432,6 @@ report.sales.by.user.pos.month.tree report.sales.by.user.pos.month - tree @@ -456,7 +445,6 @@ report.sales.by.user.pos.month.calendar report.sales.by.user.pos.month - calendar @@ -469,7 +457,6 @@ report.sales.by.user.pos.month.graph report.sales.by.user.pos.month - graph @@ -493,7 +480,6 @@ report.sales.by.margin.pos.form report.sales.by.margin.pos - form @@ -512,7 +498,6 @@ report.sales.by.margin.pos.tree report.sales.by.margin.pos - tree @@ -528,7 +513,6 @@ report.sales.by.margin.pos.calendar report.sales.by.margin.pos - calendar @@ -541,7 +525,6 @@ report.sales.by.margin.pos.graph report.sales.by.margin.pos - graph @@ -562,7 +545,6 @@ report.sales.by.margin.pos.month.form report.sales.by.margin.pos.month - form @@ -581,7 +563,6 @@ report.sales.by.margin.pos.month.tree report.sales.by.margin.pos.month - tree @@ -597,7 +578,6 @@ report.sales.by.margin.pos.month.calendar report.sales.by.margin.pos.month - calendar @@ -610,7 +590,6 @@ report.sales.by.margin.pos.month.graph report.sales.by.margin.pos.month - graph @@ -631,7 +610,6 @@ product.normal.pos.form.inherit product.product - form @@ -647,7 +625,6 @@ product.normal.form.inherit product.product - form @@ -657,6 +634,9 @@ + +
  • @@ -922,19 +896,19 @@