bzr revid: hmo@tinyerp.com-20120821051429-603c2m8qnupopllq
This commit is contained in:
Harry (OpenERP) 2012-08-21 10:44:29 +05:30
commit cfe6f2a566
31 changed files with 345 additions and 215 deletions

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2012-05-10 17:32+0000\n"
"Last-Translator: Michael Otcheskih <otma@mail.ru>\n"
"PO-Revision-Date: 2012-08-17 11:07+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-08-07 05:06+0000\n"
"X-Generator: Launchpad (build 15745)\n"
"X-Launchpad-Export-Date: 2012-08-18 04:58+0000\n"
"X-Generator: Launchpad (build 15810)\n"
#. module: account
#: view:account.invoice.report:0
@ -9872,7 +9872,7 @@ msgstr "Не определен счет доходов для ТМЦ: \"%s\" (i
#. module: account
#: constraint:account.move.line:0
msgid "You can not create journal items on closed account."
msgstr ""
msgstr "Нельзя создать элемент журнала по закрытому счету ."
#. module: account
#: field:account.account,unrealized_gain_loss:0

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
"PO-Revision-Date: 2010-12-23 13:10+0000\n"
"PO-Revision-Date: 2012-08-17 10:54+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-08-07 05:17+0000\n"
"X-Generator: Launchpad (build 15745)\n"
"X-Launchpad-Export-Date: 2012-08-18 04:58+0000\n"
"X-Generator: Launchpad (build 15810)\n"
#. module: account_analytic_default
#: help:account.analytic.default,partner_id:0
@ -133,7 +133,7 @@ msgstr "Аналитика по умолчанию"
#. module: account_analytic_default
#: sql_constraint:stock.picking:0
msgid "Reference must be unique per Company!"
msgstr ""
msgstr "Ссылка должна быть уникальна для каждой компании!"
#. module: account_analytic_default
#: view:account.analytic.default:0

View File

@ -1106,7 +1106,8 @@ class account_voucher(osv.osv):
# otherwise we use the rates of the system (giving the voucher date in the context)
amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)
if line.amount == line.amount_unreconciled and line.move_line_id.currency_id.id == voucher_currency:
foreign_currency_diff = line.move_line_id.amount_residual_currency + amount_currency
sign = voucher_brw.type in ('payment', 'purchase') and -1 or 1
foreign_currency_diff = sign * line.move_line_id.amount_residual_currency + amount_currency
move_line['amount_currency'] = amount_currency
voucher_line = move_line_obj.create(cr, uid, move_line)

View File

@ -1,3 +1,4 @@
import controllers
import auth_oauth
import res_users
import res_config

View File

