[MERGE]: Merge with lp:openobject-addons
bzr revid: mma@tinyerp.com-20121009101117-4fs6wj4mac954kcc
This commit is contained in:
+44
-17
@@ -595,12 +595,15 @@ class account_account(osv.osv):
|
||||
res.append((record['id'], name))
|
||||
return res
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None, done_list=[], local=False):
|
||||
def copy(self, cr, uid, id, default=None, context=None, done_list=None, local=False):
|
||||
if default is None:
|
||||
default = {}
|
||||
else:
|
||||
default = default.copy()
|
||||
if done_list is None:
|
||||
done_list = []
|
||||
account = self.browse(cr, uid, id, context=context)
|
||||
new_child_ids = []
|
||||
if not default:
|
||||
default = {}
|
||||
default = default.copy()
|
||||
default.update(code=_("%s (copy)") % (account['code'] or ''))
|
||||
if not local:
|
||||
done_list = []
|
||||
@@ -777,11 +780,14 @@ class account_journal(osv.osv):
|
||||
(_check_currency, 'Configuration error!\nThe currency chosen should be shared by the default accounts too.', ['currency','default_debit_account_id','default_credit_account_id']),
|
||||
]
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None, done_list=[], local=False):
|
||||
journal = self.browse(cr, uid, id, context=context)
|
||||
if not default:
|
||||
def copy(self, cr, uid, id, default=None, context=None, done_list=None, local=False):
|
||||
if default is None:
|
||||
default = {}
|
||||
default = default.copy()
|
||||
else:
|
||||
default = default.copy()
|
||||
if done_list is None:
|
||||
done_list = []
|
||||
journal = self.browse(cr, uid, id, context=context)
|
||||
default.update(
|
||||
code=_("%s (copy)") % (journal['code'] or ''),
|
||||
name=_("%s (copy)") % (journal['name'] or ''),
|
||||
@@ -1178,7 +1184,7 @@ class account_fiscalyear(osv.osv):
|
||||
'end_journal_period_id':fields.many2one('account.journal.period','End of Year Entries Journal', readonly=True),
|
||||
}
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None):
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
default.update({
|
||||
'period_ids': [],
|
||||
'end_journal_period_id': False
|
||||
@@ -1437,9 +1443,15 @@ class account_move(osv.osv):
|
||||
result = super(account_move, self).create(cr, uid, vals, context)
|
||||
return result
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None):
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if context is None:
|
||||
default = {}
|
||||
else:
|
||||
default = default.copy()
|
||||
if context is None:
|
||||
context = {}
|
||||
else:
|
||||
context = context.copy()
|
||||
default.update({
|
||||
'state':'draft',
|
||||
'name':'/',
|
||||
@@ -2269,7 +2281,10 @@ class account_model(osv.osv):
|
||||
_defaults = {
|
||||
'legend': lambda self, cr, uid, context:_('You can specify year, month and date in the name of the model using the following labels:\n\n%(year)s: To Specify Year \n%(month)s: To Specify Month \n%(date)s: Current Date\n\ne.g. My model on %(date)s'),
|
||||
}
|
||||
def generate(self, cr, uid, ids, datas={}, context=None):
|
||||
|
||||
def generate(self, cr, uid, ids, data=None, context=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
move_ids = []
|
||||
entry = {}
|
||||
account_move_obj = self.pool.get('account.move')
|
||||
@@ -2280,8 +2295,8 @@ class account_model(osv.osv):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
if datas.get('date', False):
|
||||
context.update({'date': datas['date']})
|
||||
if data.get('date', False):
|
||||
context.update({'date': data['date']})
|
||||
|
||||
move_date = context.get('date', time.strftime('%Y-%m-%d'))
|
||||
move_date = datetime.strptime(move_date,"%Y-%m-%d")
|
||||
@@ -2467,10 +2482,10 @@ class account_subscription_line(osv.osv):
|
||||
all_moves = []
|
||||
obj_model = self.pool.get('account.model')
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
datas = {
|
||||
data = {
|
||||
'date': line.date,
|
||||
}
|
||||
move_ids = obj_model.generate(cr, uid, [line.subscription_id.model_id.id], datas, context)
|
||||
move_ids = obj_model.generate(cr, uid, [line.subscription_id.model_id.id], data, context)
|
||||
tocheck[line.subscription_id.id] = True
|
||||
self.write(cr, uid, [line.id], {'move_id':move_ids[0]})
|
||||
all_moves.extend(move_ids)
|
||||
@@ -3236,7 +3251,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||
property_obj.create(cr, uid, vals, context=context)
|
||||
return True
|
||||
|
||||
def _install_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, acc_ref={}, taxes_ref={}, tax_code_ref={}, context=None):
|
||||
def _install_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, acc_ref=None, taxes_ref=None, tax_code_ref=None, context=None):
|
||||
'''
|
||||
This function recursively loads the template objects and create the real objects from them.
|
||||
|
||||
@@ -3254,6 +3269,12 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||
* a last identical containing the mapping of tax code templates and tax codes
|
||||
:rtype: tuple(dict, dict, dict)
|
||||
'''
|
||||
if acc_ref is None:
|
||||
acc_ref = {}
|
||||
if taxes_ref is None:
|
||||
taxes_ref = {}
|
||||
if tax_code_ref is None:
|
||||
tax_code_ref = {}
|
||||
template = self.pool.get('account.chart.template').browse(cr, uid, template_id, context=context)
|
||||
if template.parent_id:
|
||||
tmp1, tmp2, tmp3 = self._install_template(cr, uid, template.parent_id.id, company_id, code_digits=code_digits, acc_ref=acc_ref, taxes_ref=taxes_ref, tax_code_ref=tax_code_ref, context=context)
|
||||
@@ -3266,7 +3287,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||
tax_code_ref.update(tmp3)
|
||||
return acc_ref, taxes_ref, tax_code_ref
|
||||
|
||||
def _load_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, account_ref={}, taxes_ref={}, tax_code_ref={}, context=None):
|
||||
def _load_template(self, cr, uid, template_id, company_id, code_digits=None, obj_wizard=None, account_ref=None, taxes_ref=None, tax_code_ref=None, context=None):
|
||||
'''
|
||||
This function generates all the objects from the templates
|
||||
|
||||
@@ -3284,6 +3305,12 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||
* a last identical containing the mapping of tax code templates and tax codes
|
||||
:rtype: tuple(dict, dict, dict)
|
||||
'''
|
||||
if account_ref is None:
|
||||
account_ref = {}
|
||||
if taxes_ref is None:
|
||||
taxes_ref = {}
|
||||
if tax_code_ref is None:
|
||||
tax_code_ref = {}
|
||||
template = self.pool.get('account.chart.template').browse(cr, uid, template_id, context=context)
|
||||
obj_tax_code_template = self.pool.get('account.tax.code.template')
|
||||
obj_acc_tax = self.pool.get('account.tax')
|
||||
|
||||
@@ -29,12 +29,12 @@ class bank(osv.osv):
|
||||
'currency_id': fields.related('journal_id', 'currency', type="many2one", relation='res.currency', readonly=True,
|
||||
string="Currency", help="Currency of the related account journal."),
|
||||
}
|
||||
def create(self, cr, uid, data, context={}):
|
||||
def create(self, cr, uid, data, context=None):
|
||||
result = super(bank, self).create(cr, uid, data, context=context)
|
||||
self.post_write(cr, uid, [result], context=context)
|
||||
return result
|
||||
|
||||
def write(self, cr, uid, ids, data, context={}):
|
||||
def write(self, cr, uid, ids, data, context=None):
|
||||
result = super(bank, self).write(cr, uid, ids, data, context=context)
|
||||
self.post_write(cr, uid, ids, context=context)
|
||||
return result
|
||||
@@ -53,7 +53,7 @@ class bank(osv.osv):
|
||||
data['currency_name'] = data['currency_id'] and currency_name[data['currency_id'][0]] or ''
|
||||
return super(bank, self)._prepare_name_get(cr, uid, bank_dicts, context=context)
|
||||
|
||||
def post_write(self, cr, uid, ids, context={}):
|
||||
def post_write(self, cr, uid, ids, context=None):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
|
||||
|
||||
@@ -461,10 +461,9 @@ class account_bank_statement(osv.osv):
|
||||
return {}
|
||||
balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context)
|
||||
|
||||
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['default_debit_account_id', 'company_id'], context=context)
|
||||
account_id = journal_data['default_debit_account_id']
|
||||
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['company_id'], context=context)
|
||||
company_id = journal_data['company_id']
|
||||
return {'value': {'balance_start': balance_start, 'account_id': account_id, 'company_id': company_id}}
|
||||
return {'value': {'balance_start': balance_start, 'company_id': company_id}}
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
stat = self.read(cr, uid, ids, ['state'], context=context)
|
||||
|
||||
@@ -1308,17 +1308,19 @@ class account_invoice(osv.osv):
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>created</b>.") % (self._get_document_type(obj.type)),
|
||||
subtype="account.mt_invoice_new", context=context)
|
||||
|
||||
def confirm_paid_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>paid</b>.") % (self._get_document_type(obj.type)),
|
||||
subtype="account.mt_invoice_paid", context=context)
|
||||
|
||||
def invoice_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (_(self._get_document_type(obj.type))), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("%s <b>cancelled</b>.") % (self._get_document_type(obj.type)),
|
||||
context=context)
|
||||
|
||||
account_invoice()
|
||||
|
||||
class account_invoice_line(osv.osv):
|
||||
|
||||
@@ -1358,6 +1360,7 @@ class account_invoice_line(osv.osv):
|
||||
_columns = {
|
||||
'name': fields.text('Description', required=True),
|
||||
'origin': fields.char('Source', size=256, help="Reference of the document that produced this invoice."),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the invoice."),
|
||||
'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True),
|
||||
'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'),
|
||||
'product_id': fields.many2one('product.product', 'Product', ondelete='set null'),
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Invoice">
|
||||
<field context="{'partner_id': partner_id, 'price_type': 'price_type' in dir() and price_type or False, 'type': type}" name="invoice_line">
|
||||
<field context="{'partner_id': partner_id, 'price_type': context.get('price_type') or False, 'type': type}" name="invoice_line">
|
||||
<tree string="Invoice lines" editable="bottom">
|
||||
<field name="product_id"
|
||||
on_change="product_id_change(product_id, uos_id, quantity, name, parent.type, parent.partner_id, parent.fiscal_position, price_unit, parent.currency_id, context, parent.company_id)"/>
|
||||
@@ -278,7 +278,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
@@ -438,7 +437,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
||||
@@ -1105,7 +1105,7 @@ class account_move_line(osv.osv):
|
||||
'has been confirmed.') % res[2])
|
||||
return res
|
||||
|
||||
def _remove_move_reconcile(self, cr, uid, move_ids=[], context=None):
|
||||
def _remove_move_reconcile(self, cr, uid, move_ids=None, context=None):
|
||||
# Function remove move rencocile ids related with moves
|
||||
obj_move_line = self.pool.get('account.move.line')
|
||||
obj_move_rec = self.pool.get('account.move.reconcile')
|
||||
|
||||
@@ -1549,10 +1549,7 @@
|
||||
<field name="view_mode">account_reconciliation_list</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
Good job!
|
||||
</p><p>
|
||||
There is nothing to reconcile. All invoices and payments
|
||||
have been reconciled, your partner balance is clean.
|
||||
No journal items found.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -518,7 +518,6 @@
|
||||
<!--
|
||||
Account Statement Sequences
|
||||
-->
|
||||
|
||||
<record id="sequence_reconcile" model="ir.sequence.type">
|
||||
<field name="name">Account Reconcile</field>
|
||||
<field name="code">account.reconcile</field>
|
||||
@@ -554,8 +553,6 @@
|
||||
<field eval="1" name="number_next"/>
|
||||
<field eval="1" name="number_increment"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
Invoice requests (deprecated)
|
||||
-->
|
||||
@@ -564,7 +561,14 @@
|
||||
<field name="object">account.invoice</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!-- mail: subtypes -->
|
||||
<record id="mt_invoice_new" model="mail.message.subtype">
|
||||
<field name="name">created</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
</record>
|
||||
<record id="mt_invoice_paid" model="mail.message.subtype">
|
||||
<field name="name">paid</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -47,4 +47,4 @@ class account_analytic_chart(osv.osv_memory):
|
||||
return result
|
||||
|
||||
account_analytic_chart()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -52,4 +52,4 @@ class account_analytic_inverted_balance(osv.osv_memory):
|
||||
}
|
||||
|
||||
account_analytic_inverted_balance()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -55,4 +55,4 @@ class project_account_analytic_line(osv.osv_memory):
|
||||
|
||||
project_account_analytic_line()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -68,7 +68,7 @@ class account_balance(report_sxw.rml_parse, common_report_header):
|
||||
return self.pool.get('account.account').browse(self.cr, self.uid, data['form']['id']).company_id.name
|
||||
return super(account_balance ,self)._get_account(data)
|
||||
|
||||
def lines(self, form, ids=[], done=None):#, level=1):
|
||||
def lines(self, form, ids=None, done=None):
|
||||
def _process_child(accounts, disp_acc, parent):
|
||||
account_rec = [acct for acct in accounts if acct['id']==parent][0]
|
||||
currency_obj = self.pool.get('res.currency')
|
||||
|
||||
@@ -105,4 +105,4 @@ class journal_print(report_sxw.rml_parse, common_report_header):
|
||||
|
||||
report_sxw.report_sxw('report.account.central.journal', 'account.journal.period', 'addons/account/report/account_central_journal.rml', parser=journal_print, header='internal')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -158,4 +158,4 @@ class journal_print(report_sxw.rml_parse, common_report_header):
|
||||
|
||||
report_sxw.report_sxw('report.account.general.journal', 'account.journal.period', 'addons/account/report/general_journal.rml', parser=journal_print, header='internal')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -284,4 +284,4 @@ class report_account_sales(osv.osv):
|
||||
)""")
|
||||
report_account_sales()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -160,7 +160,7 @@ class tax_report(report_sxw.rml_parse, common_report_header):
|
||||
i+=1
|
||||
return res
|
||||
|
||||
def _get_codes(self, based_on, company_id, parent=False, level=0, period_list=[], context=None):
|
||||
def _get_codes(self, based_on, company_id, parent=False, level=0, period_list=None, context=None):
|
||||
obj_tc = self.pool.get('account.tax.code')
|
||||
ids = obj_tc.search(self.cr, self.uid, [('parent_id','=',parent),('company_id','=',company_id)], order='sequence', context=context)
|
||||
|
||||
@@ -171,7 +171,11 @@ class tax_report(report_sxw.rml_parse, common_report_header):
|
||||
res += self._get_codes(based_on, company_id, code.id, level+1, context=context)
|
||||
return res
|
||||
|
||||
def _add_codes(self, based_on, account_list=[], period_list=[], context=None):
|
||||
def _add_codes(self, based_on, account_list=None, period_list=None, context=None):
|
||||
if account_list is None:
|
||||
account_list = []
|
||||
if period_list is None:
|
||||
period_list = []
|
||||
res = []
|
||||
obj_tc = self.pool.get('account.tax.code')
|
||||
for account in account_list:
|
||||
|
||||
@@ -45,4 +45,3 @@ class res_currency_account(osv.osv):
|
||||
res_currency_account()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
@@ -3,10 +3,17 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="AccountReconciliation">
|
||||
<t t-if="widget.current_partner === null">
|
||||
<div class="oe_view_nocontent">
|
||||
<p>
|
||||
Good job!
|
||||
</p><p>
|
||||
There is nothing to reconcile. All invoices and payments
|
||||
have been reconciled, your partner balance is clean.
|
||||
</p>
|
||||
</div>
|
||||
</t>
|
||||
<div class="oe_account_reconciliation">
|
||||
<t t-if="widget.current_partner === null">
|
||||
There is no pending reconciliation.
|
||||
</t>
|
||||
<t t-if="widget.current_partner !== null">
|
||||
<div>
|
||||
<div>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-
|
||||
I create a supplier invoice
|
||||
-
|
||||
!record {model: account.invoice, id: account_invoice_supplier0}:
|
||||
!record {model: account.invoice, id: account_invoice_supplier0, view: invoice_supplier_form}:
|
||||
account_id: account.a_pay
|
||||
check_total: 3000.0
|
||||
company_id: base.main_company
|
||||
|
||||
@@ -71,4 +71,4 @@ class account_invoice_cancel(osv.osv_memory):
|
||||
|
||||
account_invoice_cancel()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
<field name="model">account.invoice.confirm</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Confirm Draft Invoices" version="7.0">
|
||||
<separator string="Confirm Draft Invoices"/>
|
||||
<p class="oe_grey">
|
||||
Once draft invoices are confirmed, you will not be able
|
||||
to modify them. The invoices will receive a unique
|
||||
number and journal items will be created in your chart
|
||||
of accounts.
|
||||
</p>
|
||||
<footer>
|
||||
<button string="Confirm Invoices" name="invoice_confirm" type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
@@ -27,7 +32,6 @@
|
||||
<field name="model">account.invoice.cancel</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Cancel Selected Invoices" version="7.0">
|
||||
<separator string="Cancel Selected Invoices"/>
|
||||
<footer>
|
||||
<button string="Cancel Invoices" name="invoice_cancel" type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
|
||||
@@ -47,4 +47,4 @@ class account_journal_select(osv.osv_memory):
|
||||
|
||||
account_journal_select()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -61,4 +61,4 @@ the bank account\nin the journal definition for reconciliation.'))
|
||||
|
||||
account_move_bank_reconcile()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -38,7 +38,7 @@ class account_move_journal(osv.osv_memory):
|
||||
_defaults = {
|
||||
'target_move': 'all'
|
||||
}
|
||||
def _get_period(self, cr, uid, context={}):
|
||||
def _get_period(self, cr, uid, context=None):
|
||||
"""
|
||||
Return default account period value
|
||||
"""
|
||||
|
||||
@@ -52,4 +52,4 @@ class account_move_line_reconcile_select(osv.osv_memory):
|
||||
|
||||
account_move_line_reconcile_select()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -69,4 +69,4 @@ class account_move_line_select(osv.osv_memory):
|
||||
|
||||
account_move_line_select()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -41,4 +41,4 @@ class account_move_line_unreconcile_select(osv.osv_memory):
|
||||
|
||||
account_move_line_unreconcile_select()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -160,4 +160,4 @@ class account_move_line_reconcile_writeoff(osv.osv_memory):
|
||||
|
||||
account_move_line_reconcile_writeoff()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -41,4 +41,4 @@ class account_state_open(osv.osv_memory):
|
||||
|
||||
account_state_open()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -50,4 +50,4 @@ class account_subscription_generate(osv.osv_memory):
|
||||
|
||||
account_subscription_generate()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -50,4 +50,4 @@ class account_unreconcile_reconcile(osv.osv_memory):
|
||||
|
||||
account_unreconcile_reconcile()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -34,7 +34,7 @@ class crossovered_analytic(report_sxw.rml_parse):
|
||||
})
|
||||
self.base_amount = 0.00
|
||||
|
||||
def find_children(self,ref_ids):
|
||||
def find_children(self, ref_ids):
|
||||
to_return_ids = []
|
||||
final_list = []
|
||||
parent_list = []
|
||||
@@ -53,7 +53,7 @@ class crossovered_analytic(report_sxw.rml_parse):
|
||||
final_list.extend(set_list)
|
||||
return final_list #to_return_ids[0]
|
||||
|
||||
def set_account(self,cats):
|
||||
def set_account(self, cats):
|
||||
lst = []
|
||||
category = self.pool.get('account.analytic.account').read(self.cr, self.uid, cats)
|
||||
for cat in category:
|
||||
@@ -62,7 +62,7 @@ class crossovered_analytic(report_sxw.rml_parse):
|
||||
lst.extend(self.set_account(cat['child_ids']))
|
||||
return lst
|
||||
|
||||
def _ref_lines(self,form):
|
||||
def _ref_lines(self, form):
|
||||
result = []
|
||||
res = {}
|
||||
acc_pool = self.pool.get('account.analytic.account')
|
||||
@@ -112,7 +112,9 @@ class crossovered_analytic(report_sxw.rml_parse):
|
||||
result.append(res)
|
||||
return result
|
||||
|
||||
def _lines(self, form, ids={}):
|
||||
def _lines(self, form, ids=None):
|
||||
if ids is None:
|
||||
ids = {}
|
||||
if not ids:
|
||||
ids = self.ids
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ import stock
|
||||
import purchase
|
||||
import invoice
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
|
||||
#class sale_order_line(osv.osv):
|
||||
# _name = 'sale.order.line'
|
||||
# _description = 'Sale Order line'
|
||||
# _inherit = 'sale.order.line'
|
||||
#
|
||||
# def invoice_line_create(self, cr, uid, ids, context={}):
|
||||
# line_ids = super('sale_order_line',self).invoice_line_create(cr, uid, ids, context)
|
||||
# invoice_line_obj = self.pool.get('account.invoice.line')
|
||||
# for line in invoice_line_obj.browse(cr, uid, line_ids):
|
||||
# if line.product_id:
|
||||
# a = line.product_id.product_tmpl_id.property_stock_account_output and line.product_id.product_tmpl_id.property_stock_account_output.id
|
||||
# if not a:
|
||||
# a = line.product_id.categ_id.property_stock_account_output_categ and line.product_id.categ_id.property_stock_account_output_categ.id
|
||||
# if a:
|
||||
# a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, a)
|
||||
# invoice_line_obj.write(cr, uid, line.id, {'account_id':a})
|
||||
#
|
||||
#sale_order_line()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -75,7 +75,7 @@ class account_asset_asset(osv.osv):
|
||||
_name = 'account.asset.asset'
|
||||
_description = 'Asset'
|
||||
|
||||
def _get_period(self, cr, uid, context={}):
|
||||
def _get_period(self, cr, uid, context=None):
|
||||
periods = self.pool.get('account.period').find(cr, uid)
|
||||
if periods:
|
||||
return periods[0]
|
||||
@@ -176,7 +176,9 @@ class account_asset_asset(osv.osv):
|
||||
year = depreciation_date.year
|
||||
return True
|
||||
|
||||
def validate(self, cr, uid, ids, context={}):
|
||||
def validate(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
return self.write(cr, uid, ids, {
|
||||
'state':'open'
|
||||
}, context)
|
||||
@@ -304,7 +306,7 @@ class account_asset_asset(osv.osv):
|
||||
default.update({'depreciation_line_ids': [], 'state': 'draft'})
|
||||
return super(account_asset_asset, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
def _compute_entries(self, cr, uid, ids, period_id, context={}):
|
||||
def _compute_entries(self, cr, uid, ids, period_id, context=None):
|
||||
result = []
|
||||
period_obj = self.pool.get('account.period')
|
||||
depreciation_obj = self.pool.get('account.asset.depreciation.line')
|
||||
|
||||
@@ -35,7 +35,9 @@ class analytic_account_budget_report(report_sxw.rml_parse):
|
||||
})
|
||||
self.context = context
|
||||
|
||||
def funct(self, object, form, ids={}, done=None, level=1):
|
||||
def funct(self, object, form, ids=None, done=None, level=1):
|
||||
if ids is None:
|
||||
ids = {}
|
||||
if not ids:
|
||||
ids = self.ids
|
||||
if not done:
|
||||
@@ -153,7 +155,7 @@ class analytic_account_budget_report(report_sxw.rml_parse):
|
||||
tot['perc'] = float(tot['prac'] / tot['theo']) * 100
|
||||
return result
|
||||
|
||||
def funct_total(self,form):
|
||||
def funct_total(self, form):
|
||||
result = []
|
||||
res = {}
|
||||
res = {
|
||||
@@ -167,4 +169,4 @@ class analytic_account_budget_report(report_sxw.rml_parse):
|
||||
|
||||
report_sxw.report_sxw('report.account.analytic.account.budget', 'account.analytic.account', 'addons/account_budget/report/analytic_account_budget_report.rml',parser=analytic_account_budget_report,header='internal')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -34,7 +34,9 @@ class budget_report(report_sxw.rml_parse):
|
||||
})
|
||||
self.context = context
|
||||
|
||||
def funct(self, object, form, ids={}, done=None, level=1):
|
||||
def funct(self, object, form, ids=None, done=None, level=1):
|
||||
if ids is None:
|
||||
ids = {}
|
||||
if not ids:
|
||||
ids = self.ids
|
||||
if not done:
|
||||
|
||||
@@ -37,7 +37,9 @@ class budget_report(report_sxw.rml_parse):
|
||||
})
|
||||
self.context = context
|
||||
|
||||
def funct(self, object, form, ids={}, done=None, level=1):
|
||||
def funct(self, object, form, ids=None, done=None, level=1):
|
||||
if ids is None:
|
||||
ids = {}
|
||||
if not ids:
|
||||
ids = self.ids
|
||||
if not done:
|
||||
|
||||
@@ -52,4 +52,4 @@ class account_budget_analytic(osv.osv_memory):
|
||||
|
||||
account_budget_analytic()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -53,4 +53,4 @@ class account_budget_crossvered_report(osv.osv_memory):
|
||||
|
||||
account_budget_crossvered_report()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -54,4 +54,4 @@ class account_budget_report(osv.osv_memory):
|
||||
|
||||
account_budget_report()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -23,4 +23,4 @@ import account_followup
|
||||
import wizard
|
||||
import report
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -7,14 +7,14 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
|
||||
"PO-Revision-Date: 2009-02-03 06:24+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"PO-Revision-Date: 2012-10-08 15:59+0000\n"
|
||||
"Last-Translator: waleed bazaza <waleed_bazaza@yahoo.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-28 06:07+0000\n"
|
||||
"X-Generator: Launchpad (build 15864)\n"
|
||||
"X-Launchpad-Export-Date: 2012-10-09 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build 16112)\n"
|
||||
|
||||
#. module: account_followup
|
||||
#: view:account_followup.followup:0
|
||||
@@ -42,7 +42,7 @@ msgstr "متابعة"
|
||||
#: help:account.followup.print.all,test_print:0
|
||||
msgid ""
|
||||
"Check if you want to print followups without changing followups level."
|
||||
msgstr ""
|
||||
msgstr "اختر هذه الخانة إذا أردت طباعة المتابعات بدون تغيير متوى المتابعات."
|
||||
|
||||
#. module: account_followup
|
||||
#: model:account_followup.followup.line,description:account_followup.demo_followup_line2
|
||||
@@ -101,7 +101,7 @@ msgstr "الدليل"
|
||||
#. module: account_followup
|
||||
#: view:account_followup.stat:0
|
||||
msgid "Follow up Entries with period in current year"
|
||||
msgstr ""
|
||||
msgstr "مدخلات المتابعات بفترات في السنة الحالية"
|
||||
|
||||
#. module: account_followup
|
||||
#: view:account.followup.print.all:0
|
||||
@@ -314,6 +314,9 @@ msgid ""
|
||||
"\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
"جميع رسائل البريد الالكتروني قد أرسلت بنجاح للشركاء:.\n"
|
||||
"\n"
|
||||
"%s"
|
||||
|
||||
#. module: account_followup
|
||||
#: constraint:account_followup.followup.line:0
|
||||
@@ -362,6 +365,11 @@ msgid ""
|
||||
"\n"
|
||||
"%s"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
"رسالة البريد الالكتروني قد أرسلت للشركاء التاليين.!\n"
|
||||
"\n"
|
||||
"%s"
|
||||
|
||||
#. module: account_followup
|
||||
#: help:account.followup.print,date:0
|
||||
@@ -503,7 +511,7 @@ msgstr "تقرير المتابعة"
|
||||
#. module: account_followup
|
||||
#: view:account_followup.followup.line:0
|
||||
msgid "Follow-Up Steps"
|
||||
msgstr ""
|
||||
msgstr "خطوات المتابعة"
|
||||
|
||||
#. module: account_followup
|
||||
#: field:account_followup.stat,period_id:0
|
||||
@@ -514,7 +522,7 @@ msgstr "فترة"
|
||||
#: code:addons/account_followup/wizard/account_followup_print.py:307
|
||||
#, python-format
|
||||
msgid "Followup Summary"
|
||||
msgstr ""
|
||||
msgstr "خلاصة المتابعة"
|
||||
|
||||
#. module: account_followup
|
||||
#: view:account.followup.print:0
|
||||
@@ -535,7 +543,7 @@ msgstr "مستوى اعلى متابعة"
|
||||
#. module: account_followup
|
||||
#: model:ir.actions.act_window,name:account_followup.action_view_account_followup_followup_form
|
||||
msgid "Review Invoicing Follow-Ups"
|
||||
msgstr ""
|
||||
msgstr "استعراض متابعة الفوترة"
|
||||
|
||||
#. module: account_followup
|
||||
#: constraint:account.move.line:0
|
||||
@@ -595,7 +603,7 @@ msgstr "الوصف"
|
||||
#. module: account_followup
|
||||
#: constraint:account_followup.followup:0
|
||||
msgid "Only One Followup by Company."
|
||||
msgstr ""
|
||||
msgstr "متابعة واحدة غقط من الشركة."
|
||||
|
||||
#. module: account_followup
|
||||
#: view:account_followup.stat:0
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
|
||||
import account_followup_print
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -209,7 +209,7 @@ class account_followup_print_all(osv.osv_memory):
|
||||
to_update[str(id)]= {'level': fups[followup_line_id][1], 'partner_id': stat_line_id}
|
||||
return {'partner_ids': partner_list, 'to_update': to_update}
|
||||
|
||||
def do_mail(self ,cr, uid, ids, context=None):
|
||||
def do_mail(self, cr, uid, ids, context=None):
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
move_obj = self.pool.get('account.move.line')
|
||||
user_obj = self.pool.get('res.users')
|
||||
|
||||
@@ -29,4 +29,4 @@ import account_move_line
|
||||
import account_invoice
|
||||
import report
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -50,4 +50,4 @@ class Invoice(osv.osv):
|
||||
|
||||
Invoice()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -26,7 +26,7 @@ from tools.translate import _
|
||||
class account_move_line(osv.osv):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
def amount_to_pay(self, cr, uid, ids, name, arg={}, context=None):
|
||||
def amount_to_pay(self, cr, uid, ids, name, arg=None, context=None):
|
||||
""" Return the amount still to pay regarding all the payemnt orders
|
||||
(excepting cancelled orders)"""
|
||||
if not ids:
|
||||
@@ -117,4 +117,4 @@ class account_move_line(osv.osv):
|
||||
|
||||
account_move_line()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -139,7 +139,9 @@ class payment_order(osv.osv):
|
||||
wf_service.trg_validate(uid, 'payment.order', ids[0], 'done', cr)
|
||||
return True
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None):
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
default.update({
|
||||
'state': 'draft',
|
||||
'line_ids': [],
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
##############################################################################
|
||||
|
||||
import payment_order
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -77,7 +77,7 @@ class payment_order(report_sxw.rml_parse):
|
||||
user = pool.get('res.users').browse(self.cr, self.uid, self.uid)
|
||||
return user.company_id and user.company_id.currency_id and user.company_id.currency_id.symbol or False
|
||||
|
||||
def _get_account_name(self,bank_id):
|
||||
def _get_account_name(self, bank_id):
|
||||
if bank_id:
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
value_name = pool.get('res.partner.bank').name_get(self.cr, self.uid, [bank_id])
|
||||
@@ -87,4 +87,4 @@ class payment_order(report_sxw.rml_parse):
|
||||
|
||||
report_sxw.report_sxw('report.payment.order', 'payment.order', 'addons/account_payment/report/payment_order.rml', parser=payment_order, header="external")
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -23,4 +23,4 @@ import account_payment_order
|
||||
import account_payment_populate_statement
|
||||
import account_payment_pay
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -56,4 +56,4 @@ class account_payment_make_payment(osv.osv_memory):
|
||||
|
||||
account_payment_make_payment()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -86,24 +86,24 @@ class account_payment_populate_statement(osv.osv_memory):
|
||||
'name': line.name,
|
||||
'partner_id': line.partner_id.id,
|
||||
'journal_id': statement.journal_id.id,
|
||||
'account_id': result.get('account_id', statement.journal_id.default_credit_account_id.id),
|
||||
'account_id': result['value'].get('account_id', statement.journal_id.default_credit_account_id.id),
|
||||
'company_id': statement.company_id.id,
|
||||
'currency_id': statement.currency.id,
|
||||
'date': line.date or time.strftime('%Y-%m-%d'),
|
||||
'amount': abs(amount),
|
||||
'period_id': statement.period_id.id
|
||||
'period_id': statement.period_id.id,
|
||||
}
|
||||
voucher_id = voucher_obj.create(cr, uid, voucher_res, context=context)
|
||||
voucher_line_dict = False
|
||||
if result['value']['line_ids']:
|
||||
for line_dict in result['value']['line_ids']:
|
||||
move_line = move_line_obj.browse(cr, uid, line_dict['move_line_id'], context)
|
||||
if line.move_line_id.move_id.id == move_line.move_id.id:
|
||||
voucher_line_dict = line_dict
|
||||
|
||||
voucher_line_dict = {}
|
||||
for line_dict in result['value']['line_cr_ids'] + result['value']['line_dr_ids']:
|
||||
move_line = move_line_obj.browse(cr, uid, line_dict['move_line_id'], context)
|
||||
if line.move_line_id.move_id.id == move_line.move_id.id:
|
||||
voucher_line_dict = line_dict
|
||||
|
||||
if voucher_line_dict:
|
||||
voucher_line_dict.update({'voucher_id': voucher_id})
|
||||
voucher_line_obj.create(cr, uid, voucher_line_dict, context=context)
|
||||
|
||||
st_line_id = statement_line_obj.create(cr, uid, {
|
||||
'name': line.order_id.reference or '?',
|
||||
'amount': - amount,
|
||||
@@ -120,4 +120,4 @@ class account_payment_populate_statement(osv.osv_memory):
|
||||
|
||||
account_payment_populate_statement()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
import account_sequence
|
||||
import account_sequence_installer
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -24,4 +24,4 @@ import invoice
|
||||
import report
|
||||
import wizard
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -547,6 +547,19 @@ class account_voucher(osv.osv):
|
||||
vals = self.recompute_payment_rate(cr, uid, ids, res, currency_id, date, ttype, journal_id, amount, context=context)
|
||||
for key in vals.keys():
|
||||
res[key].update(vals[key])
|
||||
#TODO: onchange_partner_id() should not returns [pre_line, line_dr_ids, payment_rate...] for type sale, and not
|
||||
# [pre_line, line_cr_ids, payment_rate...] for type purchase.
|
||||
# We should definitively split account.voucher object in two and make distinct on_change functions. In the
|
||||
# meanwhile, bellow lines must be there because the fields aren't present in the view, what crashes if the
|
||||
# onchange returns a value for them
|
||||
if ttype == 'sale':
|
||||
del(res['value']['line_dr_ids'])
|
||||
del(res['value']['pre_line'])
|
||||
del(res['value']['payment_rate'])
|
||||
elif ttype == 'purchase':
|
||||
del(res['value']['line_cr_ids'])
|
||||
del(res['value']['pre_line'])
|
||||
del(res['value']['payment_rate'])
|
||||
return res
|
||||
|
||||
def recompute_voucher_lines(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context=None):
|
||||
@@ -588,7 +601,7 @@ class account_voucher(osv.osv):
|
||||
|
||||
#set default values
|
||||
default = {
|
||||
'value': {'line_ids': [] ,'line_dr_ids': [] ,'line_cr_ids': [] ,'pre_line': False,},
|
||||
'value': {'line_dr_ids': [] ,'line_cr_ids': [] ,'pre_line': False,},
|
||||
}
|
||||
|
||||
#drop existing lines
|
||||
@@ -667,6 +680,7 @@ class account_voucher(osv.osv):
|
||||
|
||||
#voucher line creation
|
||||
for line in account_move_lines:
|
||||
|
||||
if _remove_noise_in_o2m():
|
||||
continue
|
||||
|
||||
@@ -771,8 +785,10 @@ class account_voucher(osv.osv):
|
||||
if account_id and account_id.tax_ids:
|
||||
tax_id = account_id.tax_ids[0].id
|
||||
|
||||
vals = self.onchange_price(cr, uid, ids, line_ids, tax_id, partner_id, context)
|
||||
vals['value'].update({'tax_id':tax_id,'amount': amount})
|
||||
vals = {'value':{} }
|
||||
if ttype in ('sale', 'purchase'):
|
||||
vals = self.onchange_price(cr, uid, ids, line_ids, tax_id, partner_id, context)
|
||||
vals['value'].update({'tax_id':tax_id,'amount': amount})
|
||||
currency_id = False
|
||||
if journal.currency:
|
||||
currency_id = journal.currency.id
|
||||
@@ -849,7 +865,7 @@ class account_voucher(osv.osv):
|
||||
res['account_id'] = account_id
|
||||
return {'value':res}
|
||||
|
||||
def _sel_context(self, cr, uid, voucher_id,context=None):
|
||||
def _sel_context(self, cr, uid, voucher_id, context=None):
|
||||
"""
|
||||
Select the context to use accordingly if it needs to be multicurrency or not.
|
||||
|
||||
@@ -1183,6 +1199,7 @@ class account_voucher(osv.osv):
|
||||
account_id = voucher_brw.partner_id.property_account_receivable.id
|
||||
else:
|
||||
account_id = voucher_brw.partner_id.property_account_payable.id
|
||||
sign = voucher_brw.type == 'payment' and -1 or 1
|
||||
move_line = {
|
||||
'name': write_off_name or name,
|
||||
'account_id': account_id,
|
||||
@@ -1191,7 +1208,7 @@ class account_voucher(osv.osv):
|
||||
'date': voucher_brw.date,
|
||||
'credit': diff > 0 and diff or 0.0,
|
||||
'debit': diff < 0 and -diff or 0.0,
|
||||
'amount_currency': company_currency <> current_currency and voucher_brw.writeoff_amount or False,
|
||||
'amount_currency': company_currency <> current_currency and (sign * -1 * voucher_brw.writeoff_amount) or False,
|
||||
'currency_id': company_currency <> current_currency and current_currency or False,
|
||||
'analytic_account_id': voucher_brw.analytic_id and voucher_brw.analytic_id.id or False,
|
||||
}
|
||||
@@ -1275,7 +1292,9 @@ class account_voucher(osv.osv):
|
||||
self.reconcile_send_note(cr, uid, [voucher.id], context=context)
|
||||
return True
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context=None):
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
default.update({
|
||||
'state': 'draft',
|
||||
'number': False,
|
||||
@@ -1302,17 +1321,17 @@ class account_voucher(osv.osv):
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
message = "%s <b>created</b>." % self._document_type[obj.type or False]
|
||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
|
||||
|
||||
def post_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
message = "%s '%s' is <b>posted</b>." % (self._document_type[obj.type or False], obj.move_id.name)
|
||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
|
||||
|
||||
def reconcile_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
message = "%s <b>reconciled</b>." % self._document_type[obj.type or False]
|
||||
self.message_post(cr, uid, [obj.id], body=message, context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=message, subtype="account_voucher.mt_voucher", context=context)
|
||||
|
||||
account_voucher()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- notify all employees of module installation -->
|
||||
<record model="mail.message" id="module_install_notification">
|
||||
<field name="model">mail.group</field>
|
||||
@@ -13,5 +14,12 @@
|
||||
<p>You can track customer payments easily and automate follow-ups. You get an overview of the discussion with your customers on each invoice for easier traceability. For advanced accounting features, you should install the "Accounting and Finance" module.</p>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
<!-- mail: subtypes -->
|
||||
<record id="mt_voucher" model="mail.message.subtype">
|
||||
<field name="name">Status Change</field>
|
||||
<field name="res_model">account.voucher</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- where and when is this view used?? -->
|
||||
<record model="ir.ui.view" id="view_voucher_form">
|
||||
<field name="name">account.voucher.form</field>
|
||||
<field name="model">account.voucher</field>
|
||||
@@ -108,7 +109,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
||||
@@ -23,4 +23,4 @@ import account_voucher
|
||||
import account_voucher_print
|
||||
import account_voucher_sales_receipt
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
-
|
||||
In order to check account voucher module in OpenERP I create a customer voucher
|
||||
-
|
||||
!record {model: account.voucher, id: account_voucher_voucherforaxelor0}:
|
||||
!record {model: account.voucher, id: account_voucher_voucherforaxelor0, view: view_sale_receipt_form}:
|
||||
type: sale
|
||||
account_id: account.cash
|
||||
amount: 1000.0
|
||||
company_id: base.main_company
|
||||
@@ -47,7 +48,8 @@
|
||||
-
|
||||
Now I create a Vendor Voucher
|
||||
-
|
||||
!record {model: account.voucher, id: account_voucher_voucheraxelor0, view: False}:
|
||||
!record {model: account.voucher, id: account_voucher_voucheraxelor0, view: view_voucher_filter_vendor}:
|
||||
type: purchase
|
||||
account_id: account.cash
|
||||
amount: 1000.0
|
||||
company_id: base.main_company
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
-
|
||||
Demo for Account Voucher
|
||||
-
|
||||
!record {model: account.voucher, id: account_voucher_voucheraxelor0again}:
|
||||
!record {model: account.voucher, id: account_voucher_voucheraxelor0again, view: view_sale_receipt_form}:
|
||||
type: sale
|
||||
account_id: account.cash
|
||||
company_id: base.main_company
|
||||
journal_id: account.bank_journal
|
||||
|
||||
@@ -216,6 +216,10 @@
|
||||
assert move_line.credit == 63.00, "Debtor account has wrong entry."
|
||||
elif move_line.amount_currency == 10.00:
|
||||
assert move_line.debit == 9.00, "Writeoff amount is wrong."
|
||||
elif move_line.amount_currency == 240.00:
|
||||
assert move_line.debit == 216.00, "Bank entry is wrong."
|
||||
else:
|
||||
assert False, "Unrecognized journal entry"
|
||||
-
|
||||
I check the residual amount of Invoice1, should be 20 in amount_currency
|
||||
-
|
||||
@@ -237,7 +241,7 @@
|
||||
-
|
||||
On the first April, I create the second voucher of payment with values 45 USD, journal USD,
|
||||
-
|
||||
!record {model: account.voucher, id: account_voucher_2_case1}:
|
||||
!record {model: account.voucher, id: account_voucher_2_case1, view: view_vendor_receipt_form}:
|
||||
account_id: account.cash
|
||||
amount: 45.0
|
||||
company_id: base.main_company
|
||||
@@ -323,8 +327,16 @@
|
||||
assert move_line.debit == 4.75, "Writeoff amount is wrong."
|
||||
elif move_line.debit == 11.5 and move_line.account_id.reconcile:
|
||||
assert move_line.amount_currency == 0.0 and move_line.reconcile_id.id == reconcile_a, "Exchange difference entry for the invoice of 100$ is wrong"
|
||||
elif move_line.credit == 11.5:
|
||||
assert move_line.amount_currency == 0.0
|
||||
elif move_line.debit == 31.0 and move_line.account_id.reconcile:
|
||||
assert move_line.amount_currency == 0.0 and move_line.reconcile_id.id == reconcile_b, "Exchange difference entry for the invoice of 200$ is wrong"
|
||||
elif move_line.credit == 31.0:
|
||||
assert move_line.amount_currency == 0.0
|
||||
elif move_line.amount_currency == 45.00:
|
||||
assert move_line.debit == 42.75, "Bank entry is wrong."
|
||||
else:
|
||||
assert False, "Unrecognized journal entry"
|
||||
-
|
||||
I check the residual amount of Invoice1, should be 0 in residual currency and 0 in amount_residual and paid
|
||||
-
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
-
|
||||
I check that my currency rate difference is correct. 0 in debit with no amount_currency
|
||||
-
|
||||
I check that my writeoff is correct. 11.05 credit and 13.26 amount_currency
|
||||
I check that my writeoff is correct. 11.05 credit and -13.26 amount_currency
|
||||
-
|
||||
!python {model: account.voucher}: |
|
||||
voucher = self.search(cr, uid, [('name', '=', 'First payment: Case 4'), ('partner_id', '=', ref('base.res_partner_19'))])
|
||||
@@ -179,7 +179,7 @@
|
||||
elif move_line.debit == 0.00 and move_line.credit == 0.00:
|
||||
assert move_line.amount_currency == 0.00, "Incorrect Currency Difference."
|
||||
elif move_line.credit == 10.61:
|
||||
assert move_line.amount_currency == 13.26, "Writeoff amount is wrong."
|
||||
assert move_line.amount_currency == -13.26, "Writeoff amount is wrong."
|
||||
else:
|
||||
assert False, "Wrong entry"
|
||||
-
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
-
|
||||
Creating a Voucher Receipt for partner Seagate with amount 30000.0
|
||||
-
|
||||
!record {model: account.voucher, id: account_voucher_seagate_0}:
|
||||
!record {model: account.voucher, id: account_voucher_seagate_0, view: view_sale_receipt_form}:
|
||||
account_id: account.a_recv
|
||||
amount: 30000.0
|
||||
company_id: base.main_company
|
||||
|
||||
@@ -243,7 +243,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
@@ -519,7 +518,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<h1><label for="number" string="Sale Receipt"/> <field name="number" class="oe_inline" readonly="1"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="type" invisible="True"/>
|
||||
<field name="partner_id" domain="[('customer','=',True)]" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": true}'/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
@@ -80,9 +81,9 @@
|
||||
<field name="date" on_change="onchange_date(date, currency_id, currency_id, amount, company_id, context)"/>
|
||||
<field name="name"/>
|
||||
<field name="paid" invisible="1"/>
|
||||
<field name="paid_amount_in_company_currency" invisible="1"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
</group>
|
||||
<field name="type" invisible="True"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Sales Information">
|
||||
@@ -146,7 +147,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
@@ -236,6 +236,7 @@
|
||||
widget="selection"
|
||||
on_change="onchange_journal(journal_id, line_dr_ids, tax_id, partner_id, date, amount, type, company_id, context)"
|
||||
groups="account.group_account_user"/>
|
||||
<field name="paid_amount_in_company_currency" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
@@ -302,7 +303,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,8 @@ that have no counterpart in the general financial accounts.
|
||||
'security/analytic_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'analytic_sequence.xml',
|
||||
'analytic_view.xml'
|
||||
'analytic_view.xml',
|
||||
'analytic_data.xml'
|
||||
],
|
||||
'demo': [],
|
||||
'installable': True,
|
||||
|
||||
@@ -125,7 +125,8 @@ class account_analytic_account(osv.osv):
|
||||
if account.company_id:
|
||||
if account.company_id.currency_id.id != value:
|
||||
raise osv.except_osv(_('Error!'), _("If you set a company, the currency selected has to be the same as it's currency. \nYou can remove the company belonging, and thus change the currency, only on analytic account of type 'view'. This can be really usefull for consolidation purposes of several companies charts with different currencies, for example."))
|
||||
return cr.execute("""update account_analytic_account set currency_id=%s where id=%s""", (value, account.id, ))
|
||||
if value:
|
||||
return cr.execute("""update account_analytic_account set currency_id=%s where id=%s""", (value, account.id, ))
|
||||
|
||||
def _currency(self, cr, uid, ids, field_name, arg, context=None):
|
||||
result = {}
|
||||
@@ -163,7 +164,7 @@ class account_analytic_account(osv.osv):
|
||||
'date': fields.date('Date End', select=True),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
|
||||
'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','To Renew'),('close','Closed')], 'Status', required=True,),
|
||||
'currency_id': fields.function(_currency, fnct_inv=_set_company_currency,
|
||||
'currency_id': fields.function(_currency, fnct_inv=_set_company_currency, #the currency_id field is readonly except if it's a view account and if there is no company
|
||||
store = {
|
||||
'res.company': (_get_analytic_account, ['currency_id'], 10),
|
||||
}, string='Currency', type='many2one', relation='res.currency'),
|
||||
@@ -284,7 +285,8 @@ class account_analytic_account(osv.osv):
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name), context=context)
|
||||
self.message_post(cr, uid, [obj.id], body=_("Contract for <em>%s</em> has been <b>created</b>.") % (obj.partner_id.name),
|
||||
subtype="analytic.mt_account_status", context=context)
|
||||
|
||||
account_analytic_account()
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- mail: subtypes -->
|
||||
<record id="mt_account_status" model="mail.message.subtype">
|
||||
<field name="name">Status Change</field>
|
||||
<field name="res_model">account.analytic.account</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -24,6 +24,7 @@
|
||||
<field name="partner_id" on_change="on_change_partner_id(partner_id, name)" attrs="{'required':[('type','=','contract')]}"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="code"/>
|
||||
<field name="currency_id" attrs="{'invisible': ['|',('type', '<>', 'view'), ('company_id', '<>', False)]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="type"/>
|
||||
@@ -53,7 +54,6 @@
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_is_follower" invisible="1"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
</div>
|
||||
|
||||
@@ -1,63 +1,86 @@
|
||||
# Translation of OpenERP Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * analytic_user_function
|
||||
# Dutch (Belgium) translation for openobject-addons
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 15:34:14+0000\n"
|
||||
"PO-Revision-Date: 2009-08-28 15:34:14+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-08 00:35+0000\n"
|
||||
"PO-Revision-Date: 2012-10-02 07:35+0000\n"
|
||||
"Last-Translator: Els Van Vossel (Agaplan) <Unknown>\n"
|
||||
"Language-Team: Dutch (Belgium) <nl_BE@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-10-03 05:09+0000\n"
|
||||
"X-Generator: Launchpad (build 16061)\n"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr ""
|
||||
#: field:analytic.user.funct.grid,product_id:0
|
||||
msgid "Product"
|
||||
msgstr "Product"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: model:ir.model,name:analytic_user_function.model_analytic_user_funct_grid
|
||||
msgid "Relation table between users and products on a analytic account"
|
||||
msgstr ""
|
||||
"Relatietabel tussen gebruikers en producten van een analytische rekening"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: field:analytic_user_funct_grid,product_id:0
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
#: constraint:hr.analytic.timesheet:0
|
||||
msgid "You cannot modify an entry in a Confirmed/Done timesheet !."
|
||||
msgstr "In een bevestigde/afgesloten uurrooster kunt u geen regels wijzigen."
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: field:analytic_user_funct_grid,account_id:0
|
||||
#: field:analytic.user.funct.grid,account_id:0
|
||||
#: model:ir.model,name:analytic_user_function.model_account_analytic_account
|
||||
msgid "Analytic Account"
|
||||
msgstr ""
|
||||
msgstr "Analytische rekening"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: view:account.analytic.account:0
|
||||
#: field:account.analytic.account,user_product_ids:0
|
||||
msgid "Users/Products Rel."
|
||||
msgstr ""
|
||||
msgstr "Rel. gebruikers/producten"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: field:analytic_user_funct_grid,user_id:0
|
||||
#: field:analytic.user.funct.grid,user_id:0
|
||||
msgid "User"
|
||||
msgstr "Gebruiker"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: code:addons/analytic_user_function/analytic_user_function.py:96
|
||||
#: code:addons/analytic_user_function/analytic_user_function.py:131
|
||||
#, python-format
|
||||
msgid "There is no expense account define for this product: \"%s\" (id:%d)"
|
||||
msgstr ""
|
||||
"Er is geen kostenrekening gedefinieerd voor dit product: \"%s\" (id:%d)"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: constraint:ir.model:0
|
||||
msgid "The Object name must start with x_ and not contain any special character !"
|
||||
msgstr "De objectnaam moet beginnen met x_ en mag geen speciale karakters bevatten !"
|
||||
#: code:addons/analytic_user_function/analytic_user_function.py:95
|
||||
#: code:addons/analytic_user_function/analytic_user_function.py:130
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr "Fout"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: model:ir.module.module,shortdesc:analytic_user_function.module_meta_information
|
||||
msgid "Analytic User Function"
|
||||
msgstr ""
|
||||
#: constraint:account.analytic.account:0
|
||||
msgid "Error! You can not create recursive analytic accounts."
|
||||
msgstr "U kunt niet dezelfde analytische rekeningen maken."
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: view:analytic_user_funct_grid:0
|
||||
#: model:ir.model,name:analytic_user_function.model_hr_analytic_timesheet
|
||||
msgid "Timesheet Line"
|
||||
msgstr "Uurroosterlijn"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: view:analytic.user.funct.grid:0
|
||||
msgid "User's Product for this Analytic Account"
|
||||
msgstr ""
|
||||
msgstr "Product van gebruiker voor deze analytische rekening"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The Object name must start with x_ and not contain any special character !"
|
||||
#~ msgstr ""
|
||||
#~ "De objectnaam moet beginnen met x_ en mag geen speciale karakters bevatten !"
|
||||
|
||||
@@ -363,7 +363,7 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
})
|
||||
raise osv.except_osv(error_type, error_msg)
|
||||
|
||||
def anonymize_database(self,cr, uid, ids, context=None):
|
||||
def anonymize_database(self, cr, uid, ids, context=None):
|
||||
"""Sets the 'anonymized' state to defined fields"""
|
||||
|
||||
# create a new history record:
|
||||
@@ -498,7 +498,7 @@ class ir_model_fields_anonymize_wizard(osv.osv_memory):
|
||||
'target':'new',
|
||||
}
|
||||
|
||||
def reverse_anonymize_database(self,cr, uid, ids, context=None):
|
||||
def reverse_anonymize_database(self, cr, uid, ids, context=None):
|
||||
"""Set the 'clear' state to defined fields"""
|
||||
|
||||
ir_model_fields_anonymization_model = self.pool.get('ir.model.fields.anonymization')
|
||||
|
||||
@@ -202,7 +202,7 @@ class audittrail_objects_proxy(object_proxy):
|
||||
res = value
|
||||
return res
|
||||
|
||||
def create_log_line(self, cr, uid, log_id, model, lines=[]):
|
||||
def create_log_line(self, cr, uid, log_id, model, lines=None):
|
||||
"""
|
||||
Creates lines for changed fields with its old and new values
|
||||
|
||||
@@ -211,6 +211,8 @@ class audittrail_objects_proxy(object_proxy):
|
||||
@param model: Object which values are being changed
|
||||
@param lines: List of values for line is to be created
|
||||
"""
|
||||
if lines is None:
|
||||
lines = []
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
obj_pool = pool.get(model.model)
|
||||
model_pool = pool.get('ir.model')
|
||||
@@ -349,9 +351,9 @@ class audittrail_objects_proxy(object_proxy):
|
||||
data[(model.id, resource_id)] = {'text':values_text, 'value': values}
|
||||
return data
|
||||
|
||||
def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values, field_list=[]):
|
||||
def prepare_audittrail_log_line(self, cr, uid, pool, model, resource_id, method, old_values, new_values, field_list=None):
|
||||
"""
|
||||
This function compares the old data (i.e before the method was executed) and the new data
|
||||
This function compares the old data (i.e before the method was executed) and the new data
|
||||
(after the method was executed) and returns a structure with all the needed information to
|
||||
log those differences.
|
||||
|
||||
@@ -375,9 +377,11 @@ class audittrail_objects_proxy(object_proxy):
|
||||
(model.id, resource_id): []
|
||||
}
|
||||
|
||||
The reason why the structure returned is build as above is because when modifying an existing
|
||||
The reason why the structure returned is build as above is because when modifying an existing
|
||||
record, we may have to log a change done in a x2many field of that object
|
||||
"""
|
||||
if field_list is None:
|
||||
field_list = []
|
||||
key = (model.id, resource_id)
|
||||
lines = {
|
||||
key: []
|
||||
@@ -416,7 +420,7 @@ class audittrail_objects_proxy(object_proxy):
|
||||
lines[key].append(data)
|
||||
return lines
|
||||
|
||||
def process_data(self, cr, uid, pool, res_ids, model, method, old_values={}, new_values={}, field_list=[]):
|
||||
def process_data(self, cr, uid, pool, res_ids, model, method, old_values=None, new_values=None, field_list=None):
|
||||
"""
|
||||
This function processes and iterates recursively to log the difference between the old
|
||||
data (i.e before the method was executed) and the new data and creates audittrail log
|
||||
@@ -435,6 +439,8 @@ class audittrail_objects_proxy(object_proxy):
|
||||
on specific fields only.
|
||||
:return: True
|
||||
"""
|
||||
if field_list is None:
|
||||
field_list = []
|
||||
# loop on all the given ids
|
||||
for res_id in res_ids:
|
||||
# compare old and new values and get audittrail log lines accordingly
|
||||
|
||||
@@ -34,11 +34,15 @@ Allow users to login through Google OAuth2.
|
||||
'depends': ['base', 'web', 'base_setup'],
|
||||
'data': [
|
||||
'auth_oauth_data.xml',
|
||||
'auth_oauth_data.yml',
|
||||
'auth_oauth_view.xml',
|
||||
'security/ir.model.access.csv'
|
||||
],
|
||||
'js': ['static/src/js/auth_oauth.js'],
|
||||
'css': ['static/lib/zocial/css/zocial.css'],
|
||||
'css': [
|
||||
'static/lib/zocial/css/zocial.css',
|
||||
'static/src/css/auth_oauth.css',
|
||||
],
|
||||
'qweb': ['static/src/xml/auth_oauth.xml'],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="provider_openerp" model="auth.oauth.provider">
|
||||
<field name="name">OpenERP Accounts</field>
|
||||
<field name="auth_endpoint">https://accounts.openerp.com/oauth2/auth</field>
|
||||
<field name="scope">userinfo</field>
|
||||
<field name="validation_endpoint">https://accounts.openerp.com/oauth2/tokeninfo</field>
|
||||
<field name="data_endpoint"></field>
|
||||
<field name="css_class">zocial openerp</field>
|
||||
<field name="body">Sign in with OpenERP account</field>
|
||||
</record>
|
||||
<record id="provider_facebook" model="auth.oauth.provider">
|
||||
<field name="name">Facebook Graph</field>
|
||||
<field name="auth_endpoint">https://www.facebook.com/dialog/oauth</field>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
-
|
||||
Use database uuid as client_id for OpenERP oauth provider
|
||||
-
|
||||
!python {model: ir.config_parameter}: |
|
||||
oauth = self.pool.get('auth.oauth.provider')
|
||||
oauth.write(cr, uid, [ref('provider_openerp')], {'client_id': self.get_param(cr, uid, 'database.uuid')})
|
||||
@@ -16,10 +16,13 @@ class OAuthController(openerpweb.Controller):
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def list_providers(self, req, dbname):
|
||||
registry = openerp.modules.registry.RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
providers = registry.get('auth.oauth.provider')
|
||||
l = providers.read(cr, SUPERUSER_ID, providers.search(cr, SUPERUSER_ID, [('enabled','=',True)]))
|
||||
try:
|
||||
registry = openerp.modules.registry.RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
providers = registry.get('auth.oauth.provider')
|
||||
l = providers.read(cr, SUPERUSER_ID, providers.search(cr, SUPERUSER_ID, [('enabled','=',True)]))
|
||||
except Exception:
|
||||
l = []
|
||||
return l
|
||||
|
||||
@openerpweb.httprequest
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
import urllib
|
||||
import urlparse
|
||||
import urllib2
|
||||
import simplejson
|
||||
|
||||
@@ -20,8 +21,11 @@ class res_users(osv.Model):
|
||||
}
|
||||
|
||||
def auth_oauth_rpc(self, cr, uid, endpoint, access_token, context=None):
|
||||
params = urllib.urlencode({'access_token':access_token})
|
||||
url = endpoint + '?' + params
|
||||
params = urllib.urlencode({ 'access_token': access_token })
|
||||
if urlparse.urlparse(endpoint)[4]:
|
||||
url = endpoint + '&' + params
|
||||
else:
|
||||
url = endpoint + '?' + params
|
||||
f = urllib2.urlopen(url)
|
||||
response = f.read()
|
||||
return simplejson.loads(response)
|
||||
@@ -38,26 +42,32 @@ class res_users(osv.Model):
|
||||
validation = self.auth_oauth_rpc(cr, uid, p.validation_endpoint, access_token)
|
||||
if validation.get("error"):
|
||||
raise openerp.exceptions.AccessDenied
|
||||
login = validation['email']
|
||||
if p.data_endpoint:
|
||||
data = self.auth_oauth_rpc(cr, uid, p.data_endpoint, access_token)
|
||||
validation.update(data)
|
||||
# required
|
||||
oauth_uid = validation['user_id']
|
||||
name = self.auth_oauth_rpc(cr, uid, p.data_endpoint, access_token)['name']
|
||||
|
||||
credentials = (cr.dbname, login, access_token)
|
||||
if not oauth_uid:
|
||||
raise openerp.exceptions.AccessDenied
|
||||
email = validation.get('email', 'provider_%d_user_%d' % (p.id, oauth_uid))
|
||||
# optional
|
||||
name = validation.get('name', email)
|
||||
res = self.search(cr, uid, [("oauth_uid", "=", oauth_uid)])
|
||||
if res:
|
||||
self.write(cr, uid, res[0], {'oauth_access_token':access_token})
|
||||
self.write(cr, uid, res[0], { 'oauth_access_token': access_token })
|
||||
else:
|
||||
# New user
|
||||
new_user = {
|
||||
'name': name,
|
||||
'login': login,
|
||||
'user_email': login,
|
||||
'oauth_provider_id': 1,
|
||||
'login': email,
|
||||
'user_email': email,
|
||||
'oauth_provider_id': p.id,
|
||||
'oauth_uid': oauth_uid,
|
||||
'oauth_access_token': access_token,
|
||||
'active': True,
|
||||
}
|
||||
self.auth_signup_create(cr, uid, new_user)
|
||||
credentials = (cr.dbname, email, access_token)
|
||||
return credentials
|
||||
|
||||
def check_credentials(self, cr, uid, password):
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
.openerp .oe_application .zocial {
|
||||
font: white;
|
||||
}
|
||||
|
||||
.openerp .zocial.openerp:before {
|
||||
content: "\E02E";
|
||||
font-style: italic;
|
||||
text-shadow: 0 1px 1px black;
|
||||
}
|
||||
|
||||
.openerp a.zocial.openerp {
|
||||
float: right;
|
||||
border: 1px solid #222222;
|
||||
color: white;
|
||||
margin: 0;
|
||||
background-color: #b92020;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(#b92020), to(#600606));
|
||||
background-image: -webkit-linear-gradient(top, #b92020, #600606);
|
||||
background-image: -moz-linear-gradient(top, #b92020, #600606);
|
||||
background-image: -ms-linear-gradient(top, #b92020, #600606);
|
||||
background-image: -o-linear-gradient(top, #b92020, #600606);
|
||||
background-image: linear-gradient(to bottom, #b92020, #600606);
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset;
|
||||
text-shadow: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.openerp .oe_login .oe_oauth_provider_login_button {
|
||||
margin-top: 4px;
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
openerp.auth_oauth = function(instance) {
|
||||
var QWeb = instance.web.qweb;
|
||||
|
||||
instance.web.Login = instance.web.Login.extend({
|
||||
instance.web.Login.include({
|
||||
start: function(parent, params) {
|
||||
var self = this;
|
||||
var d = this._super.apply(this, arguments);
|
||||
this.$el.on('click', 'a.zocial', this.on_oauth_sign_in);
|
||||
this.oauth_providers = [];
|
||||
@@ -11,7 +12,13 @@ openerp.auth_oauth = function(instance) {
|
||||
} else if(this.params.oauth_error === 2) {
|
||||
this.do_warn("Authentication error","");
|
||||
}
|
||||
return d.then(this.do_oauth_load);
|
||||
return d.then(this.do_oauth_load).fail(function() {
|
||||
self.do_oauth_load([]);
|
||||
});
|
||||
},
|
||||
on_db_loaded: function(result) {
|
||||
this._super.apply(this, arguments);
|
||||
this.$("form [name=db]").change(this.do_oauth_load);
|
||||
},
|
||||
do_oauth_load: function() {
|
||||
var db = this.$("form [name=db]").val();
|
||||
@@ -21,6 +28,7 @@ openerp.auth_oauth = function(instance) {
|
||||
},
|
||||
on_oauth_loaded: function(result) {
|
||||
this.oauth_providers = result;
|
||||
this.$('.oe_oauth_provider_login_button').remove();
|
||||
var buttons = QWeb.render("auth_oauth.Login.button",{"widget":this});
|
||||
this.$(".oe_login_pane form ul").after(buttons);
|
||||
},
|
||||
@@ -33,7 +41,7 @@ openerp.auth_oauth = function(instance) {
|
||||
var state_object = {
|
||||
d: dbname,
|
||||
p: p.id
|
||||
}
|
||||
};
|
||||
var state = JSON.stringify(state_object);
|
||||
var params = {
|
||||
response_type: 'token',
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="auth_oauth.Login.button">
|
||||
<t t-foreach="widget.oauth_providers" t-as="p">
|
||||
<a href="#" t-att-class="p.css_class" t-att-data-index="p_index"><t t-esc="p.body"/></a>
|
||||
<br/>
|
||||
<a href="#" t-attf-class="oe_oauth_provider_login_button #{p.css_class}" t-att-data-index="p_index"><t t-esc="p.body"/></a>
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -1 +1,23 @@
|
||||
import auth_reset_password
|
||||
# -*- 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 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import controllers
|
||||
import res_users
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
# -*- 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 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Reset Password',
|
||||
'description': """
|
||||
@@ -9,9 +30,11 @@ Allow users to reset their password from the login page.
|
||||
'category': 'Authentication',
|
||||
'website': 'http://www.openerp.com',
|
||||
'installable': True,
|
||||
'depends': ['auth_anonymous', 'email_template'],
|
||||
'data': ['auth_reset_password.xml'],
|
||||
'depends': ['auth_signup', 'email_template'],
|
||||
'data': [
|
||||
'auth_reset_password.xml',
|
||||
'res_users_view.xml',
|
||||
],
|
||||
'js': ['static/src/js/reset_password.js'],
|
||||
'css': ['static/src/css/reset_password.css'],
|
||||
'qweb': ['static/src/xml/reset_password.xml'],
|
||||
}
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import simplejson
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
from openerp.tools import config
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
TWENTY_FOUR_HOURS = 24 * 60 * 60
|
||||
|
||||
def message_sign(data, secret):
|
||||
src = simplejson.dumps([data, secret], indent=None, separators=(',', ':'), sort_keys=True)
|
||||
sign = hashlib.sha1(src).hexdigest()
|
||||
msg = simplejson.dumps([data, sign], indent=None, separators=(',', ':'), sort_keys=True)
|
||||
# pad message to avoid '='
|
||||
pad = (3 - len(msg) % 3) % 3
|
||||
msg = msg + " " * pad
|
||||
msg = base64.urlsafe_b64encode(msg)
|
||||
return msg, sign
|
||||
|
||||
def message_check(msg, secret):
|
||||
msg = base64.urlsafe_b64decode(msg)
|
||||
l = simplejson.loads(msg)
|
||||
msg_data = l[0]
|
||||
msg_sign = l[1]
|
||||
tmp, sign = message_sign(msg_data, secret)
|
||||
if msg_sign == sign:
|
||||
return msg_data
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def _auth_reset_password_secret(self, cr, uid, context=None):
|
||||
uuid = self.pool.get('ir.config_parameter').get_param(cr, uid, 'database.uuid')
|
||||
res = {
|
||||
'dbname': cr.dbname,
|
||||
'uuid': uuid,
|
||||
'admin_passwd': config['admin_passwd']
|
||||
}
|
||||
return res
|
||||
|
||||
def _auth_reset_password_host(self, cr, uid, context=None):
|
||||
return self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', '')
|
||||
|
||||
def _auth_reset_password_link(self, cr, uid, ids, context=None):
|
||||
assert len(ids) == 1
|
||||
host = self._auth_reset_password_host(cr, uid, context)
|
||||
secret = self._auth_reset_password_secret(cr, uid, context)
|
||||
msg_src = {
|
||||
'time': time.time(),
|
||||
'uid': ids[0],
|
||||
}
|
||||
msg, sign = message_sign(msg_src, secret)
|
||||
link = urlparse.urljoin(host, '/login?db=%s&login=anonymous&key=anonymous#action=reset_password&token=%s' % (cr.dbname, msg))
|
||||
return link
|
||||
|
||||
def _auth_reset_password_check_token(self, cr, uid, token, context=None):
|
||||
secret = self._auth_reset_password_secret(cr, uid, context)
|
||||
data = message_check(token, secret)
|
||||
if data and (time.time() - data['time'] < TWENTY_FOUR_HOURS):
|
||||
return data
|
||||
return None
|
||||
|
||||
def _auth_reset_password_send_email(self, cr, uid, email_to, tpl_name, res_id, context=None):
|
||||
model, tpl_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'auth_reset_password', tpl_name)
|
||||
assert model == 'email.template'
|
||||
|
||||
msg_id = self.pool.get(model).send_mail(cr, uid, tpl_id, res_id, force_send=False, context=context)
|
||||
MailMessage = self.pool.get('mail.message')
|
||||
MailMessage.write(cr, uid, [msg_id], {'email_to': email_to}, context=context)
|
||||
MailMessage.send(cr, uid, [msg_id], context=context)
|
||||
|
||||
def send_reset_password_request(self, cr, uid, email, context=None):
|
||||
# TODO reseting a password knowing only an email is not good enough (email can be shared between multiple logins).
|
||||
ids = self.pool.get('res.users').search(cr, SUPERUSER_ID, [('user_email', '=', email)], context=context)
|
||||
if ids:
|
||||
self._auth_reset_password_send_email(cr, SUPERUSER_ID, email, 'reset_password_email', ids[0], context=context)
|
||||
return True
|
||||
#else:
|
||||
# _m, company_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'main_company')
|
||||
# self._auth_reset_password_send_email(cr, uid, email, 'email_no_user', company_id, context=context)
|
||||
return False
|
||||
|
||||
class auth_reset_password(osv.TransientModel):
|
||||
_name = 'auth.reset_password'
|
||||
_rec_name = 'password'
|
||||
_columns = {
|
||||
'password': fields.char('Password', size=64),
|
||||
'password_confirmation': fields.char('Confirm Password', size=64),
|
||||
'token': fields.char('Token', size=128),
|
||||
'state': fields.selection([(x, x) for x in 'draft done missmatch error'.split()], required=True),
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
pw = values.get('password')
|
||||
if not pw or pw != values.get('password_confirmation'):
|
||||
raise osv.except_osv('Error', 'Passwords missmatch')
|
||||
|
||||
Users = self.pool.get('res.users')
|
||||
data = Users._auth_reset_password_check_token(cr, uid, values.get('token', ''))
|
||||
if data:
|
||||
Users.write(cr, SUPERUSER_ID, data['uid'], {'password': pw}, context=context)
|
||||
else:
|
||||
raise osv.except_osv('Error', 'Invalid token')
|
||||
|
||||
# Dont store password
|
||||
values = {'state': 'done'}
|
||||
return super(auth_reset_password, self).create(cr, uid, values, context)
|
||||
|
||||
def change(self, cr, uid, ids, context=None):
|
||||
return True
|
||||
|
||||
def onchange_pw(self, cr, uid, ids, password, password_confirmation, context=None):
|
||||
if password != password_confirmation:
|
||||
return {'value': {'state': 'missmatch'}}
|
||||
return {'value': {'state': 'draft'}}
|
||||
|
||||
def onchange_token(self, cr, uid, ids, token, context=None):
|
||||
Users = self.pool.get('res.users')
|
||||
if not Users._auth_reset_password_check_token(cr, uid, token, context=context):
|
||||
return {'value': {'state': 'error'}}
|
||||
return {}
|
||||
@@ -7,56 +7,15 @@
|
||||
<field name="name">Reset Password</field>
|
||||
<field name="model_id" ref="base.model_res_users"/>
|
||||
<field name="email_from"><![CDATA[${object.company_id.name} <${object.company_id.email}>]]></field>
|
||||
<field name="email_to" eval="False"><!--(set by reset_password module)--></field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="subject">Password reset</field>
|
||||
<field name="body_html"><![CDATA[
|
||||
<p>A password reset was requested the OpenERP account linked to this email on ${object._auth_reset_password_host()}</p>
|
||||
<p>A password reset was requested for the OpenERP account linked to this email.</p>
|
||||
|
||||
<p>You may change your password following this <a href="${object._auth_reset_password_link()}">link</a>,
|
||||
or by copy-pasting the following URL in your browser: ${object._auth_reset_password_link()}</p>
|
||||
<p>You may change your password following <a href="${object.signup_url}">this link</a>.</p>
|
||||
|
||||
<p>Note: If you did not ask for a password reset, you can safely ignore this email.</p>]]></field>
|
||||
</record>
|
||||
|
||||
<!-- TODO get own css -->
|
||||
<record id="reset_password_wizard_form_view" model="ir.ui.view">
|
||||
<field name="name">auth.reset_password.form</field>
|
||||
<field name="model">auth.reset_password</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Reset Password" version="7.0">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="token" on_change="onchange_token(token)" invisible="1"/>
|
||||
<group colspan="4" states="draft,missmatch">
|
||||
<field name="password" required='1' on_change="onchange_pw(password,password_confirmation)"/>
|
||||
<field name="password_confirmation" required='1' on_change="onchange_pw(password,password_confirmation)"/>
|
||||
<group colspan="4" states="missmatch">
|
||||
<div>Passwords missmatch</div>
|
||||
</group>
|
||||
<group colspan="2" col="1">
|
||||
<button string="Change Password" name="change" icon="gtk-dialog-authentication" attrs="{'readonly': [('state', '=', 'missmatch')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group colspan="4" states="error" col="1">
|
||||
<div>Invalid or expired token</div>
|
||||
<button special="cancel" string="Close"/>
|
||||
</group>
|
||||
<group colspan="4" states="done" col="1">
|
||||
<div>Password changed. We sent you an email confirming the password change.</div>
|
||||
<button special="cancel" string="Close"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_reset" model="ir.actions.act_window">
|
||||
<field name="name">Reset Password</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">auth.reset_password</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+6
-5
@@ -2,22 +2,23 @@
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# 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 Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
# 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.
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import main
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,52 @@
|
||||
# -*- 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 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.modules.registry import RegistryManager
|
||||
import openerp.addons.web.common.http as openerpweb
|
||||
|
||||
import werkzeug
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class Controller(openerpweb.Controller):
|
||||
_cp_path = '/auth_reset_password'
|
||||
|
||||
@openerpweb.httprequest
|
||||
def reset_password(self, req, dbname, login):
|
||||
""" retrieve user, and perform reset password """
|
||||
url = '/'
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
try:
|
||||
res_users = registry.get('res.users')
|
||||
res_users.reset_password(cr, SUPERUSER_ID, login)
|
||||
cr.commit()
|
||||
message = 'An email has been sent with credentials to reset your password'
|
||||
except Exception as e:
|
||||
# signup error
|
||||
_logger.exception('error when resetting password')
|
||||
message = e.message
|
||||
url = "/#action=login&error_message=%s" % werkzeug.urls.url_quote(message)
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -0,0 +1,59 @@
|
||||
# -*- 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 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
def now(**kwargs):
|
||||
dt = datetime.now() + timedelta(**kwargs)
|
||||
return dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def reset_password(self, cr, uid, login, context=None):
|
||||
""" retrieve the user corresponding to login (login or email),
|
||||
and reset their password
|
||||
"""
|
||||
user_ids = self.search(cr, uid, [('login', '=', login)], context=context)
|
||||
if not user_ids:
|
||||
user_ids = self.search(cr, uid, [('email', '=', login)], context=context)
|
||||
if len(user_ids) != 1:
|
||||
raise Exception('Reset password: invalid username or email')
|
||||
return self.action_reset_password(cr, uid, user_ids, context=context)
|
||||
|
||||
def action_reset_password(self, cr, uid, ids, context=None):
|
||||
""" create signup token for each user, and send their signup url by email """
|
||||
# prepare reset password signup
|
||||
res_partner = self.pool.get('res.partner')
|
||||
partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context)]
|
||||
res_partner.signup_prepare(cr, uid, partner_ids, expiration=now(days=+1), context=context)
|
||||
|
||||
# send email to users with their signup url
|
||||
template = self.pool.get('ir.model.data').get_object(cr, uid, 'auth_reset_password', 'reset_password_email')
|
||||
assert template._name == 'email.template'
|
||||
for user in self.browse(cr, uid, ids, context):
|
||||
self.pool.get('email.template').send_mail(cr, uid, template.id, user.id, context=context)
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="res_users_form_view" model="ir.ui.view">
|
||||
<field name="name">user.form.reset_password</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet/*[1]" position="before">
|
||||
<div class="oe_right oe_button_box">
|
||||
<button string="Reset Password" type="object" name="action_reset_password"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,12 +0,0 @@
|
||||
.openerp .oe_login .oe_login_pane {
|
||||
height: 152px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_pane ul.oe_login_switch a {
|
||||
color: #eeeeee;
|
||||
margin: 0 8px;
|
||||
}
|
||||
.openerp .oe_login .oe_login_pane ul.oe_login_switch a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +1,30 @@
|
||||
openerp.auth_reset_password = function(instance) {
|
||||
var _t = instance.web._t;
|
||||
|
||||
instance.web.Login.include({
|
||||
start: function() {
|
||||
var $e = this.$el;
|
||||
$e.find('a.oe_login_switch').click(function() {
|
||||
$e.find('ul.oe_login_switch').toggle();
|
||||
var $m = $e.find('form input[name=is_reset_pw]');
|
||||
$m.attr('checked', !$m.is(':checked'));
|
||||
});
|
||||
this.$('a.oe_reset_password').click(this.do_reset_password);
|
||||
return this._super();
|
||||
},
|
||||
on_submit: function(ev) {
|
||||
if(ev) {
|
||||
do_reset_password: function(ev) {
|
||||
if (ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
var $e = this.$el;
|
||||
var db = $e.find("form [name=db]").val();
|
||||
var db = this.$("form [name=db]").val();
|
||||
var login = this.$("form input[name=login]").val();
|
||||
if (!db) {
|
||||
this.do_warn(_t("Login"), _t("No database selected !"));
|
||||
this.do_warn("Login", "No database selected !");
|
||||
return false;
|
||||
} else if (!login) {
|
||||
this.do_warn("Login", "Please enter a username or email address.")
|
||||
return false;
|
||||
}
|
||||
var $m = $e.find('form input[name=is_reset_pw]');
|
||||
if ($m.is(':checked')) {
|
||||
var email = $e.find('form input[name=email]').val();
|
||||
return this.do_reset_password(db, email);
|
||||
} else {
|
||||
return this._super(ev);
|
||||
}
|
||||
},
|
||||
do_reset_password: function(db, email) {
|
||||
var self = this;
|
||||
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
|
||||
self.do_notify(_t('Reset Password'), _.str.sprintf(_t('We have sent an email to %s with further instructions'), email), true);
|
||||
}, function(error, event) {
|
||||
// no traceback please
|
||||
event.preventDefault();
|
||||
});
|
||||
}).fail(function(error, event) {
|
||||
// cannot log as anonymous or reset_password not installed
|
||||
self.do_warn(_t('Reset Password'), _.str.sprintf(_t('Reset Password functionnality is not available for database %s'), db), true);
|
||||
});
|
||||
var params = {
|
||||
dbname : db,
|
||||
login: login,
|
||||
};
|
||||
var url = "/auth_reset_password/reset_password?" + $.param(params);
|
||||
window.location = url;
|
||||
}
|
||||
});
|
||||
|
||||
instance.reset_password = {};
|
||||
instance.reset_password.ResetPassword = instance.web.Widget.extend({
|
||||
init: function(parent, params) {
|
||||
this._super(parent);
|
||||
this.token = (params && params.token) || false;
|
||||
},
|
||||
start: function() {
|
||||
this.do_action({
|
||||
name: 'Reset Password',
|
||||
type: 'ir.actions.act_window',
|
||||
context: {default_token: this.token},
|
||||
res_model: 'auth.reset_password',
|
||||
target: 'new',
|
||||
views: [[false, 'form']]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
instance.web.client_actions.add("reset_password", "instance.reset_password.ResetPassword");
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- vim:fdl=1:
|
||||
-->
|
||||
<!-- vim:fdl=1: -->
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-extend="Login">
|
||||
<t t-jquery="form ul:first">
|
||||
// addClass does not work :(
|
||||
this.attr('class', (this.attr('class') || '') + ' oe_login_switch');
|
||||
</t>
|
||||
<t t-jquery="form ul:first li:last" t-operation="after">
|
||||
<li>
|
||||
<a class="oe_login_switch" href="#">Forgot your password?</a>
|
||||
</li>
|
||||
</t>
|
||||
<t t-jquery="form ul:first" t-operation="after">
|
||||
<ul class="oe_login_switch" style="display:none;">
|
||||
<li style="display:none;"><input type="checkbox" name="is_reset_pw"/></li>
|
||||
<li>Email</li>
|
||||
<li><input type="email" name="email"/></li>
|
||||
<li><button name="submit">Reset Password</button></li>
|
||||
<li><a class="oe_login_switch" href="#">< Back</a></li>
|
||||
</ul>
|
||||
<li><a class="oe_reset_password" href="#">Reset password</a></li>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -34,7 +34,9 @@ Allow users to sign up.
|
||||
'data': [
|
||||
'auth_signup_data.xml',
|
||||
'res_config.xml',
|
||||
'res_users_view.xml',
|
||||
],
|
||||
'js': ['static/src/js/auth_signup.js'],
|
||||
'css' : ['static/src/css/base.css'],
|
||||
'qweb': ['static/src/xml/auth_signup.xml'],
|
||||
}
|
||||
|
||||
@@ -1,35 +1,63 @@
|
||||
import logging
|
||||
|
||||
import werkzeug.urls
|
||||
# -*- 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 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.modules.registry import RegistryManager
|
||||
from openerp.addons.web.controllers.main import login_and_redirect
|
||||
import openerp.addons.web.common.http as openerpweb
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
import werkzeug
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class OpenIDController(openerpweb.Controller):
|
||||
class Controller(openerpweb.Controller):
|
||||
_cp_path = '/auth_signup'
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def retrieve(self, req, dbname, token):
|
||||
""" retrieve the user info (name, login or email) corresponding to a signup token """
|
||||
registry = RegistryManager.get(dbname)
|
||||
user_info = None
|
||||
with registry.cursor() as cr:
|
||||
res_partner = registry.get('res.partner')
|
||||
user_info = res_partner.signup_retrieve_info(cr, SUPERUSER_ID, token)
|
||||
return user_info
|
||||
|
||||
@openerpweb.httprequest
|
||||
def signup(self, req, dbname, name, login, password):
|
||||
def signup(self, req, dbname, token, name, login, password):
|
||||
""" sign up a user (new or existing), and log it in """
|
||||
url = '/'
|
||||
registry = RegistryManager.get(dbname)
|
||||
with registry.cursor() as cr:
|
||||
try:
|
||||
Users = registry.get('res.users')
|
||||
credentials = Users.auth_signup(cr, SUPERUSER_ID, name, login, password)
|
||||
res_users = registry.get('res.users')
|
||||
values = {'name': name, 'login': login, 'password': password}
|
||||
credentials = res_users.signup(cr, SUPERUSER_ID, values, token)
|
||||
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:
|
||||
except Exception as e:
|
||||
# signup error
|
||||
_logger.exception('error when signup')
|
||||
url = "/#action=auth_signup&error=UE" # Unexcpected Error
|
||||
url = "/#action=login&error_message=%s" % werkzeug.urls.url_quote(e.message)
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
||||
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -20,22 +20,27 @@
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
|
||||
class base_config_settings(osv.TransientModel):
|
||||
_inherit = 'base.config.settings'
|
||||
|
||||
_columns = {
|
||||
'auth_signup_uninvited': fields.boolean('Allow public users to sign up', help="If unchecked only invited users may sign up"),
|
||||
'auth_signup_uninvited': fields.boolean('Allow external 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_auth_signup_template_user_id(self, cr, uid, fields, context=None):
|
||||
icp = self.pool.get('ir.config_parameter')
|
||||
# we use safe_eval on the result, since the value of the parameter is a nonempty string
|
||||
return {
|
||||
'auth_signup_template_user_id': icp.get_param(cr, uid, 'auth_signup.template_user_id', 0) or False
|
||||
'auth_signup_uninvited': safe_eval(icp.get_param(cr, uid, 'auth_signup.allow_uninvited', 'False')),
|
||||
'auth_signup_template_user_id': safe_eval(icp.get_param(cr, uid, 'auth_signup.template_user_id', 'False')),
|
||||
}
|
||||
|
||||
def set_auth_signup_template_user_id(self, cr, uid, ids, context=None):
|
||||
config = self.browse(cr, uid, ids[0], context=context)
|
||||
icp = self.pool.get('ir.config_parameter')
|
||||
icp.set_param(cr, uid, 'auth_signup.template_user_id', config.auth_signup_template_user_id.id)
|
||||
# we store the repr of the values, since the value of the parameter is a required string
|
||||
icp.set_param(cr, uid, 'auth_signup.allow_uninvited', repr(config.auth_signup_uninvited))
|
||||
icp.set_param(cr, uid, 'auth_signup.template_user_id', repr(config.auth_signup_template_user_id.id))
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
</div>
|
||||
<div attrs="{'invisible':[('auth_signup_uninvited','=',False)]}">
|
||||
<label for="auth_signup_template_user_id"/>
|
||||
<field name="auth_signup_template_user_id" class="oe_inline" domain="['|',('active','=',0),('active','=',1)]"/>
|
||||
<field name="auth_signup_template_user_id" class="oe_inline"
|
||||
attrs="{'required': [('auth_signup_uninvited', '=', True)]}"
|
||||
domain="['|',('active','=',0),('active','=',1)]"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
|
||||
+197
-39
@@ -1,47 +1,205 @@
|
||||
# -*- 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 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 <http://www.gnu.org/licenses/>
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import openerp
|
||||
from openerp.osv import osv
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
|
||||
import time
|
||||
import random
|
||||
import urllib
|
||||
import urlparse
|
||||
|
||||
def random_token():
|
||||
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
|
||||
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
return ''.join(random.choice(chars) for i in xrange(20))
|
||||
|
||||
def now():
|
||||
return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
|
||||
class res_partner(osv.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
def _get_signup_valid(self, cr, uid, ids, name, arg, context=None):
|
||||
dt = now()
|
||||
res = {}
|
||||
for partner in self.browse(cr, uid, ids, context):
|
||||
res[partner.id] = bool(partner.signup_token) and \
|
||||
(not partner.signup_expiration or dt <= partner.signup_expiration)
|
||||
return res
|
||||
|
||||
def _get_signup_url(self, cr, uid, ids, name, arg, context=None):
|
||||
""" determine a signup url for a given partner """
|
||||
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
||||
|
||||
# if required, make sure that every partner without user has a valid signup token
|
||||
if context and context.get('signup_valid'):
|
||||
unsigned_ids = [p.id for p in self.browse(cr, uid, ids, context) if not p.user_ids]
|
||||
self.signup_prepare(cr, uid, unsigned_ids, context=context)
|
||||
|
||||
res = dict.fromkeys(ids, False)
|
||||
for partner in self.browse(cr, uid, ids, context):
|
||||
if partner.signup_token:
|
||||
params = (urllib.quote(cr.dbname), urllib.quote(partner.signup_token))
|
||||
res[partner.id] = urlparse.urljoin(base_url, "#action=login&db=%s&token=%s" % params)
|
||||
elif partner.user_ids:
|
||||
user = partner.user_ids[0]
|
||||
params = (urllib.quote(cr.dbname), urllib.quote(user.login))
|
||||
res[partner.id] = urlparse.urljoin(base_url, "#action=login&db=%s&login=%s" % params)
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'signup_token': fields.char(size=24, string='Signup Token'),
|
||||
'signup_expiration': fields.datetime(string='Signup Expiration'),
|
||||
'signup_valid': fields.function(_get_signup_valid, type='boolean', string='Signup Token is Valid'),
|
||||
'signup_url': fields.function(_get_signup_url, type='char', string='Signup URL'),
|
||||
}
|
||||
|
||||
def action_signup_prepare(self, cr, uid, ids, context=None):
|
||||
return self.signup_prepare(cr, uid, ids, context=context)
|
||||
|
||||
def signup_prepare(self, cr, uid, ids, expiration=False, context=None):
|
||||
""" generate a new token for the partners with the given validity, if necessary
|
||||
:param expiration: the expiration datetime of the token (string, optional)
|
||||
"""
|
||||
for partner in self.browse(cr, uid, ids, context):
|
||||
if expiration or not partner.signup_valid:
|
||||
token = random_token()
|
||||
while self._signup_retrieve_partner(cr, uid, token, context=context):
|
||||
token = random_token()
|
||||
partner.write({'signup_token': token, 'signup_expiration': expiration})
|
||||
return True
|
||||
|
||||
def _signup_retrieve_partner(self, cr, uid, token,
|
||||
check_validity=False, raise_exception=False, context=None):
|
||||
""" find the partner corresponding to a token, and possibly check its validity
|
||||
:param token: the token to resolve
|
||||
:param check_validity: if True, also check validity
|
||||
:param raise_exception: if True, raise exception instead of returning False
|
||||
:return: partner (browse record) or False (if raise_exception is False)
|
||||
"""
|
||||
partner_ids = self.search(cr, uid, [('signup_token', '=', token)], context=context)
|
||||
if not partner_ids:
|
||||
if raise_exception:
|
||||
raise Exception("Signup token '%s' is not valid" % token)
|
||||
return False
|
||||
partner = self.browse(cr, uid, partner_ids[0], context)
|
||||
if check_validity and not partner.signup_valid:
|
||||
if raise_exception:
|
||||
raise Exception("Signup token '%s' is no longer valid" % token)
|
||||
return False
|
||||
return partner
|
||||
|
||||
def signup_retrieve_info(self, cr, uid, token, context=None):
|
||||
""" retrieve the user info about the token
|
||||
:return: a dictionary with the user information:
|
||||
- 'db': the name of the database
|
||||
- 'token': the token, if token is valid
|
||||
- 'name': the name of the partner, if token is valid
|
||||
- 'login': the user login, if the user already exists
|
||||
- 'email': the partner email, if the user does not exist
|
||||
"""
|
||||
partner = self._signup_retrieve_partner(cr, uid, token, raise_exception=True, context=None)
|
||||
res = {'db': cr.dbname}
|
||||
if partner.signup_valid:
|
||||
res['token'] = token
|
||||
res['name'] = partner.name
|
||||
if partner.user_ids:
|
||||
res['login'] = partner.user_ids[0].login
|
||||
else:
|
||||
res['email'] = partner.email or ''
|
||||
return res
|
||||
|
||||
|
||||
|
||||
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, SUPERUSER_ID, user_template_id, new_user, context=context)
|
||||
else:
|
||||
self.pool.get('res.users').create(cr, SUPERUSER_ID, new_user, context=context)
|
||||
def _get_state(self, cr, uid, ids, name, arg, context=None):
|
||||
return dict((user.id, 'new' if not user.login_date else 'reset' if user.signup_token else 'active')
|
||||
for user in self.browse(cr, uid, ids, 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
|
||||
_columns = {
|
||||
'state': fields.function(_get_state, string='State', type='selection',
|
||||
selection=[('new', 'New'), ('active', 'Active'), ('reset', 'Resetting Password')]),
|
||||
}
|
||||
|
||||
#
|
||||
def signup(self, cr, uid, values, token=None, context=None):
|
||||
""" signup a user, to either:
|
||||
- create a new user (no token), or
|
||||
- create a user for a partner (with token, but no user for partner), or
|
||||
- change the password of a user (with token, and existing user).
|
||||
:param values: a dictionary with field values
|
||||
:param token: signup token (optional)
|
||||
:return: (dbname, login, password) for the signed up user
|
||||
"""
|
||||
assert values.get('login') and values.get('password')
|
||||
result = (cr.dbname, values['login'], values['password'])
|
||||
|
||||
if token:
|
||||
# signup with a token: find the corresponding partner id
|
||||
res_partner = self.pool.get('res.partner')
|
||||
partner = res_partner._signup_retrieve_partner(cr, uid, token,
|
||||
check_validity=True, raise_exception=True, context=None)
|
||||
# invalidate signup token
|
||||
partner.write({'signup_token': False, 'signup_expiration': False})
|
||||
if partner.user_ids:
|
||||
# user exists, modify its password
|
||||
partner.user_ids[0].write({'password': values['password']})
|
||||
else:
|
||||
# user does not exist: sign up invited user
|
||||
self._signup_create_user(cr, uid, {
|
||||
'name': partner.name,
|
||||
'login': values['login'],
|
||||
'password': values['password'],
|
||||
'email': values['login'],
|
||||
'partner_id': partner.id,
|
||||
}, context=context)
|
||||
return result
|
||||
|
||||
# sign up an external user
|
||||
assert values.get('name'), 'Signup: no name given for new user'
|
||||
self._signup_create_user(cr, uid, {
|
||||
'name': values['name'],
|
||||
'login': values['login'],
|
||||
'password': values['password'],
|
||||
'email': values['login'],
|
||||
}, context=context)
|
||||
return result
|
||||
|
||||
def _signup_create_user(self, cr, uid, values, context=None):
|
||||
""" create a new user from the template user """
|
||||
ir_config_parameter = self.pool.get('ir.config_parameter')
|
||||
template_user_id = safe_eval(ir_config_parameter.get_param(cr, uid, 'auth_signup.template_user_id', 'False'))
|
||||
assert template_user_id and self.exists(cr, uid, template_user_id, context=context), 'Signup: invalid template user'
|
||||
|
||||
# check that uninvited users may sign up
|
||||
if 'partner_id' not in values:
|
||||
if not safe_eval(ir_config_parameter.get_param(cr, uid, 'auth_signup.allow_uninvited', 'False')):
|
||||
raise Exception('Signup is not allowed for uninvited users')
|
||||
|
||||
# create a copy of the template user (attached to a specific partner_id if given)
|
||||
values['active'] = True
|
||||
return self.copy(cr, uid, template_user_id, values, context=context)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="res_users_form_view" model="ir.ui.view">
|
||||
<field name="name">user.form.state</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,3 @@
|
||||
base.css: base.sass
|
||||
sass --trace -t expanded base.sass base.css
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user