@ -28,12 +28,13 @@
'author': 'Victor Tabuenca',
'maintainer': 'OpenERP s.a.',
'website': 'http://www.openerp.com',
'depends': ['base', 'web'],
'depends': ['base', 'web', 'base_setup'],
'data': [
'auth_oauth_data.xml'
'auth_oauth_data.xml',
],
'update_xml': [
'auth_oauth_view.xml'
'auth_oauth_view.xml',
'res_config.xml',
],
'js': [
'static/src/js/auth_oauth.js',

View File

@ -1,6 +1,6 @@
from openerp.osv import osv, fields
class auth_oauth_providers(osv.osv):
class auth_oauth_provider(osv.osv):
"""Class defining the configuration values of an OAuth2 provider"""
_name = 'auth.oauth.provider'
@ -8,15 +8,17 @@ class auth_oauth_providers(osv.osv):
_order = 'name'
_columns = {
'name' : fields.char('Provider name', required=True), # Name of the OAuth2 entity, Google, LinkedIn, etc
'client_id' : fields.char('Client ID', required=True), # Our identifier
'auth_endpoint' : fields.char('Authentication URL', required=True), # OAuth provider URL to authenticate users
'name' : fields.char('Provider name'), # Name of the OAuth2 entity, Google, LinkedIn, etc
'client_id' : fields.char('Client ID'), # Our identifier
'auth_endpoint' : fields.char('Authentication URL'), # OAuth provider URL to authenticate users
'scope' : fields.char('Scope'), # OAUth user data desired to access
'validation_endpoint' : fields.char('Validation URL'), # OAuth provider URL to validate tokens
'data_endpoint' : fields.char('Data URL'),
'enabled' : fields.boolean('Allowed'),
'css_class' : fields.char('CSS class'),
'body' : fields.char('Body'),
'active' : fields.boolean('Active'),
'sequence' : fields.integer(),
}
_defaults = {
'enabled' : False,
}

View File

@ -1,38 +1,34 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<data>
<record id="provider_facebook" model="auth.oauth.provider">
<field name="name">Facebook Graph</field>
<field name="client_id">facebook_client_id</field>
<field name="auth_endpoint">https://www.facebook.com/dialog/oauth</field>
<field name="scope"></field>
<field name="validation_endpoint">https://graph.facebook.com/me/permissions</field>
<field name="data_endpoint"></field>
<field name="css_class">zocial facebook</field>
<field name="body">Sign in with facebook</field>
<field name="active">True</field>
</record>
<record id="provider_google" model="auth.oauth.provider">
<field name="name">Google OAuth2</field>
<field name="client_id">108010644258-duuhmp6pu7li4tsmnqg7j9rvdeklg0ki.apps.googleusercontent.com</field>
<field name="auth_endpoint">https://accounts.google.com/o/oauth2/auth</field>
<field name="scope">https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile</field>
<field name="validation_endpoint">https://www.googleapis.com/oauth2/v1/tokeninfo</field>
<field name="data_endpoint">https://www.googleapis.com/oauth2/v1/userinfo</field>
<field name="css_class">zocial google</field>
<field name="body">Sign in with google</field>
<field name="active">True</field>
</record>
<record id="provider_twitter" model="auth.oauth.provider">
<field name="name">Twitter OAuth2</field>
<field name="client_id">108010644258-duuhmp6pu7li4tsmnqg7j9rvdeklg0ki.apps.twitterusercontent.com</field>
<!-- <record id="provider_twitter" model="auth.oauth.provider">
<field name="name">Twitter OAuth</field>
<field name="auth_endpoint">https://api.twitter.com/oauth/request_token</field>
<field name="scope"></field>
<field name="validation_endpoint">https://api.twitter.com/oauth/authorize</field>
<field name="data_endpoint"></field>
<field name="css_class">zocial twitter</field>
<field name="body">Sign in with twitter</field>
<field name="active">True</field>
</record>
</record> -->
</data>
</openerp>

View File

@ -11,7 +11,7 @@
<group>
<field name="name" />
<field name="client_id" />
<field name="active" />
<field name="enabled" />
</group>
<group>
<field name="auth_endpoint" />
@ -22,7 +22,7 @@
</sheet>
</form>
</field>
</record>
</record>
<record model="ir.ui.view" id="view_oauth_provider_list">
<field name="name">auth.oauth.provider.list</field>
<field name="model">auth.oauth.provider</field>
@ -31,7 +31,7 @@
<tree string="arch" version="7.0">
<field name="name" />
<field name="client_id" />
<field name="active" />
<field name="enabled" />
</tree>
</field>
</record>

View File

@ -18,7 +18,7 @@ class OAuthController(openerpweb.Controller):
registry = openerp.modules.registry.RegistryManager.get(dbname)
with registry.cursor() as cr:
providers = registry.get('auth.oauth.provider')
l = providers.read(cr, 1, providers.search(cr, 1, []))
l = providers.read(cr, 1, providers.search(cr, 1, [('enabled','=',True)]))
return l
@openerpweb.httprequest

View File

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
##############################################################################
from openerp.osv import osv, fields
import logging
_logger = logging.getLogger(__name__)
class base_config_settings(osv.TransientModel):
_inherit = 'base.config.settings'
_columns = {
'auth_oauth_google_enabled' : fields.boolean('Allow users to sign in with Google'),
'auth_oauth_google_client_id' : fields.char('Client ID'),
'auth_oauth_facebook_enabled' : fields.boolean('Allow users to sign in with Facebook'),
'auth_oauth_facebook_client_id' : fields.char('Client ID'),
}
def get_oauth_providers(self, cr, uid, fields, context=None):
google_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'auth_oauth', 'provider_google')[1]
facebook_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'auth_oauth', 'provider_facebook')[1]
rg = self.pool.get('auth.oauth.provider').read(cr, uid, [google_id], ['enabled','client_id'], context=context)
rf = self.pool.get('auth.oauth.provider').read(cr, uid, [facebook_id], ['enabled','client_id'], context=context)
return {
'auth_oauth_google_enabled': rg[0]['enabled'],
'auth_oauth_google_client_id': rg[0]['client_id'],
'auth_oauth_facebook_enabled': rf[0]['enabled'],
'auth_oauth_facebook_client_id': rf[0]['client_id'],
}
def set_oauth_providers(self, cr, uid, ids, context=None):
google_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'auth_oauth', 'provider_google')[1]
facebook_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'auth_oauth', 'provider_facebook')[1]
config = self.browse(cr, uid, ids[0], context=context)
rg = {
'enabled':config.auth_oauth_google_enabled,
'client_id':config.auth_oauth_google_client_id,
}
rf = {
'enabled':config.auth_oauth_facebook_enabled,
'client_id':config.auth_oauth_facebook_client_id,
}
self.pool.get('auth.oauth.provider').write(cr, uid, [google_id], rg)
self.pool.get('auth.oauth.provider').write(cr, uid, [facebook_id], rf)

View File

@ -0,0 +1,50 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_general_configuration">
<field name="name">base.config.settings.oauth</field>
<field name="model">base.config.settings</field>
<field name="inherit_id" ref="base_setup.view_general_configuration"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='module_auth_oauth']/.." position="after">
<div attrs="{'invisible':[('module_auth_oauth','=',False)]}">
<div name="google">
<div>
<field name="auth_oauth_google_enabled" class="oe_inline"/>
<label for="auth_oauth_google_enabled"/>
</div>
<div attrs="{'invisible':[('auth_oauth_google_enabled','=',False)]}">
<blockquote>
To setup the signin process with Google, first you have to perform the following steps:<br/>
<br/>
- Go to the <a href="https://code.google.com/apis/console/">Google APIs console</a><br/>
- Ceate a new project<br/>
- Go to Api Access<br/>
- Create an oauth client_id<br/>
- Edit settings and set both Authorized Redirect URIs and Authorized JavaScript Origins to your hostname.<br/>
<br/>
Now copy paste the client_id here: <field name="auth_oauth_google_client_id" class="oe_inline" placeholder="e.g. 1234-xyz.apps.googleusercontent.com"/>
</blockquote>
</div>
</div>
<div name="facebook">
<div>
<field name="auth_oauth_facebook_enabled" class="oe_inline"/>
<label for="auth_oauth_facebook_enabled"/>
</div>
<div attrs="{'invisible':[('auth_oauth_facebook_enabled','=',False)]}">
<blockquote>
To setup the signin process with Google, first you have to perform the following steps:<br/>
<br/>
Now copy paste the client_id here: <field name="auth_oauth_facebook_client_id" class="oe_inline" placeholder="e.g. 1234-xyz.apps.googleusercontent.com"/>
</blockquote>
</div>
</div>
</div>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -21,9 +21,7 @@ openerp.auth_oauth = function(instance) {
},
on_oauth_loaded: function(result) {
this.oauth_providers = result;
console.log(result);
var buttons = QWeb.render("auth_oauth.Login.button",{"widget":this});
console.log(buttons);
this.$(".oe_login_pane form ul").after(buttons);
},
on_oauth_sign_in: function(ev) {

View File

@ -25,7 +25,8 @@ 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):

View File

@ -7,16 +7,15 @@
<field name="model">base.config.settings</field>
<field name="inherit_id" ref="base_setup.view_general_configuration"/>
<field name="arch" type="xml">
<xpath expr="//group[last()]" position="after">
<group>
<label for="id" string="External Users"/>
<div>
<div>
<label for="auth_signup_template_user_id"/>
<field name="auth_signup_template_user_id" class="oe_inline"/>
</div>
</div>
</group>
<xpath expr="//field[@name='module_auth_anonymous']/.." position="after">
<div>
<field name="auth_signup_uninvited" class="oe_inline"/>
<label for="auth_signup_uninvited"/>
</div>
<div>
<label for="auth_signup_template_user_id"/>
<field name="auth_signup_template_user_id" class="oe_inline"/>
</div>
</xpath>
</field>
</record>

View File

@ -28,10 +28,13 @@ class base_config_settings(osv.osv_memory):
'module_multi_company': fields.boolean('manage multiple companies',
help="""Work in multi-company environments, with appropriate security access between companies.
This installs the module multi_company."""),
'module_portal': fields.boolean('activate customer portal',
help="""The portal will give access to a series of documents for your customers; his quotations, his invoices, his projects, etc."""),
'module_share': fields.boolean('allow documents sharing',
help="""As an example, you will be able to share a project or some tasks to your customers, or quotes/sales to several persons at your customer company, or your agenda availabilities to your contacts."""),
help="""Share or embbed any screen of openerp."""),
'module_portal': fields.boolean('activate the customer/supplier portal',
help="""Give access your customers and suppliers to their documents."""),
'module_auth_anonymous': fields.boolean('activate the public portal',
help="""Enable the public part of openerp, openerp becomes a public website."""),
'module_auth_oauth': fields.boolean('use external authentication providers, sign in with google, facebook, ...'),
}
def open_company(self, cr, uid, ids, context=None):

View File

@ -28,20 +28,34 @@
</div>
</group>
<group>
<label for="id" string="Share Data"/>
<div>
<label for="id" string="Email"/>
<div name="email">
<div>
<field name="module_share" class="oe_inline"/>
<label for="module_share"/>
<button type="action"
name="%(base.action_ir_mail_server_list)d"
string="Configure outgoing email servers" class="oe_link"/>
</div>
</div>
</group>
<group>
<label for="id" string="Portal access"/>
<div>
<div>
<field name="module_portal" class="oe_inline"/>
<label for="module_portal"/>
</div>
<div>
<button type="action"
name="%(base.action_ir_mail_server_list)d"
string="Configure outgoing email servers" class="oe_link"/>
<field name="module_auth_anonymous" class="oe_inline"/>
<label for="module_auth_anonymous"/>
</div>
</div>
</group>
<group>
<label for="id" string="Authentication"/>
<div>
<div>
<field name="module_auth_oauth" class="oe_inline"/>
<label for="module_auth_oauth"/>
</div>
</div>
</group>

View File

@ -34,8 +34,7 @@ The whole workflow is implemented:
* Draft expense
* Confirmation of the sheet by the employee
* Validation by his manager
* Validation by the accountant and invoice creation
* Payment of the invoice to the employee
* Validation by the accountant and receipt creation
This module also uses the analytic accounting and is compatible with
the invoice on timesheet module so that you will be able to automatically
@ -44,7 +43,7 @@ re-invoice your customer's expenses if your work by project.
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'images': ['images/hr_expenses_analysis.jpeg', 'images/hr_expenses.jpeg'],
'depends': ['hr', 'account'],
'depends': ['hr', 'account_voucher'],
'init_xml': [],
'update_xml': [
'security/ir.model.access.csv',

View File

@ -40,12 +40,16 @@ class hr_expense_expense(osv.osv):
if context is None:
context = {}
if not default: default = {}
default.update({'invoice_id': False, 'date_confirm': False, 'date_valid': False, 'user_valid': False})
default.update({'voucher_id': False, 'date_confirm': False, 'date_valid': False, 'user_valid': False})
return super(hr_expense_expense, self).copy(cr, uid, id, default, context=context)
def _amount(self, cr, uid, ids, field_name, arg, context=None):
cr.execute("SELECT s.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_expense s LEFT OUTER JOIN hr_expense_line l ON (s.id=l.expense_id) WHERE s.id IN %s GROUP BY s.id ", (tuple(ids),))
res = dict(cr.fetchall())
res= {}
for expense in self.browse(cr, uid, ids, context=context):
total = 0.0
for line in expense.line_ids:
total += line.unit_amount * line.unit_quantity
res[expense.id] = total
return res
def _get_currency(self, cr, uid, context=None):
@ -63,7 +67,7 @@ class hr_expense_expense(osv.osv):
'name': fields.char('Description', size=128, required=True),
'id': fields.integer('Sheet ID', readonly=True),
'date': fields.date('Date', select=True),
'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is invoiced"),
'journal_id': fields.many2one('account.journal', 'Force Journal', help = "The journal used when the expense is done."),
'employee_id': fields.many2one('hr.employee', "Employee", required=True),
'user_id': fields.many2one('res.users', 'User', required=True),
'date_confirm': fields.date('Confirmation Date', select=True, help = "Date of the confirmation of the sheet expense. It's filled when the button Confirm is pressed."),
@ -73,7 +77,7 @@ class hr_expense_expense(osv.osv):
'line_ids': fields.one2many('hr.expense.line', 'expense_id', 'Expense Lines', readonly=True, states={'draft':[('readonly',False)]} ),
'note': fields.text('Note'),
'amount': fields.function(_amount, string='Total Amount', digits_compute= dp.get_precision('Account')),
'invoice_id': fields.many2one('account.invoice', "Employee's Invoice"),
'voucher_id': fields.many2one('account.voucher', "Employee's Receipt"),
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
'department_id':fields.many2one('hr.department','Department'),
'company_id': fields.many2one('res.company', 'Company', required=True),
@ -82,11 +86,10 @@ class hr_expense_expense(osv.osv):
('cancelled', 'Refused'),
('confirm', 'Waiting Approval'),
('accepted', 'Approved'),
('invoiced', 'Invoiced'),
('paid', 'Reimbursed')
('done', 'Done'),
],
'Status', readonly=True, help='When the expense request is created the status is \'Draft\'.\n It is confirmed by the user and request is sent to admin, the status is \'Waiting Confirmation\'.\
\nIf the admin accepts it, the status is \'Accepted\'.\n If an invoice is made for the expense request, the status is \'Invoiced\'.\n If the expense is paid to user, the status is \'Reimbursed\'.'),
\nIf the admin accepts it, the status is \'Accepted\'.\n If a receipt is made for the expense request, the status is \'Done\'.'),
}
_defaults = {
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.employee', context=c),
@ -97,6 +100,13 @@ class hr_expense_expense(osv.osv):
'currency_id': _get_currency,
}
def onchange_currency_id(self, cr, uid, ids, currency_id=False, company_id=False, context=None):
res = {'value': {'journal_id': False}}
journal_ids = self.pool.get('account.journal').search(cr, uid, [('type','=','purchase'), ('currency','=',currency_id), ('company_id', '=', company_id)], context=context)
if journal_ids:
res['value']['journal_id'] = journal_ids[0]
return res
def onchange_employee_id(self, cr, uid, ids, employee_id, context=None):
emp_obj = self.pool.get('hr.employee')
department_id = False
@ -126,101 +136,94 @@ class hr_expense_expense(osv.osv):
self.write(cr, uid, ids, {'state':'cancelled'})
return True
def expense_paid(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state':'paid'})
return True
def invoice(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow")
mod_obj = self.pool.get('ir.model.data')
res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_supplier_form')
inv_ids = []
for id in ids:
wf_service.trg_validate(uid, 'hr.expense.expense', id, 'invoice', cr)
inv_ids.append(self.browse(cr, uid, id).invoice_id.id)
return {
'name': _('Supplier Invoices'),
'view_type': 'form',
'view_mode': 'form',
'view_id': [res and res[1] or False],
'res_model': 'account.invoice',
'context': "{'type':'out_invoice', 'journal_type': 'purchase'}",
'type': 'ir.actions.act_window',
'nodestroy': True,
'target': 'current',
'res_id': inv_ids and inv_ids[0] or False,
}
def action_invoice_create(self, cr, uid, ids):
res = False
invoice_obj = self.pool.get('account.invoice')
def action_receipt_create(self, cr, uid, ids, context=None):
property_obj = self.pool.get('ir.property')
sequence_obj = self.pool.get('ir.sequence')
analytic_journal_obj = self.pool.get('account.analytic.journal')
account_journal = self.pool.get('account.journal')
for exp in self.browse(cr, uid, ids):
voucher_obj = self.pool.get('account.voucher')
currency_obj = self.pool.get('res.currency')
wkf_service = netsvc.LocalService("workflow")
if context is None:
context = {}
for exp in self.browse(cr, uid, ids, context=context):
company_id = exp.company_id.id
lines = []
for l in exp.line_ids:
tax_id = []
if l.product_id:
acc = l.product_id.product_tmpl_id.property_account_expense
total = 0.0
ctx = context.copy()
ctx.update({'date': exp.date})
journal = False
if exp.journal_id:
journal = exp.journal_id
else:
journal_id = voucher_obj._get_journal(cr, uid, context={'type': 'purchase', 'company_id': company_id})
if journal_id:
journal = account_journal.browse(cr, uid, journal_id, context=context)
for line in exp.line_ids:
if line.product_id:
acc = line.product_id.product_tmpl_id.property_account_expense
if not acc:
acc = l.product_id.categ_id.property_account_expense_categ
tax_id = [x.id for x in l.product_id.supplier_taxes_id]
acc = line.product_id.categ_id.property_account_expense_categ
else:
acc = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context={'force_company': company_id})
if not acc:
raise osv.except_osv(_('Error!'), _('Please configure Default Expense account for Product purchase: `property_account_expense_categ`.'))
total_amount = line.total_amount
if journal.currency:
if exp.currency_id != journal.currency:
total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, journal.currency.id, total_amount, context=ctx)
elif exp.currency_id != exp.company_id.currency_id:
total_amount = currency_obj.compute(cr, uid, exp.currency_id.id, exp.company_id.currency_id.id, total_amount, context=ctx)
lines.append((0, False, {
'name': l.name,
'name': line.name,
'account_id': acc.id,
'price_unit': l.unit_amount,
'quantity': l.unit_quantity,
'uos_id': l.uom_id.id,
'product_id': l.product_id and l.product_id.id or False,
'invoice_line_tax_id': tax_id and [(6, 0, tax_id)] or False,
'account_analytic_id': l.analytic_account.id,
'account_analytic_id': line.analytic_account.id,
'amount': total_amount,
'type': 'dr'
}))
total += total_amount
if not exp.employee_id.address_home_id:
raise osv.except_osv(_('Error!'), _('The employee must have a home address.'))
acc = exp.employee_id.address_home_id.property_account_payable.id
payment_term_id = exp.employee_id.address_home_id.property_payment_term.id
inv = {
voucher = {
'name': exp.name,
'reference': sequence_obj.get(cr, uid, 'hr.expense.invoice'),
'account_id': acc,
'type': 'in_invoice',
'type': 'purchase',
'partner_id': exp.employee_id.address_home_id.id,
'company_id': company_id,
'origin': exp.name,
'invoice_line': lines,
'currency_id': exp.currency_id.id,
'payment_term': payment_term_id,
'fiscal_position': exp.employee_id.address_home_id.property_account_position.id
'line_ids': lines,
'amount': total,
'journal_id': journal.id,
}
if payment_term_id:
to_update = invoice_obj.onchange_payment_term_date_invoice(cr, uid, [], payment_term_id, None)
if to_update:
inv.update(to_update['value'])
journal = False
if exp.journal_id:
inv['journal_id']=exp.journal_id.id
journal = exp.journal_id
else:
journal_id = invoice_obj._get_journal(cr, uid, context={'type': 'in_invoice', 'company_id': company_id})
if journal_id:
inv['journal_id'] = journal_id
journal = account_journal.browse(cr, uid, journal_id)
if journal and not journal.analytic_journal_id:
analytic_journal_ids = analytic_journal_obj.search(cr, uid, [('type','=','purchase')])
analytic_journal_ids = analytic_journal_obj.search(cr, uid, [('type','=','purchase')], context=context)
if analytic_journal_ids:
account_journal.write(cr, uid, [journal.id],{'analytic_journal_id':analytic_journal_ids[0]})
inv_id = invoice_obj.create(cr, uid, inv, {'type': 'in_invoice'})
invoice_obj.button_compute(cr, uid, [inv_id], {'type': 'in_invoice'}, set_total=True)
self.write(cr, uid, [exp.id], {'invoice_id': inv_id, 'state': 'invoiced'})
res = inv_id
return res
account_journal.write(cr, uid, [journal.id], {'analytic_journal_id': analytic_journal_ids[0]}, context=context)
voucher_id = voucher_obj.create(cr, uid, voucher, context=context)
wkf_service.trg_validate(uid, 'account.voucher', voucher_id, 'proforma_voucher', cr)
self.write(cr, uid, [exp.id], {'voucher_id': voucher_id, 'state': 'done'}, context=context)
return True
def action_view_receipt(self, cr, uid, ids, context=None):
'''
This function returns an action that display existing receipt of given expense ids.
'''
assert len(ids) == 1, 'This option should only be used for a single id at a time'
voucher_id = self.browse(cr, uid, ids[0], context=context).voucher_id.id
res = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_voucher', 'view_purchase_receipt_form')
result = {
'name': _('Expense Receipt'),
'view_type': 'form',
'view_mode': 'form',
'view_id': res and res[1] or False,
'res_model': 'account.voucher',
'type': 'ir.actions.act_window',
'nodestroy': True,
'target': 'current',
'res_id': voucher_id,
}
return result
hr_expense_expense()

View File

@ -31,7 +31,7 @@
<field name="date"/>
<field name="user_id" invisible="1"/>
<field name="name"/>
<field name="currency_id"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="amount"/>
<field name="state"/>
</tree>
@ -42,7 +42,7 @@
<field name="name">hr.expense.expense.tree</field>
<field name="model">hr.expense.expense</field>
<field name="arch" type="xml">
<tree colors="blue:state == 'draft';black:state in ('confirm','accepted','invoiced','paid');gray:state == 'cancelled'" string="Expenses" editable="top">
<tree colors="blue:state == 'draft';black:state in ('confirm','accepted','done');gray:state == 'cancelled'" string="Expenses" editable="top">
<field name="employee_id"/>
<field name="date"/>
<field name="department_id"/>
@ -64,9 +64,10 @@
<button name="confirm" states="draft" string="Submit to Manager" type="workflow" class="oe_highlight"/>
<button name="validate" states="confirm" string="Approve" type="workflow" groups="base.group_hr_user" class="oe_highlight"/>
<button name="draft" states="confirm,cancelled" string="Set to Draft" type="workflow" groups="base.group_hr_user" />
<button name="invoice" states="accepted" string="Invoice" type="object" groups="base.group_hr_user" class="oe_highlight"/>
<button name="done" states="accepted" string="Generate Accounting Entries" type="workflow" groups="account.group_account_invoice" class="oe_highlight"/>
<button name="action_view_receipt" states="done" string="Open Receipt" type="object"/>
<button name="refuse" states="confirm,accepted" string="Refuse" type="workflow" groups="base.group_hr_user" />
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,accepted" statusbar_colors='{"confirm":"blue","cancelled":"red"}'/>
<field name="state" widget="statusbar" statusbar_visible="draft,confirm,accepted,done" statusbar_colors='{"confirm":"blue","cancelled":"red"}'/>
</header>
<sheet>
<group>
@ -79,7 +80,7 @@
<group>
<field name="name"/>
<field name="user_valid"/>
<field name="currency_id"/>
<field name="currency_id" groups="base.group_multi_currency" on_change="onchange_currency_id(currency_id, company_id)"/>
</group>
</group>
<notebook>
@ -105,14 +106,21 @@
</group>
</form>
</field>
<separator string="Notes"/>
<field name="note" placeholder="Free Notes"/>
<group>
<div>
<separator string="Notes"/>
<field name="note" placeholder="Free Notes"/>
</div>
<group class="oe_subtotal_footer">
<field name="amount"/>
</group>
</group>
</page>
<page string="Other Info">
<group>
<group string="Accounting Data">
<field name="journal_id"/>
<field name="invoice_id" context="{'type':'in_invoice', 'journal_type': 'purchase'}"/>
<field name="journal_id" widget="selection" domain="[('type', '=', 'purchase')]"/>
<field name="voucher_id" context="{'form_view_ref': 'account_voucher.view_purchase_receipt_form'}"/>
</group>
</group>
</page>

View File

@ -32,14 +32,6 @@
<field name="action">expense_accept()</field>
</record>
<record id="act_paid" model="workflow.activity">
<field name="wkf_id" ref="wkf_expenses"/>
<field name="name">paid</field>
<field name="kind">function</field>
<field name="action">expense_paid()</field>
<field name="flow_stop">True</field>
</record>
<record id="act_refused" model="workflow.activity">
<field name="wkf_id" ref="wkf_expenses"/>
<field name="name">refused</field>
@ -47,12 +39,11 @@
<field name="action">expense_canceled()</field>
</record>
<record id="act_invoice" model="workflow.activity">
<record id="act_done" model="workflow.activity">
<field name="wkf_id" ref="wkf_expenses"/>
<field name="name">invoice</field>
<field name="kind">subflow</field>
<field name="subflow_id" ref="account.wkf"/>
<field name="action">action_invoice_create()</field>
<field name="name">done</field>
<field name="kind">function</field>
<field name="action">action_receipt_create()</field>
</record>
<record id="t1" model="workflow.transition">
@ -91,15 +82,8 @@
<record id="t8" model="workflow.transition">
<field name="act_from" ref="act_accepted"/>
<field name="act_to" ref="act_invoice"/>
<field name="signal">invoice</field>
<field name="group_id" ref="base.group_hr_user"/>
</record>
<record id="t9" model="workflow.transition">
<field name="act_from" ref="act_invoice"/>
<field name="act_to" ref="act_paid"/>
<field name="signal">subflow.paid</field>
<field name="act_to" ref="act_done"/>
<field name="signal">done</field>
<field name="group_id" ref="base.group_hr_user"/>
</record>

View File

@ -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,

View File

@ -6,13 +6,13 @@
<field name="name">hr.expense.report.tree</field>
<field name="model">hr.expense.report</field>
<field name="arch" type="xml">
<tree colors="blue:state == 'draft';black:state in ('confirm','accepted','invoiced','paid');gray:state == 'cancelled'" string="Expenses Analysis">
<tree colors="blue:state == 'draft';black:state in ('confirm','accepted','done');gray:state == 'cancelled'" string="Expenses Analysis">
<field name="employee_id" invisible="1"/>
<field name="user_id" invisible="1"/>
<field name="year" invisible="1"/>
<field name="month" invisible="1"/>
<field name="day" invisible="1"/>
<field name="invoice_id" invisible="1"/>
<field name="voucher_id" invisible="1"/>
<field name="analytic_account" invisible="1" groups="analytic.group_analytic_accounting"/>
<field name="department_id" invisible="1"/>
<field name="company_id" invisible="1"/>
@ -22,7 +22,6 @@
<field name="state" invisible="1"/>
<field name="nbr" sum="# of Lines"/>
<field name="no_of_products" sum="# of Products"/>
<field name="invoiced" sum="Total Invoiced Lines"/>
<field name="price_average" avg="Average Price"/>
<field name="price_total" sum="Total Price"/>
<field name="delay_confirm"/>
@ -50,7 +49,7 @@
<search string="Expenses Analysis">
<filter string="Waiting" icon="terp-gtk-media-pause" domain="[('state', '=' ,'confirm')]" help = "Confirm Expenses"/>
<filter string="Approved" icon="terp-check" domain="[('state','=','accepted')]" help = "Approved Expenses"/>
<filter string="Invoiced" icon="terp-dolar" domain="[('state','in', ('invoiced', 'paid'))]" help = "Invoiced Expenses"/>
<filter string="Done" icon="terp-dolar" domain="[('state','=', 'done')]" help = "Done Expenses"/>
<field name="employee_id"/>
<field name="department_id"/>
<group expand="0" string="Extended Filters...">

View File

@ -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.
-

View File

@ -6,9 +6,10 @@
<field name="model">base.config.settings</field>
<field name="inherit_id" ref="base_setup.view_general_configuration"/>
<field name="arch" type="xml">
<xpath expr="/form/group[last()]/div[last()]/div[last()]" position='after' version="7.0">
<xpath expr="//div[@name='email']" position='inside'>
<div>
<label for="alias_domain" class="oe_inline"/><field name="alias_domain" placeholder="mycompany.my.openerp.com" class="oe_inline"/>
<label for="alias_domain" class="oe_inline"/>
<field name="alias_domain" placeholder="mycompany.my.openerp.com" class="oe_inline"/>
</div>
</xpath>
</field>

View File

@ -70,7 +70,7 @@
width: 486px;
}
.openerp div.oe_mail_msg_content li {
.openerp div.oe_mail_msg_content > li {
float: left;
margin-right: 3px;
}
@ -349,6 +349,11 @@
color: #888;
}
.openerp .oe_mail_msg_footer li {
float: left;
margin-right: 3px;
}
.openerp .oe_mail_msg_body {
margin-bottom: .5em;
text-align: justify;

View File

@ -838,19 +838,26 @@ openerp.mail = function(session) {
init: function() {
this._super.apply(this, arguments);
this.params = this.get_definition_options();
this.params = this.options;
this.params.thread_level = this.params.thread_level || 0;
this.thread = null;
this.ds = new session.web.DataSet(this, this.view.model);
this.ds_users = new session.web.DataSet(this, 'res.users');
},
start: function() {
// NB: all the widget should be modified to check the actual_mode property on view, not use
// any other method to know if the view is in create mode anymore
this.view.on("change:actual_mode", this, this._check_visibility);
this._check_visibility();
mail.ChatterUtils.bind_events(this);
this.$element.find('button.oe_mail_button_followers').click(function () { self.do_toggle_followers(); });
if (! this.params.see_subscribers_options) {
this.$element.find('button.oe_mail_button_followers').hide(); }
this.$element.find('button.oe_mail_button_follow').click(function () { self.do_follow(); });
this.$element.find('button.oe_mail_button_unfollow').click(function () { self.do_unfollow(); })
.mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); })
.mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); });
},
_check_visibility: function() {

View File

@ -61,6 +61,17 @@
<div class="oe_mail_recthread_main">
<!-- contains the document thread -->
</div>
<div class="oe_mail_recthread_aside">
<div class="oe_mail_recthread_actions">
<button type="button" class="oe_mail_button_follow">Follow</button>
<button type="button" class="oe_mail_button_unfollow oe_mail_button_mouseout">Following</button>
<button type="button" class="oe_mail_button_followers">Show followers</button>
</div>
<div class="oe_mail_recthread_followers">
<h4>Followers</h4>
<ul class="oe_mail_followers_display"></ul>
</div>
</div>
</div>
<!--
@ -104,7 +115,7 @@
<!-- default layout -->
<li t-name="mail.thread.message" class="oe_mail oe_mail_thread_msg">
<div t-attf-class="oe_mail_msg_#{record.type}">
<img class="oe_mail_icon oe_left" t-att-src="record.mini_url"/>
<img class="oe_mail_icon oe_mail_frame oe_left" t-att-src="record.mini_url"/>
<div class="oe_mail_msg_content">
<!-- dropdown menu with message options and actions -->
<span class="oe_dropdown_toggle oe_dropdown_arrow">

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
"PO-Revision-Date: 2010-10-26 08:32+0000\n"
"PO-Revision-Date: 2012-08-17 11:09+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\n"
"Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-08-07 05:25+0000\n"
"X-Generator: Launchpad (build 15745)\n"
"X-Launchpad-Export-Date: 2012-08-18 04:58+0000\n"
"X-Generator: Launchpad (build 15810)\n"
#. module: multi_company
#: model:res.company,overdue_msg:multi_company.res_company_odoo
@ -68,7 +68,7 @@ msgstr "Возвращаемое"
#. module: multi_company
#: model:ir.ui.menu,name:multi_company.menu_custom_multicompany
msgid "Multi-Companies"
msgstr ""
msgstr "Холдинги"
#. module: multi_company
#: view:multi_company.default:0

View File

@ -25,7 +25,7 @@
'depends' : [
'base',
'share',
'auth_anonymous'
'auth_signup',
],
'author' : 'OpenERP SA',
'category': 'Portal',

View File

@ -323,7 +323,7 @@
<field name="name">purchase.order.tree</field>
<field name="model">purchase.order</field>
<field name="arch" type="xml">
<tree fonts="bold:needaction_pending==True" colors="grey:state=='cancel';blue:state in (confirmed');red:state in ('except_invoice','except_picking')" string="Purchase Order">
<tree fonts="bold:needaction_pending==True" colors="grey:state=='cancel';blue:state in ('confirmed');red:state in ('except_invoice','except_picking')" string="Purchase Order">
<field name="needaction_pending" invisible="1"/>
<field name="name" string="Reference"/>
<field name="date_order" />

View File

@ -186,9 +186,9 @@
<para style="terp_default_9">
<font color="white"> </font>
</para>
<para style="terp_default_9">Tél. : [[ (o.partner_id.phone) or removeParentNode('para') ]]</para>
<para style="terp_default_9">Tel : [[ (o.partner_id.phone) or removeParentNode('para') ]]</para>
<para style="terp_default_9">Fax : [[ (o.partner_id.fax) or removeParentNode('para') ]]</para>
<para style="terp_default_9">TVA : [[ (o.partner_id.vat) or removeParentNode('para') ]]</para>
<para style="terp_default_9">TIN : [[ (o.partner_id.vat) or removeParentNode('para') ]]</para>
</td>
</tr>
</blockTable>