[MERGE] forward port of branch saas-2 up to revid 9092 dle@openerp.com-20140115165506-yuux9km39gbv7k4n
bzr revid: chs@openerp.com-20140115214454-dhl8xzr429co0j5d
This commit is contained in:
commit
91aaaec0a5
|
@ -1023,7 +1023,10 @@ class account_period(osv.osv):
|
||||||
if not result:
|
if not result:
|
||||||
result = self.search(cr, uid, args, context=context)
|
result = self.search(cr, uid, args, context=context)
|
||||||
if not result:
|
if not result:
|
||||||
raise osv.except_osv(_('Error!'), _('There is no period defined for this date: %s.\nPlease create one.')%dt)
|
model, action_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'account', 'action_account_fiscalyear')
|
||||||
|
msg = _('There is no period defined for this date: %s.\nPlease, go to Configuration/Periods and configure a fiscal year.') % dt
|
||||||
|
raise openerp.exceptions.RedirectWarning(msg, action_id, _('Go to the configuration panel'))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def action_draft(self, cr, uid, ids, *args):
|
def action_draft(self, cr, uid, ids, *args):
|
||||||
|
|
|
@ -849,18 +849,17 @@ class account_move_line(osv.osv):
|
||||||
(tuple(ids), ))
|
(tuple(ids), ))
|
||||||
r = cr.fetchall()
|
r = cr.fetchall()
|
||||||
#TODO: move this check to a constraint in the account_move_reconcile object
|
#TODO: move this check to a constraint in the account_move_reconcile object
|
||||||
|
if len(r) != 1:
|
||||||
|
raise osv.except_osv(_('Error'), _('Entries are not of the same account or already reconciled ! '))
|
||||||
if not unrec_lines:
|
if not unrec_lines:
|
||||||
raise osv.except_osv(_('Error!'), _('Entry is already reconciled.'))
|
raise osv.except_osv(_('Error!'), _('Entry is already reconciled.'))
|
||||||
account = account_obj.browse(cr, uid, account_id, context=context)
|
account = account_obj.browse(cr, uid, account_id, context=context)
|
||||||
|
if not account.reconcile:
|
||||||
|
raise osv.except_osv(_('Error'), _('The account is not defined to be reconciled !'))
|
||||||
if r[0][1] != None:
|
if r[0][1] != None:
|
||||||
raise osv.except_osv(_('Error!'), _('Some entries are already reconciled.'))
|
raise osv.except_osv(_('Error!'), _('Some entries are already reconciled.'))
|
||||||
|
|
||||||
if context.get('fy_closing'):
|
if (not currency_obj.is_zero(cr, uid, account.company_id.currency_id, writeoff)) or \
|
||||||
# We don't want to generate any write-off when being called from the
|
|
||||||
# wizard used to close a fiscal year (and it doesn't give us any
|
|
||||||
# writeoff_acc_id).
|
|
||||||
pass
|
|
||||||
elif (not currency_obj.is_zero(cr, uid, account.company_id.currency_id, writeoff)) or \
|
|
||||||
(account.currency_id and (not currency_obj.is_zero(cr, uid, account.currency_id, currency))):
|
(account.currency_id and (not currency_obj.is_zero(cr, uid, account.currency_id, currency))):
|
||||||
if not writeoff_acc_id:
|
if not writeoff_acc_id:
|
||||||
raise osv.except_osv(_('Warning!'), _('You have to provide an account for the write off/exchange difference entry.'))
|
raise osv.except_osv(_('Warning!'), _('You have to provide an account for the write off/exchange difference entry.'))
|
||||||
|
@ -1199,7 +1198,7 @@ class account_move_line(osv.osv):
|
||||||
break
|
break
|
||||||
# Automatically convert in the account's secondary currency if there is one and
|
# Automatically convert in the account's secondary currency if there is one and
|
||||||
# the provided values were not already multi-currency
|
# the provided values were not already multi-currency
|
||||||
if account.currency_id and (vals.get('amount_currency', False) is False) and account.currency_id.id != account.company_id.currency_id.id:
|
if account.currency_id and 'amount_currency' not in vals and account.currency_id.id != account.company_id.currency_id.id:
|
||||||
vals['currency_id'] = account.currency_id.id
|
vals['currency_id'] = account.currency_id.id
|
||||||
ctx = {}
|
ctx = {}
|
||||||
if 'date' in vals:
|
if 'date' in vals:
|
||||||
|
|
|
@ -224,14 +224,6 @@ class account_fiscalyear_close(osv.osv_memory):
|
||||||
query_2nd_part = ""
|
query_2nd_part = ""
|
||||||
query_2nd_part_args = []
|
query_2nd_part_args = []
|
||||||
for account in obj_acc_account.browse(cr, uid, account_ids, context={'fiscalyear': fy_id}):
|
for account in obj_acc_account.browse(cr, uid, account_ids, context={'fiscalyear': fy_id}):
|
||||||
balance_in_currency = 0.0
|
|
||||||
if account.currency_id:
|
|
||||||
cr.execute('SELECT sum(COALESCE(amount_currency,0.0)) as balance_in_currency FROM account_move_line ' \
|
|
||||||
'WHERE account_id = %s ' \
|
|
||||||
'AND ' + query_line + ' ' \
|
|
||||||
'AND currency_id = %s', (account.id, account.currency_id.id))
|
|
||||||
balance_in_currency = cr.dictfetchone()['balance_in_currency']
|
|
||||||
|
|
||||||
company_currency_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_id
|
company_currency_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_id
|
||||||
if not currency_obj.is_zero(cr, uid, company_currency_id, abs(account.balance)):
|
if not currency_obj.is_zero(cr, uid, company_currency_id, abs(account.balance)):
|
||||||
if query_2nd_part:
|
if query_2nd_part:
|
||||||
|
@ -246,7 +238,7 @@ class account_fiscalyear_close(osv.osv_memory):
|
||||||
period.id,
|
period.id,
|
||||||
account.id,
|
account.id,
|
||||||
account.currency_id and account.currency_id.id or None,
|
account.currency_id and account.currency_id.id or None,
|
||||||
balance_in_currency,
|
account.foreign_balance if account.currency_id else 0.0,
|
||||||
account.company_id.id,
|
account.company_id.id,
|
||||||
'draft')
|
'draft')
|
||||||
if query_2nd_part:
|
if query_2nd_part:
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
parent_id: account.cash
|
parent_id: account.cash
|
||||||
type: other
|
type: other
|
||||||
user_type: account.data_account_type_asset
|
user_type: account.data_account_type_asset
|
||||||
|
reconcile: True
|
||||||
-
|
-
|
||||||
Configure Creditor Account Payable.
|
Configure Creditor Account Payable.
|
||||||
-
|
-
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
parent_id: account.a_pay
|
parent_id: account.a_pay
|
||||||
type: other
|
type: other
|
||||||
user_type: account.data_account_type_payable
|
user_type: account.data_account_type_payable
|
||||||
|
reconcile: True
|
||||||
-
|
-
|
||||||
Configure Debtor Account Receivable.
|
Configure Debtor Account Receivable.
|
||||||
-
|
-
|
||||||
|
@ -61,6 +63,7 @@
|
||||||
parent_id: account.a_recv
|
parent_id: account.a_recv
|
||||||
type: other
|
type: other
|
||||||
user_type: account.data_account_type_receivable
|
user_type: account.data_account_type_receivable
|
||||||
|
reconcile: True
|
||||||
-
|
-
|
||||||
Configure Cost of Good sale Account.
|
Configure Cost of Good sale Account.
|
||||||
-
|
-
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
parent_id: account.cash
|
parent_id: account.cash
|
||||||
type: other
|
type: other
|
||||||
user_type: account.data_account_type_asset
|
user_type: account.data_account_type_asset
|
||||||
|
reconcile: True
|
||||||
-
|
-
|
||||||
Configure Creditor Account Payable.
|
Configure Creditor Account Payable.
|
||||||
-
|
-
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
parent_id: account.a_pay
|
parent_id: account.a_pay
|
||||||
type: other
|
type: other
|
||||||
user_type: account.data_account_type_payable
|
user_type: account.data_account_type_payable
|
||||||
|
reconcile: True
|
||||||
-
|
-
|
||||||
Configure Debtor Account Receivable.
|
Configure Debtor Account Receivable.
|
||||||
-
|
-
|
||||||
|
@ -61,6 +63,7 @@
|
||||||
parent_id: account.a_recv
|
parent_id: account.a_recv
|
||||||
type: other
|
type: other
|
||||||
user_type: account.data_account_type_receivable
|
user_type: account.data_account_type_receivable
|
||||||
|
reconcile: True
|
||||||
-
|
-
|
||||||
Configure Cost of Good sale Account.
|
Configure Cost of Good sale Account.
|
||||||
-
|
-
|
||||||
|
|
|
@ -217,7 +217,7 @@ class account_voucher(osv.osv):
|
||||||
if context.get('type', 'sale') in ('purchase', 'payment'):
|
if context.get('type', 'sale') in ('purchase', 'payment'):
|
||||||
nodes = doc.xpath("//field[@name='partner_id']")
|
nodes = doc.xpath("//field[@name='partner_id']")
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
node.set('context', "{'search_default_supplier': 1}")
|
node.set('context', "{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}")
|
||||||
if context.get('invoice_type','') in ('in_invoice', 'in_refund'):
|
if context.get('invoice_type','') in ('in_invoice', 'in_refund'):
|
||||||
node.set('string', _("Supplier"))
|
node.set('string', _("Supplier"))
|
||||||
res['arch'] = etree.tostring(doc)
|
res['arch'] = etree.tostring(doc)
|
||||||
|
@ -1329,7 +1329,7 @@ class account_voucher(osv.osv):
|
||||||
'date': voucher.date,
|
'date': voucher.date,
|
||||||
'credit': diff > 0 and diff or 0.0,
|
'credit': diff > 0 and diff or 0.0,
|
||||||
'debit': diff < 0 and -diff or 0.0,
|
'debit': diff < 0 and -diff or 0.0,
|
||||||
'amount_currency': company_currency <> current_currency and (sign * -1 * voucher.writeoff_amount) or False,
|
'amount_currency': company_currency <> current_currency and (sign * -1 * voucher.writeoff_amount) or 0.0,
|
||||||
'currency_id': company_currency <> current_currency and current_currency or False,
|
'currency_id': company_currency <> current_currency and current_currency or False,
|
||||||
'analytic_account_id': voucher.analytic_id and voucher.analytic_id.id or False,
|
'analytic_account_id': voucher.analytic_id and voucher.analytic_id.id or False,
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ class account_analytic_account(osv.osv):
|
||||||
'user_id': fields.many2one('res.users', 'Project Manager', track_visibility='onchange'),
|
'user_id': fields.many2one('res.users', 'Project Manager', track_visibility='onchange'),
|
||||||
'manager_id': fields.many2one('res.users', 'Account Manager', track_visibility='onchange'),
|
'manager_id': fields.many2one('res.users', 'Account Manager', track_visibility='onchange'),
|
||||||
'date_start': fields.date('Start Date'),
|
'date_start': fields.date('Start Date'),
|
||||||
'date': fields.date('End Date', select=True, track_visibility='onchange'),
|
'date': fields.date('Expiration Date', select=True, track_visibility='onchange'),
|
||||||
'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.
|
'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'),('pending','To Renew'),('close','Closed'),('cancelled', 'Cancelled')], 'Status', required=True, track_visibility='onchange'),
|
'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'),('pending','To Renew'),('close','Closed'),('cancelled', 'Cancelled')], 'Status', required=True, track_visibility='onchange'),
|
||||||
'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
|
'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
|
||||||
|
|
|
@ -1049,11 +1049,13 @@ class crm_lead(format_address, osv.osv):
|
||||||
def schedule_phonecall_send_note(self, cr, uid, ids, phonecall_id, action, context=None):
|
def schedule_phonecall_send_note(self, cr, uid, ids, phonecall_id, action, context=None):
|
||||||
phonecall = self.pool.get('crm.phonecall').browse(cr, uid, [phonecall_id], context=context)[0]
|
phonecall = self.pool.get('crm.phonecall').browse(cr, uid, [phonecall_id], context=context)[0]
|
||||||
if action == 'log':
|
if action == 'log':
|
||||||
prefix = 'Logged'
|
message = _('Logged a call for %(date)s. %(description)s')
|
||||||
else:
|
else:
|
||||||
prefix = 'Scheduled'
|
message = _('Scheduled a call for %(date)s. %(description)s')
|
||||||
suffix = ' %s' % phonecall.description
|
phonecall_date = datetime.strptime(phonecall.date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
message = _("%s a call for %s.%s") % (prefix, phonecall.date, suffix)
|
phonecall_usertime = fields.datetime.context_timestamp(cr, uid, phonecall_date, context=context).strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
html_time = "<time datetime='%s+00:00'>%s</time>" % (phonecall.date, phonecall_usertime)
|
||||||
|
message = message % dict(date=html_time, description=phonecall.description)
|
||||||
return self.message_post(cr, uid, ids, body=message, context=context)
|
return self.message_post(cr, uid, ids, body=message, context=context)
|
||||||
|
|
||||||
def log_meeting(self, cr, uid, ids, meeting_subject, meeting_date, duration, context=None):
|
def log_meeting(self, cr, uid, ids, meeting_subject, meeting_date, duration, context=None):
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
openerp.crm_partner_assign = function (instance) {
|
openerp.crm_partner_assign = function (instance) {
|
||||||
instance.crm_partner_assign = instance.crm_partner_assign || {};
|
instance.crm_partner_assign = instance.crm_partner_assign || {};
|
||||||
instance.crm_partner_assign.next_or_list = function(parent) {
|
instance.crm_partner_assign.next_or_list = function(parent) {
|
||||||
var form = parent.inner_widget.views.form.controller;
|
if (parent.inner_widget.active_view === "form"){
|
||||||
form.dataset.remove_ids([form.dataset.ids[form.dataset.index]]);
|
var form = parent.inner_widget.views.form.controller;
|
||||||
form.reload();
|
form.dataset.remove_ids([form.dataset.ids[form.dataset.index]]);
|
||||||
if (!form.dataset.ids.length){
|
form.reload();
|
||||||
parent.inner_widget.switch_mode('list');
|
if (!form.dataset.ids.length){
|
||||||
|
parent.inner_widget.switch_mode('list');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
parent.inner_widget.views[parent.inner_widget.active_view].controller.reload();
|
||||||
}
|
}
|
||||||
parent.do_action({ type: 'ir.actions.act_window_close' });
|
parent.do_action({ type: 'ir.actions.act_window_close' });
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,7 +53,7 @@ class crm_lead_forward_to_partner(osv.TransientModel):
|
||||||
values = {'partner_assigned_id': False}
|
values = {'partner_assigned_id': False}
|
||||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||||
partner_ids = self.pool.get('res.partner').search(cr, SUPERUSER_ID, [('id', 'child_of', user.partner_id.commercial_partner_id.id)], context=context)
|
partner_ids = self.pool.get('res.partner').search(cr, SUPERUSER_ID, [('id', 'child_of', user.partner_id.commercial_partner_id.id)], context=context)
|
||||||
lead_obj.message_unsubscribe(cr, SUPERUSER_ID, context.get('active_ids'), partner_ids, context=None)
|
lead_obj.message_unsubscribe(cr, SUPERUSER_ID, context.get('active_ids', []), partner_ids, context=None)
|
||||||
try:
|
try:
|
||||||
stage_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', stage)[1]
|
stage_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm_partner_assign', stage)[1]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -62,11 +62,12 @@ class crm_lead_forward_to_partner(osv.TransientModel):
|
||||||
values.update({'stage_id': stage_id})
|
values.update({'stage_id': stage_id})
|
||||||
if wizard.comment:
|
if wizard.comment:
|
||||||
message += '<p>%s</p>' % wizard.comment
|
message += '<p>%s</p>' % wizard.comment
|
||||||
lead_obj.message_post(cr, uid, context.get('active_ids'), body=message, context=context)
|
for active_id in context.get('active_ids', []):
|
||||||
|
lead_obj.message_post(cr, uid, active_id, body=message, context=context)
|
||||||
if values:
|
if values:
|
||||||
lead_obj.write(cr, SUPERUSER_ID, context.get('active_ids'), values)
|
lead_obj.write(cr, SUPERUSER_ID, context.get('active_ids', []), values)
|
||||||
if wizard.interested:
|
if wizard.interested:
|
||||||
for lead in lead_obj.browse(cr, uid, context.get('active_ids'), context=context):
|
for lead in lead_obj.browse(cr, uid, context.get('active_ids', []), context=context):
|
||||||
lead_obj.convert_opportunity(cr, SUPERUSER_ID, [lead.id], lead.partner_id and lead.partner_id.id or None, context=None)
|
lead_obj.convert_opportunity(cr, SUPERUSER_ID, [lead.id], lead.partner_id and lead.partner_id.id or None, context=None)
|
||||||
return {
|
return {
|
||||||
'type': 'ir.actions.client',
|
'type': 'ir.actions.client',
|
||||||
|
|
|
@ -139,6 +139,8 @@ class crm_lead_forward_to_partner(osv.TransientModel):
|
||||||
values = {'partner_assigned_id': partner_id, 'user_id': partner_leads['partner'].user_id.id}
|
values = {'partner_assigned_id': partner_id, 'user_id': partner_leads['partner'].user_id.id}
|
||||||
if stage_id:
|
if stage_id:
|
||||||
values['stage_id'] = stage_id
|
values['stage_id'] = stage_id
|
||||||
|
if partner_leads['partner'].user_id:
|
||||||
|
values['section_id'] = partner_leads['partner'].user_id.default_section_id.id
|
||||||
lead_obj.write(cr, uid, lead_ids, values)
|
lead_obj.write(cr, uid, lead_ids, values)
|
||||||
self.pool.get('crm.lead').message_subscribe(cr, uid, lead_ids, [partner_id], context=context)
|
self.pool.get('crm.lead').message_subscribe(cr, uid, lead_ids, [partner_id], context=context)
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -23,6 +23,7 @@ import openerp
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID
|
||||||
from openerp import tools
|
from openerp import tools
|
||||||
from openerp.osv import osv, fields
|
from openerp.osv import osv, fields
|
||||||
|
from openerp.modules.registry import RegistryManager
|
||||||
|
|
||||||
class decimal_precision(osv.osv):
|
class decimal_precision(osv.osv):
|
||||||
_name = 'decimal.precision'
|
_name = 'decimal.precision'
|
||||||
|
@ -44,23 +45,28 @@ class decimal_precision(osv.osv):
|
||||||
res = cr.fetchone()
|
res = cr.fetchone()
|
||||||
return res[0] if res else 2
|
return res[0] if res else 2
|
||||||
|
|
||||||
|
def clear_cache(self, cr):
|
||||||
|
"""clear cache and update models. Notify other workers to restart their registry."""
|
||||||
|
self.precision_get.clear_cache(self)
|
||||||
|
for obj in self.pool.obj_list():
|
||||||
|
for colname, col in self.pool.get(obj)._columns.items():
|
||||||
|
if isinstance(col, (fields.float, fields.function)):
|
||||||
|
col.digits_change(cr)
|
||||||
|
RegistryManager.signal_registry_change(cr.dbname)
|
||||||
|
|
||||||
def create(self, cr, uid, data, context=None):
|
def create(self, cr, uid, data, context=None):
|
||||||
res = super(decimal_precision, self).create(cr, uid, data, context=context)
|
res = super(decimal_precision, self).create(cr, uid, data, context=context)
|
||||||
self.precision_get.clear_cache(self)
|
self.clear_cache(cr)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def unlink(self, cr, uid, ids, context=None):
|
def unlink(self, cr, uid, ids, context=None):
|
||||||
res = super(decimal_precision, self).unlink(cr, uid, ids, context=context)
|
res = super(decimal_precision, self).unlink(cr, uid, ids, context=context)
|
||||||
self.precision_get.clear_cache(self)
|
self.clear_cache(cr)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def write(self, cr, uid, ids, data, *args, **argv):
|
def write(self, cr, uid, ids, data, *args, **argv):
|
||||||
res = super(decimal_precision, self).write(cr, uid, ids, data, *args, **argv)
|
res = super(decimal_precision, self).write(cr, uid, ids, data, *args, **argv)
|
||||||
self.precision_get.clear_cache(self)
|
self.clear_cache(cr)
|
||||||
for obj in self.pool.obj_list():
|
|
||||||
for colname, col in self.pool[obj]._columns.items():
|
|
||||||
if isinstance(col, (fields.float, fields.function)):
|
|
||||||
col.digits_change(cr)
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ class test_message_compose(TestMail):
|
||||||
'body_html': '${object.description}',
|
'body_html': '${object.description}',
|
||||||
'user_signature': True,
|
'user_signature': True,
|
||||||
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
|
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
|
||||||
'email_to': 'b@b.b c@c.c',
|
'email_to': 'b@b.b, c@c.c',
|
||||||
'email_cc': 'd@d.d'
|
'email_cc': 'd@d.d'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ class test_message_compose(TestMail):
|
||||||
email_template.write(cr, uid, [email_template_id], {
|
email_template.write(cr, uid, [email_template_id], {
|
||||||
'model_id': user_model_id,
|
'model_id': user_model_id,
|
||||||
'body_html': '${object.login}',
|
'body_html': '${object.login}',
|
||||||
'email_to': '${object.email} c@c',
|
'email_to': '${object.email}, c@c',
|
||||||
'partner_to': '%i,%i' % (p_b_id, p_c_id),
|
'partner_to': '%i,%i' % (p_b_id, p_c_id),
|
||||||
'email_cc': 'd@d',
|
'email_cc': 'd@d',
|
||||||
})
|
})
|
||||||
|
@ -217,7 +217,7 @@ class test_message_compose(TestMail):
|
||||||
'subject': '${object.name}',
|
'subject': '${object.name}',
|
||||||
'body_html': '${object.description}',
|
'body_html': '${object.description}',
|
||||||
'user_signature': True,
|
'user_signature': True,
|
||||||
'email_to': 'b@b.b c@c.c',
|
'email_to': 'b@b.b, c@c.c',
|
||||||
'email_cc': 'd@d.d',
|
'email_cc': 'd@d.d',
|
||||||
'partner_to': '${user.partner_id.id},%s,%s,-1' % (self.user_raoul.partner_id.id, self.user_bert.partner_id.id)
|
'partner_to': '${user.partner_id.id},%s,%s,-1' % (self.user_raoul.partner_id.id, self.user_bert.partner_id.id)
|
||||||
})
|
})
|
||||||
|
@ -226,7 +226,7 @@ class test_message_compose(TestMail):
|
||||||
msg_id = email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, context=context)
|
msg_id = email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, context=context)
|
||||||
mail = self.mail_mail.browse(cr, uid, msg_id, context=context)
|
mail = self.mail_mail.browse(cr, uid, msg_id, context=context)
|
||||||
self.assertEqual(mail.subject, 'Pigs', 'email_template: send_mail: wrong subject')
|
self.assertEqual(mail.subject, 'Pigs', 'email_template: send_mail: wrong subject')
|
||||||
self.assertEqual(mail.email_to, 'b@b.b c@c.c', 'email_template: send_mail: wrong email_to')
|
self.assertEqual(mail.email_to, 'b@b.b, c@c.c', 'email_template: send_mail: wrong email_to')
|
||||||
self.assertEqual(mail.email_cc, 'd@d.d', 'email_template: send_mail: wrong email_cc')
|
self.assertEqual(mail.email_cc, 'd@d.d', 'email_template: send_mail: wrong email_cc')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
set([partner.id for partner in mail.recipient_ids]),
|
set([partner.id for partner in mail.recipient_ids]),
|
||||||
|
|
|
@ -137,7 +137,7 @@ class mail_compose_message(osv.TransientModel):
|
||||||
def _get_or_create_partners_from_values(self, cr, uid, rendered_values, context=None):
|
def _get_or_create_partners_from_values(self, cr, uid, rendered_values, context=None):
|
||||||
""" Check for email_to, email_cc, partner_to """
|
""" Check for email_to, email_cc, partner_to """
|
||||||
partner_ids = []
|
partner_ids = []
|
||||||
mails = tools.email_split(rendered_values.pop('email_to', '') + ' ' + rendered_values.pop('email_cc', ''))
|
mails = tools.email_split(rendered_values.pop('email_to', '')) + tools.email_split(rendered_values.pop('email_cc', ''))
|
||||||
for mail in mails:
|
for mail in mails:
|
||||||
partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
|
partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
|
||||||
partner_ids.append(partner_id)
|
partner_ids.append(partner_id)
|
||||||
|
|
|
@ -120,7 +120,7 @@ class config(osv.Model):
|
||||||
res['url'] = content['alternateLink']
|
res['url'] = content['alternateLink']
|
||||||
key = self._get_key_from_url(res['url'])
|
key = self._get_key_from_url(res['url'])
|
||||||
request_url = "https://www.googleapis.com/drive/v2/files/%s/permissions?emailMessage=This+is+a+drive+file+created+by+OpenERP&sendNotificationEmails=false&access_token=%s" % (key, access_token)
|
request_url = "https://www.googleapis.com/drive/v2/files/%s/permissions?emailMessage=This+is+a+drive+file+created+by+OpenERP&sendNotificationEmails=false&access_token=%s" % (key, access_token)
|
||||||
data = {'role': 'reader', 'type': 'anyone', 'value': '', 'withLink': True}
|
data = {'role': 'writer', 'type': 'anyone', 'value': '', 'withLink': True}
|
||||||
try:
|
try:
|
||||||
req = urllib2.Request(request_url, json.dumps(data), headers)
|
req = urllib2.Request(request_url, json.dumps(data), headers)
|
||||||
urllib2.urlopen(req)
|
urllib2.urlopen(req)
|
||||||
|
@ -133,7 +133,7 @@ class config(osv.Model):
|
||||||
req = urllib2.Request(request_url, json.dumps(data), headers)
|
req = urllib2.Request(request_url, json.dumps(data), headers)
|
||||||
urllib2.urlopen(req)
|
urllib2.urlopen(req)
|
||||||
except urllib2.HTTPError:
|
except urllib2.HTTPError:
|
||||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _("The permission 'writer' for your email '%s' has not been written on the document. Is this email a valid Google Account ?" % user.email), context=context)
|
pass
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def get_google_drive_config(self, cr, uid, res_model, res_id, context=None):
|
def get_google_drive_config(self, cr, uid, res_model, res_id, context=None):
|
||||||
|
|
|
@ -76,10 +76,11 @@ class account_analytic_account(osv.osv):
|
||||||
|
|
||||||
def on_change_partner_id(self, cr, uid, ids, partner_id, name, context=None):
|
def on_change_partner_id(self, cr, uid, ids, partner_id, name, context=None):
|
||||||
res = super(account_analytic_account, self).on_change_partner_id(cr, uid, ids, partner_id, name, context=context)
|
res = super(account_analytic_account, self).on_change_partner_id(cr, uid, ids, partner_id, name, context=context)
|
||||||
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
if partner_id:
|
||||||
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
|
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||||
if pricelist:
|
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
|
||||||
res['value']['pricelist_id'] = pricelist
|
if pricelist:
|
||||||
|
res['value']['pricelist_id'] = pricelist
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def set_close(self, cr, uid, ids, context=None):
|
def set_close(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -9,12 +9,14 @@ openerp.hr_timesheet_sheet = function(instance) {
|
||||||
},
|
},
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
var self = this;
|
||||||
this.set({
|
this.set({
|
||||||
sheets: [],
|
sheets: [],
|
||||||
date_to: false,
|
date_to: false,
|
||||||
date_from: false,
|
date_from: false,
|
||||||
});
|
});
|
||||||
this.updating = false;
|
this.updating = false;
|
||||||
|
this.defs = [];
|
||||||
this.field_manager.on("field_changed:timesheet_ids", this, this.query_sheets);
|
this.field_manager.on("field_changed:timesheet_ids", this, this.query_sheets);
|
||||||
this.field_manager.on("field_changed:date_from", this, function() {
|
this.field_manager.on("field_changed:date_from", this, function() {
|
||||||
this.set({"date_from": instance.web.str_to_date(this.field_manager.get_field_value("date_from"))});
|
this.set({"date_from": instance.web.str_to_date(this.field_manager.get_field_value("date_from"))});
|
||||||
|
@ -29,6 +31,14 @@ openerp.hr_timesheet_sheet = function(instance) {
|
||||||
this.res_o2m_drop = new instance.web.DropMisordered();
|
this.res_o2m_drop = new instance.web.DropMisordered();
|
||||||
this.render_drop = new instance.web.DropMisordered();
|
this.render_drop = new instance.web.DropMisordered();
|
||||||
this.description_line = _t("/");
|
this.description_line = _t("/");
|
||||||
|
// Original save function is overwritten in order to wait all running deferreds to be done before actually applying the save.
|
||||||
|
this.view.original_save = _.bind(this.view.save, this.view);
|
||||||
|
this.view.save = function(prepend_on_create){
|
||||||
|
self.prepend_on_create = prepend_on_create;
|
||||||
|
return $.when.apply($, self.defs).then(function(){
|
||||||
|
return self.view.original_save(self.prepend_on_create);
|
||||||
|
});
|
||||||
|
};
|
||||||
},
|
},
|
||||||
go_to: function(event) {
|
go_to: function(event) {
|
||||||
var id = JSON.parse($(event.target).data("id"));
|
var id = JSON.parse($(event.target).data("id"));
|
||||||
|
@ -192,11 +202,11 @@ openerp.hr_timesheet_sheet = function(instance) {
|
||||||
account.days[day_count].lines[0].unit_amount += num - self.sum_box(account, day_count);
|
account.days[day_count].lines[0].unit_amount += num - self.sum_box(account, day_count);
|
||||||
var product = (account.days[day_count].lines[0].product_id instanceof Array) ? account.days[day_count].lines[0].product_id[0] : account.days[day_count].lines[0].product_id
|
var product = (account.days[day_count].lines[0].product_id instanceof Array) ? account.days[day_count].lines[0].product_id[0] : account.days[day_count].lines[0].product_id
|
||||||
var journal = (account.days[day_count].lines[0].journal_id instanceof Array) ? account.days[day_count].lines[0].journal_id[0] : account.days[day_count].lines[0].journal_id
|
var journal = (account.days[day_count].lines[0].journal_id instanceof Array) ? account.days[day_count].lines[0].journal_id[0] : account.days[day_count].lines[0].journal_id
|
||||||
new instance.web.Model("hr.analytic.timesheet").call("on_change_unit_amount", [[], product, account.days[day_count].lines[0].unit_amount, false, false, journal]).then(function(res) {
|
self.defs.push(new instance.web.Model("hr.analytic.timesheet").call("on_change_unit_amount", [[], product, account.days[day_count].lines[0].unit_amount, false, false, journal]).then(function(res) {
|
||||||
account.days[day_count].lines[0]['amount'] = res.value.amount || 0;
|
account.days[day_count].lines[0]['amount'] = res.value.amount || 0;
|
||||||
self.display_totals();
|
self.display_totals();
|
||||||
self.sync();
|
self.sync();
|
||||||
});
|
}));
|
||||||
if(!isNaN($(this).val())){
|
if(!isNaN($(this).val())){
|
||||||
$(this).val(self.sum_box(account, day_count, true));
|
$(this).val(self.sum_box(account, day_count, true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import openerp.tools.config
|
||||||
import openerp.modules.registry
|
import openerp.modules.registry
|
||||||
from openerp import http
|
from openerp import http
|
||||||
from openerp.http import request
|
from openerp.http import request
|
||||||
from openerp.osv import osv, fields
|
from openerp.osv import osv, fields, expression
|
||||||
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
|
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
@ -249,11 +249,31 @@ class im_user(osv.osv):
|
||||||
res[obj["id"]] = obj["im_last_status"] and (last_update + delta) > current
|
res[obj["id"]] = obj["im_last_status"] and (last_update + delta) > current
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def _status_search(self, cr, uid, obj, name, domain, context=None):
|
||||||
|
current = datetime.datetime.now()
|
||||||
|
delta = datetime.timedelta(0, DISCONNECTION_TIMER)
|
||||||
|
field, operator, value = domain[0]
|
||||||
|
if operator in expression.NEGATIVE_TERM_OPERATORS:
|
||||||
|
value = not value
|
||||||
|
if value:
|
||||||
|
return ['&', ('im_last_status', '=', True), ('im_last_status_update', '>', (current - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT))]
|
||||||
|
else:
|
||||||
|
return ['|', ('im_last_status', '=', False), ('im_last_status_update', '<=', (current - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT))]
|
||||||
|
|
||||||
def search_users(self, cr, uid, text_search, fields, limit, context=None):
|
def search_users(self, cr, uid, text_search, fields, limit, context=None):
|
||||||
my_id = self.get_my_id(cr, uid, None, context)
|
my_id = self.get_my_id(cr, uid, None, context)
|
||||||
found = self.search(cr, uid, [["name", "ilike", text_search], ["id", "<>", my_id], ["uuid", "=", False]],
|
group_employee = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'group_user')[1]
|
||||||
|
found = self.search(cr, uid, [["name", "ilike", text_search], ["id", "<>", my_id], ["uuid", "=", False], ["im_status", "=", True], ["user_id.groups_id", "in", [group_employee]]],
|
||||||
order="name asc", limit=limit, context=context)
|
order="name asc", limit=limit, context=context)
|
||||||
return self.read(cr, uid, found, fields, context=context)
|
if len(found) < limit:
|
||||||
|
found += self.search(cr, uid, [["name", "ilike", text_search], ["id", "<>", my_id], ["uuid", "=", False], ["im_status", "=", True], ["id", "not in", found]],
|
||||||
|
order="name asc", limit=limit, context=context)
|
||||||
|
if len(found) < limit:
|
||||||
|
found += self.search(cr, uid, [["name", "ilike", text_search], ["id", "<>", my_id], ["uuid", "=", False], ["im_status", "=", False], ["id", "not in", found]],
|
||||||
|
order="name asc", limit=limit-len(found), context=context)
|
||||||
|
users = self.read(cr, uid, found, fields, context=context)
|
||||||
|
users.sort(key=lambda obj: found.index(obj['id']))
|
||||||
|
return users
|
||||||
|
|
||||||
def im_connect(self, cr, uid, uuid=None, context=None):
|
def im_connect(self, cr, uid, uuid=None, context=None):
|
||||||
assert_uuid(uuid)
|
assert_uuid(uuid)
|
||||||
|
@ -308,7 +328,7 @@ class im_user(osv.osv):
|
||||||
'im_last_received': fields.integer(string="Instant Messaging Last Received Message"),
|
'im_last_received': fields.integer(string="Instant Messaging Last Received Message"),
|
||||||
'im_last_status': fields.boolean(strint="Instant Messaging Last Status"),
|
'im_last_status': fields.boolean(strint="Instant Messaging Last Status"),
|
||||||
'im_last_status_update': fields.datetime(string="Instant Messaging Last Status Update"),
|
'im_last_status_update': fields.datetime(string="Instant Messaging Last Status Update"),
|
||||||
'im_status': fields.function(_im_status, string="Instant Messaging Status", type='boolean'),
|
'im_status': fields.function(_im_status, string="Instant Messaging Status", type='boolean', fnct_search=_status_search),
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -259,7 +259,7 @@ function declare($, _, openerp) {
|
||||||
_.each(messages, function(message) {
|
_.each(messages, function(message) {
|
||||||
if (! message.technical) {
|
if (! message.technical) {
|
||||||
defs.push(self.activate_session(message.session_id[0]).then(function(conv) {
|
defs.push(self.activate_session(message.session_id[0]).then(function(conv) {
|
||||||
received = true;
|
received = self.my_id !== message.from_id[0];
|
||||||
return conv.received_message(message);
|
return conv.received_message(message);
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
@ -268,12 +268,13 @@ function declare($, _, openerp) {
|
||||||
defs.push($.when(im_common.technical_messages_handlers[json.type](self, message)));
|
defs.push($.when(im_common.technical_messages_handlers[json.type](self, message)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (! this.get("window_focus") && received) {
|
return $.when.apply($, defs).then(function(){
|
||||||
this.set("waiting_messages", this.get("waiting_messages") + messages.length);
|
if (! self.get("window_focus") && received) {
|
||||||
this.ting.play();
|
self.set("waiting_messages", self.get("waiting_messages") + messages.length);
|
||||||
this.create_ting();
|
self.ting.play();
|
||||||
}
|
self.create_ting();
|
||||||
return $.when.apply($, defs);
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
calc_positions: function() {
|
calc_positions: function() {
|
||||||
var current = this.get("right_offset");
|
var current = this.get("right_offset");
|
||||||
|
@ -520,7 +521,7 @@ function declare($, _, openerp) {
|
||||||
txt += _.escape(str.slice(last, result.index));
|
txt += _.escape(str.slice(last, result.index));
|
||||||
last = url_regex.lastIndex;
|
last = url_regex.lastIndex;
|
||||||
var url = _.escape(result[0]);
|
var url = _.escape(result[0]);
|
||||||
txt += '<a href="' + url + '">' + url + '</a>';
|
txt += '<a href="' + url + '" target="_blank">' + url + '</a>';
|
||||||
}
|
}
|
||||||
txt += _.escape(str.slice(last, str.length));
|
txt += _.escape(str.slice(last, str.length));
|
||||||
return txt;
|
return txt;
|
||||||
|
|
|
@ -252,10 +252,9 @@ class mail_thread(osv.AbstractModel):
|
||||||
new = set(command[2])
|
new = set(command[2])
|
||||||
|
|
||||||
# remove partners that are no longer followers
|
# remove partners that are no longer followers
|
||||||
self.message_unsubscribe(cr, uid, [id], list(old-new))
|
self.message_unsubscribe(cr, uid, [id], list(old-new), context=context)
|
||||||
|
|
||||||
# add new followers
|
# add new followers
|
||||||
self.message_subscribe(cr, uid, [id], list(new-old))
|
self.message_subscribe(cr, uid, [id], list(new-old), context=context)
|
||||||
|
|
||||||
def _search_followers(self, cr, uid, obj, name, args, context):
|
def _search_followers(self, cr, uid, obj, name, args, context):
|
||||||
"""Search function for message_follower_ids
|
"""Search function for message_follower_ids
|
||||||
|
@ -291,7 +290,7 @@ class mail_thread(osv.AbstractModel):
|
||||||
'message_is_follower': fields.function(_get_followers, type='boolean',
|
'message_is_follower': fields.function(_get_followers, type='boolean',
|
||||||
fnct_search=_search_is_follower, string='Is a Follower', multi='_get_followers,'),
|
fnct_search=_search_is_follower, string='Is a Follower', multi='_get_followers,'),
|
||||||
'message_follower_ids': fields.function(_get_followers, fnct_inv=_set_followers,
|
'message_follower_ids': fields.function(_get_followers, fnct_inv=_set_followers,
|
||||||
fnct_search=_search_followers, type='many2many',
|
fnct_search=_search_followers, type='many2many', priority=-10,
|
||||||
obj='res.partner', string='Followers', multi='_get_followers'),
|
obj='res.partner', string='Followers', multi='_get_followers'),
|
||||||
'message_ids': fields.one2many('mail.message', 'res_id',
|
'message_ids': fields.one2many('mail.message', 'res_id',
|
||||||
domain=lambda self: [('model', '=', self._name)],
|
domain=lambda self: [('model', '=', self._name)],
|
||||||
|
@ -344,16 +343,22 @@ class mail_thread(osv.AbstractModel):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
thread_id = super(mail_thread, self).create(cr, uid, values, context=context)
|
# subscribe uid unless asked not to
|
||||||
|
if not context.get('mail_create_nosubscribe'):
|
||||||
|
pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid).partner_id.id
|
||||||
|
message_follower_ids = values.get('message_follower_ids') or [] # webclient can send None or False
|
||||||
|
message_follower_ids.append([4, pid])
|
||||||
|
values['message_follower_ids'] = message_follower_ids
|
||||||
|
# add operation to ignore access rule checking for subscription
|
||||||
|
context_operation = dict(context, operation='create')
|
||||||
|
else:
|
||||||
|
context_operation = context
|
||||||
|
thread_id = super(mail_thread, self).create(cr, uid, values, context=context_operation)
|
||||||
|
|
||||||
# automatic logging unless asked not to (mainly for various testing purpose)
|
# automatic logging unless asked not to (mainly for various testing purpose)
|
||||||
if not context.get('mail_create_nolog'):
|
if not context.get('mail_create_nolog'):
|
||||||
self.message_post(cr, uid, thread_id, body=_('%s created') % (self._description), context=context)
|
self.message_post(cr, uid, thread_id, body=_('%s created') % (self._description), context=context)
|
||||||
|
|
||||||
# subscribe uid unless asked not to
|
|
||||||
if not context.get('mail_create_nosubscribe'):
|
|
||||||
self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context)
|
|
||||||
|
|
||||||
# auto_subscribe: take values and defaults into account
|
# auto_subscribe: take values and defaults into account
|
||||||
create_values = dict(values)
|
create_values = dict(values)
|
||||||
for key, val in context.iteritems():
|
for key, val in context.iteritems():
|
||||||
|
@ -1115,11 +1120,23 @@ class mail_thread(osv.AbstractModel):
|
||||||
alternative = True
|
alternative = True
|
||||||
if part.get_content_maintype() == 'multipart':
|
if part.get_content_maintype() == 'multipart':
|
||||||
continue # skip container
|
continue # skip container
|
||||||
filename = part.get_filename() # None if normal part
|
# part.get_filename returns decoded value if able to decode, coded otherwise.
|
||||||
|
# original get_filename is not able to decode iso-8859-1 (for instance).
|
||||||
|
# therefore, iso encoded attachements are not able to be decoded properly with get_filename
|
||||||
|
# code here partially copy the original get_filename method, but handle more encoding
|
||||||
|
filename=part.get_param('filename', None, 'content-disposition')
|
||||||
|
if not filename:
|
||||||
|
filename=part.get_param('name', None)
|
||||||
|
if filename:
|
||||||
|
if isinstance(filename, tuple):
|
||||||
|
# RFC2231
|
||||||
|
filename=email.utils.collapse_rfc2231_value(filename).strip()
|
||||||
|
else:
|
||||||
|
filename=decode(filename)
|
||||||
encoding = part.get_content_charset() # None if attachment
|
encoding = part.get_content_charset() # None if attachment
|
||||||
# 1) Explicit Attachments -> attachments
|
# 1) Explicit Attachments -> attachments
|
||||||
if filename or part.get('content-disposition', '').strip().startswith('attachment'):
|
if filename or part.get('content-disposition', '').strip().startswith('attachment'):
|
||||||
attachments.append((decode(filename) or 'attachment', part.get_payload(decode=True)))
|
attachments.append((filename or 'attachment', part.get_payload(decode=True)))
|
||||||
continue
|
continue
|
||||||
# 2) text/plain -> <pre/>
|
# 2) text/plain -> <pre/>
|
||||||
if part.get_content_type() == 'text/plain' and (not alternative or not body):
|
if part.get_content_type() == 'text/plain' and (not alternative or not body):
|
||||||
|
@ -1532,20 +1549,26 @@ class mail_thread(osv.AbstractModel):
|
||||||
|
|
||||||
def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
|
def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
|
||||||
""" Add partners to the records followers. """
|
""" Add partners to the records followers. """
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
|
||||||
mail_followers_obj = self.pool.get('mail.followers')
|
mail_followers_obj = self.pool.get('mail.followers')
|
||||||
subtype_obj = self.pool.get('mail.message.subtype')
|
subtype_obj = self.pool.get('mail.message.subtype')
|
||||||
|
|
||||||
user_pid = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
user_pid = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
||||||
if set(partner_ids) == set([user_pid]):
|
if set(partner_ids) == set([user_pid]):
|
||||||
try:
|
if context.get('operation', '') != 'create':
|
||||||
self.check_access_rights(cr, uid, 'read')
|
try:
|
||||||
except (osv.except_osv, orm.except_orm):
|
self.check_access_rights(cr, uid, 'read')
|
||||||
return
|
self.check_access_rule(cr, uid, ids, 'read')
|
||||||
|
except (osv.except_osv, orm.except_orm):
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
self.check_access_rights(cr, uid, 'write')
|
self.check_access_rights(cr, uid, 'write')
|
||||||
|
self.check_access_rule(cr, uid, ids, 'write')
|
||||||
|
|
||||||
existing_pids_dict = {}
|
existing_pids_dict = {}
|
||||||
fol_ids = mail_followers_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids)])
|
fol_ids = mail_followers_obj.search(cr, SUPERUSER_ID, ['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)])
|
||||||
for fol in mail_followers_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context):
|
for fol in mail_followers_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context):
|
||||||
existing_pids_dict.setdefault(fol.res_id, set()).add(fol.partner_id.id)
|
existing_pids_dict.setdefault(fol.res_id, set()).add(fol.partner_id.id)
|
||||||
|
|
||||||
|
@ -1587,8 +1610,10 @@ class mail_thread(osv.AbstractModel):
|
||||||
user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0]
|
||||||
if set(partner_ids) == set([user_pid]):
|
if set(partner_ids) == set([user_pid]):
|
||||||
self.check_access_rights(cr, uid, 'read')
|
self.check_access_rights(cr, uid, 'read')
|
||||||
|
self.check_access_rule(cr, uid, ids, 'read')
|
||||||
else:
|
else:
|
||||||
self.check_access_rights(cr, uid, 'write')
|
self.check_access_rights(cr, uid, 'write')
|
||||||
|
self.check_access_rule(cr, uid, ids, 'write')
|
||||||
fol_obj = self.pool['mail.followers']
|
fol_obj = self.pool['mail.followers']
|
||||||
fol_ids = fol_obj.search(
|
fol_ids = fol_obj.search(
|
||||||
cr, SUPERUSER_ID, [
|
cr, SUPERUSER_ID, [
|
||||||
|
|
|
@ -1438,7 +1438,7 @@ openerp.mail = function (session) {
|
||||||
message_fetch: function (replace_domain, replace_context, ids, callback) {
|
message_fetch: function (replace_domain, replace_context, ids, callback) {
|
||||||
return this.ds_message.call('message_read', [
|
return this.ds_message.call('message_read', [
|
||||||
// ids force to read
|
// ids force to read
|
||||||
ids == false ? undefined : ids,
|
ids === false ? undefined : ids,
|
||||||
// domain + additional
|
// domain + additional
|
||||||
(replace_domain ? replace_domain : this.domain),
|
(replace_domain ? replace_domain : this.domain),
|
||||||
// ids allready loaded
|
// ids allready loaded
|
||||||
|
@ -1814,7 +1814,7 @@ openerp.mail = function (session) {
|
||||||
if ('display_log_button' in this.options) {
|
if ('display_log_button' in this.options) {
|
||||||
this.node.params.display_log_button = this.options.display_log_button;
|
this.node.params.display_log_button = this.options.display_log_button;
|
||||||
}
|
}
|
||||||
this.domain = this.node.params && this.node.params.domain || [];
|
this.domain = (this.node.params && this.node.params.domain) || (this.field && this.field.domain) || [];
|
||||||
|
|
||||||
if (!this.ParentViewManager.is_action_enabled('edit')) {
|
if (!this.ParentViewManager.is_action_enabled('edit')) {
|
||||||
this.node.params.show_link = false;
|
this.node.params.show_link = false;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<!-- Top menu item -->
|
<!-- Top menu item -->
|
||||||
<menuitem name="Marketing"
|
<menuitem name="Marketing"
|
||||||
id="base.marketing_menu"
|
id="base.marketing_menu"
|
||||||
groups="marketing.group_marketing_user,marketing.group_marketing_manager"
|
groups="base.group_user"
|
||||||
sequence="85"/>
|
sequence="85"/>
|
||||||
|
|
||||||
<record id="view_crm_lead_form" model="ir.ui.view">
|
<record id="view_crm_lead_form" model="ir.ui.view">
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
</data>
|
</data>
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<menuitem name="Configuration" id="menu_marketing_configuration" parent="base.marketing_menu" sequence="1"/>
|
|
||||||
|
|
||||||
<!-- Marketing Campaign -->
|
<!-- Marketing Campaign -->
|
||||||
|
|
||||||
<record id="act_marketing_campaing_segment_opened" model="ir.actions.act_window">
|
<record id="act_marketing_campaing_segment_opened" model="ir.actions.act_window">
|
||||||
|
@ -177,7 +175,7 @@
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem name="Campaigns" id="menu_marketing_campaign" parent="base.marketing_menu"/>
|
<menuitem name="Campaigns" id="menu_marketing_campaign" parent="base.marketing_menu" groups="marketing.group_marketing_user,marketing.group_marketing_manager"/>
|
||||||
<menuitem id="menu_marketing_campaign_form" parent="menu_marketing_campaign" action="action_marketing_campaign_form" sequence="30"/>
|
<menuitem id="menu_marketing_campaign_form" parent="menu_marketing_campaign" action="action_marketing_campaign_form" sequence="30"/>
|
||||||
|
|
||||||
<!-- Marketing Segments -->
|
<!-- Marketing Segments -->
|
||||||
|
|
|
@ -358,7 +358,7 @@
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Top menu item -->
|
<!-- Top menu item -->
|
||||||
<menuitem name="Marketing" id="base.marketing_menu" sequence="85"/>
|
<menuitem name="Marketing" id="base.marketing_menu" sequence="85" groups="base.group_user"/>
|
||||||
|
|
||||||
<!-- Add in marketing -->
|
<!-- Add in marketing -->
|
||||||
<menuitem name="Mass Mailing" id="mass_mailing_campaign"
|
<menuitem name="Mass Mailing" id="mass_mailing_campaign"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_mass_mailing_campaign,mail.mass_mailing.campaign,model_mail_mass_mailing_campaign,,1,1,1,0
|
access_mass_mailing_campaign,mail.mass_mailing.campaign,model_mail_mass_mailing_campaign,base.group_user,1,1,1,0
|
||||||
access_mass_mailing_campaign_system,mail.mass_mailing.campaign.system,model_mail_mass_mailing_campaign,base.group_system,1,1,1,1
|
access_mass_mailing_campaign_system,mail.mass_mailing.campaign.system,model_mail_mass_mailing_campaign,base.group_system,1,1,1,1
|
||||||
access_mass_mailing,mail.mass_mailing,model_mail_mass_mailing,,1,1,1,0
|
access_mass_mailing,mail.mass_mailing,model_mail_mass_mailing,base.group_user,1,1,1,0
|
||||||
access_mass_mailing_system,mail.mass_mailing.system,model_mail_mass_mailing,base.group_system,1,1,1,1
|
access_mass_mailing_system,mail.mass_mailing.system,model_mail_mass_mailing,base.group_system,1,1,1,1
|
||||||
access_mail_mail_statistics,mail.mail.statistics,model_mail_mail_statistics,,1,1,1,1
|
access_mail_mail_statistics,mail.mail.statistics,model_mail_mail_statistics,base.group_user,1,1,1,1
|
|
|
@ -43,15 +43,18 @@ class MailComposeMessage(osv.TransientModel):
|
||||||
email mass mailing. """
|
email mass mailing. """
|
||||||
res = super(MailComposeMessage, self).get_mail_values(cr, uid, wizard, res_ids, context=context)
|
res = super(MailComposeMessage, self).get_mail_values(cr, uid, wizard, res_ids, context=context)
|
||||||
if wizard.composition_mode == 'mass_mail' and wizard.mass_mailing_campaign_id: # TODO: which kind of mass mailing ?
|
if wizard.composition_mode == 'mass_mail' and wizard.mass_mailing_campaign_id: # TODO: which kind of mass mailing ?
|
||||||
current_date = fields.datetime.now()
|
if wizard.mass_mailing_id:
|
||||||
mass_mailing_id = self.pool['mail.mass_mailing'].create(
|
mass_mailing_id = wizard.mass_mailing_id.id
|
||||||
cr, uid, {
|
else:
|
||||||
'mass_mailing_campaign_id': wizard.mass_mailing_campaign_id.id,
|
current_date = fields.datetime.now()
|
||||||
'name': '%s-%s' % (wizard.mass_mailing_campaign_id.name, current_date),
|
mass_mailing_id = self.pool['mail.mass_mailing'].create(
|
||||||
'date': current_date,
|
cr, uid, {
|
||||||
'domain': wizard.active_domain,
|
'mass_mailing_campaign_id': wizard.mass_mailing_campaign_id.id,
|
||||||
'template_id': wizard.template_id and wizard.template_id.id or False,
|
'name': '%s-%s' % (wizard.mass_mailing_campaign_id.name, current_date),
|
||||||
}, context=context)
|
'date': current_date,
|
||||||
|
'domain': wizard.active_domain,
|
||||||
|
'template_id': wizard.template_id and wizard.template_id.id or False,
|
||||||
|
}, context=context)
|
||||||
for res_id in res_ids:
|
for res_id in res_ids:
|
||||||
res[res_id]['statistics_ids'] = [(0, 0, {
|
res[res_id]['statistics_ids'] = [(0, 0, {
|
||||||
'model': wizard.model,
|
'model': wizard.model,
|
||||||
|
|
|
@ -33,11 +33,6 @@ class procurement_order(osv.osv):
|
||||||
'production_id': fields.many2one('mrp.production', 'Manufacturing Order'),
|
'production_id': fields.many2one('mrp.production', 'Manufacturing Order'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None):
|
|
||||||
result = super(procurement_order, self)._prepare_order_line_procurement(cr, uid, order, line, move_id, date_planned, context)
|
|
||||||
result['property_ids'] = [(6, 0, [x.id for x in line.property_ids])]
|
|
||||||
return result
|
|
||||||
|
|
||||||
def check_produce_product(self, cr, uid, procurement, context=None):
|
def check_produce_product(self, cr, uid, procurement, context=None):
|
||||||
''' Depict the capacity of the procurement workflow to produce products (not services)'''
|
''' Depict the capacity of the procurement workflow to produce products (not services)'''
|
||||||
return True
|
return True
|
||||||
|
@ -126,6 +121,3 @@ class procurement_order(osv.osv):
|
||||||
for procurement in self.browse(cr, uid, ids, context=context):
|
for procurement in self.browse(cr, uid, ids, context=context):
|
||||||
body = _("Manufacturing Order <em>%s</em> created.") % ( procurement.production_id.name,)
|
body = _("Manufacturing Order <em>%s</em> created.") % ( procurement.production_id.name,)
|
||||||
self.message_post(cr, uid, [procurement.id], body=body, context=context)
|
self.message_post(cr, uid, [procurement.id], body=body, context=context)
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import logging
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.tools import email_re
|
from openerp.tools import email_split
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
@ -53,8 +53,8 @@ http://www.openerp.com
|
||||||
|
|
||||||
def extract_email(email):
|
def extract_email(email):
|
||||||
""" extract the email address from a user-friendly email address """
|
""" extract the email address from a user-friendly email address """
|
||||||
m = email_re.search(email or "")
|
addresses = email_split(email)
|
||||||
return m and m.group(0) or ""
|
return addresses[0] if addresses else ''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,12 @@ class TestPortalProjectBase(TestProjectBase):
|
||||||
'alias_name': 'donovan',
|
'alias_name': 'donovan',
|
||||||
'groups_id': [(6, 0, [self.group_anonymous_id])]
|
'groups_id': [(6, 0, [self.group_anonymous_id])]
|
||||||
})
|
})
|
||||||
|
self.user_manager_id = self.res_users.create(cr, uid, {
|
||||||
|
'name': 'Eustache Manager',
|
||||||
|
'login': 'eustache',
|
||||||
|
'alias_name': 'eustache',
|
||||||
|
'groups_id': [(6, 0, [self.group_project_manager_id])]
|
||||||
|
})
|
||||||
|
|
||||||
# Test 'Pigs' project
|
# Test 'Pigs' project
|
||||||
self.project_pigs_id = self.project_project.create(cr, uid, {
|
self.project_pigs_id = self.project_project.create(cr, uid, {
|
||||||
|
@ -220,7 +226,7 @@ class TestPortalProject(TestPortalProjectBase):
|
||||||
|
|
||||||
# Data: subscribe Alfred, Chell and Donovan as follower
|
# Data: subscribe Alfred, Chell and Donovan as follower
|
||||||
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_anonymous_id])
|
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_anonymous_id])
|
||||||
self.project_task.message_subscribe_users(cr, self.user_projectuser_id, [self.task_1_id, self.task_3_id], [self.user_portal_id, self.user_projectuser_id])
|
self.project_task.message_subscribe_users(cr, self.user_manager_id, [self.task_1_id, self.task_3_id], [self.user_portal_id, self.user_projectuser_id])
|
||||||
|
|
||||||
# Do: Alfred reads project -> ok (follower ok followers)
|
# Do: Alfred reads project -> ok (follower ok followers)
|
||||||
self.project_project.read(cr, self.user_projectuser_id, pigs_id, ['name'])
|
self.project_project.read(cr, self.user_projectuser_id, pigs_id, ['name'])
|
||||||
|
|
|
@ -159,7 +159,7 @@ class TestPortalIssue(TestPortalProjectBase):
|
||||||
|
|
||||||
# Data: subscribe Alfred, Chell and Donovan as follower
|
# Data: subscribe Alfred, Chell and Donovan as follower
|
||||||
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_anonymous_id])
|
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_anonymous_id])
|
||||||
self.project_issue.message_subscribe_users(cr, self.user_projectuser_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id, self.user_projectuser_id])
|
self.project_issue.message_subscribe_users(cr, self.user_manager_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id, self.user_projectuser_id])
|
||||||
|
|
||||||
# Do: Alfred reads project -> ok (follower ok followers)
|
# Do: Alfred reads project -> ok (follower ok followers)
|
||||||
# Test: followed + assigned issues visible
|
# Test: followed + assigned issues visible
|
||||||
|
|
|
@ -46,9 +46,15 @@ class project_task_type(osv.osv):
|
||||||
'there are no records in that stage to display.'),
|
'there are no records in that stage to display.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _get_default_project_ids(self, cr, uid, ctx={}):
|
||||||
|
project_id = self.pool['project.task']._get_default_project_id(cr, uid, context=ctx)
|
||||||
|
if project_id:
|
||||||
|
return [project_id]
|
||||||
|
return None
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'sequence': 1,
|
'sequence': 1,
|
||||||
'project_ids': lambda self, cr, uid, ctx=None: self.pool['project.task']._get_default_project_id(cr, uid, context=ctx),
|
'project_ids': _get_default_project_ids,
|
||||||
}
|
}
|
||||||
_order = 'sequence'
|
_order = 'sequence'
|
||||||
|
|
||||||
|
@ -64,7 +70,7 @@ class project(osv.osv):
|
||||||
""" Installation hook: aliases, project.project """
|
""" Installation hook: aliases, project.project """
|
||||||
# create aliases for all projects and avoid constraint errors
|
# create aliases for all projects and avoid constraint errors
|
||||||
alias_context = dict(context, alias_model_name='project.task')
|
alias_context = dict(context, alias_model_name='project.task')
|
||||||
self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(project, self)._auto_init,
|
return self.pool.get('mail.alias').migrate_to_alias(cr, self._name, self._table, super(project, self)._auto_init,
|
||||||
'project.task', self._columns['alias_id'], 'id', alias_prefix='project+', alias_defaults={'project_id':'id'}, context=alias_context)
|
'project.task', self._columns['alias_id'], 'id', alias_prefix='project+', alias_defaults={'project_id':'id'}, context=alias_context)
|
||||||
|
|
||||||
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import pytz
|
import pytz
|
||||||
from openerp import SUPERUSER_ID
|
from openerp import SUPERUSER_ID, workflow
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
@ -245,7 +245,7 @@ class purchase_order(osv.osv):
|
||||||
_name = "purchase.order"
|
_name = "purchase.order"
|
||||||
_inherit = ['mail.thread', 'ir.needaction_mixin']
|
_inherit = ['mail.thread', 'ir.needaction_mixin']
|
||||||
_description = "Purchase Order"
|
_description = "Purchase Order"
|
||||||
_order = "name desc"
|
_order = 'date_order desc, id desc'
|
||||||
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
if vals.get('name','/')=='/':
|
if vals.get('name','/')=='/':
|
||||||
|
@ -1290,6 +1290,7 @@ class account_invoice(osv.Model):
|
||||||
po_ids = purchase_order_obj.search(cr, user_id, [('invoice_ids', 'in', ids)], context=context)
|
po_ids = purchase_order_obj.search(cr, user_id, [('invoice_ids', 'in', ids)], context=context)
|
||||||
for po_id in po_ids:
|
for po_id in po_ids:
|
||||||
purchase_order_obj.message_post(cr, user_id, po_id, body=_("Invoice received"), context=context)
|
purchase_order_obj.message_post(cr, user_id, po_id, body=_("Invoice received"), context=context)
|
||||||
|
workflow.trg_write(uid, 'purchase.order', po_id, cr)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def confirm_paid(self, cr, uid, ids, context=None):
|
def confirm_paid(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -147,7 +147,7 @@
|
||||||
<record id="trans_router_invoice_no_order" model="workflow.transition">
|
<record id="trans_router_invoice_no_order" model="workflow.transition">
|
||||||
<field name="act_from" ref="act_router"/>
|
<field name="act_from" ref="act_router"/>
|
||||||
<field name="act_to" ref="act_invoice_end"/>
|
<field name="act_to" ref="act_invoice_end"/>
|
||||||
<field name="condition">invoice_method<>'order' and invoiced</field>
|
<field name="condition">invoice_method<>'order'</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="trans_except_picking_picking_done" model="workflow.transition">
|
<record id="trans_except_picking_picking_done" model="workflow.transition">
|
||||||
<field name="act_from" ref="act_except_picking"/>
|
<field name="act_from" ref="act_except_picking"/>
|
||||||
|
@ -200,6 +200,7 @@
|
||||||
<record id="trans_invoice_end_done" model="workflow.transition">
|
<record id="trans_invoice_end_done" model="workflow.transition">
|
||||||
<field name="act_from" ref="act_invoice_end"/>
|
<field name="act_from" ref="act_invoice_end"/>
|
||||||
<field name="act_to" ref="act_done"/>
|
<field name="act_to" ref="act_done"/>
|
||||||
|
<field name="condition">invoiced</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Procurement -->
|
<!-- Procurement -->
|
||||||
|
|
|
@ -238,7 +238,7 @@ class sale_order(osv.osv):
|
||||||
_sql_constraints = [
|
_sql_constraints = [
|
||||||
('name_uniq', 'unique(name, company_id)', 'Order Reference must be unique per Company!'),
|
('name_uniq', 'unique(name, company_id)', 'Order Reference must be unique per Company!'),
|
||||||
]
|
]
|
||||||
_order = 'name desc'
|
_order = 'date_order desc, id desc'
|
||||||
|
|
||||||
# Form filling
|
# Form filling
|
||||||
def unlink(self, cr, uid, ids, context=None):
|
def unlink(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -88,4 +88,10 @@ class mrp_production(osv.osv):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
class sale_order(osv.Model):
|
||||||
|
_inherit ='sale.order'
|
||||||
|
|
||||||
|
def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None):
|
||||||
|
result = super(sale_order, self)._prepare_order_line_procurement(cr, uid, order, line, move_id, date_planned, context)
|
||||||
|
result['property_ids'] = [(6, 0, [x.id for x in line.property_ids])]
|
||||||
|
return result
|
||||||
|
|
|
@ -124,10 +124,22 @@ class stock_picking(osv.osv):
|
||||||
|
|
||||||
def _invoice_hook(self, cursor, user, picking, invoice_id):
|
def _invoice_hook(self, cursor, user, picking, invoice_id):
|
||||||
sale_obj = self.pool.get('sale.order')
|
sale_obj = self.pool.get('sale.order')
|
||||||
|
order_line_obj = self.pool.get('sale.order.line')
|
||||||
|
invoice_obj = self.pool.get('account.invoice')
|
||||||
|
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||||
if picking.sale_id:
|
if picking.sale_id:
|
||||||
sale_obj.write(cursor, user, [picking.sale_id.id], {
|
sale_obj.write(cursor, user, [picking.sale_id.id], {
|
||||||
'invoice_ids': [(4, invoice_id)],
|
'invoice_ids': [(4, invoice_id)],
|
||||||
})
|
})
|
||||||
|
for sale_line in picking.sale_id.order_line:
|
||||||
|
if sale_line.product_id.type == 'service' and not sale_line.invoiced:
|
||||||
|
vals = order_line_obj._prepare_order_line_invoice_line(cursor, user, sale_line, False)
|
||||||
|
vals['invoice_id'] = invoice_id
|
||||||
|
invoice_line_id = invoice_line_obj.create(cursor, user, vals)
|
||||||
|
order_line_obj.write(cursor, user, [sale_line.id], {
|
||||||
|
'invoice_lines': [(6, 0, [invoice_line_id])],
|
||||||
|
})
|
||||||
|
invoice_obj.button_compute(cursor, user, [invoice_id])
|
||||||
return super(stock_picking, self)._invoice_hook(cursor, user, picking, invoice_id)
|
return super(stock_picking, self)._invoice_hook(cursor, user, picking, invoice_id)
|
||||||
|
|
||||||
def action_done(self, cr, uid, ids, context=None):
|
def action_done(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -3,6 +3,16 @@
|
||||||
-
|
-
|
||||||
!context
|
!context
|
||||||
uid: 'res_sale_stock_salesman'
|
uid: 'res_sale_stock_salesman'
|
||||||
|
-
|
||||||
|
Add SO line with service type product in SO to check flow which contain service type product in SO(BUG#1167330).
|
||||||
|
-
|
||||||
|
!record {model: sale.order.line, id: sale_order_1}:
|
||||||
|
name: 'On Site Assistance'
|
||||||
|
product_id: product.product_product_2
|
||||||
|
product_uom_qty: 1.0
|
||||||
|
product_uom: 1
|
||||||
|
price_unit: 150.0
|
||||||
|
order_id: sale.sale_order_6
|
||||||
-
|
-
|
||||||
First I check the total amount of the Quotation before Approved.
|
First I check the total amount of the Quotation before Approved.
|
||||||
-
|
-
|
||||||
|
@ -75,7 +85,7 @@
|
||||||
assert picking.partner_id.id == sale_order.partner_shipping_id.id,"Shipping Address is not correspond with sale order."
|
assert picking.partner_id.id == sale_order.partner_shipping_id.id,"Shipping Address is not correspond with sale order."
|
||||||
assert picking.note == sale_order.note,"Note is not correspond with sale order."
|
assert picking.note == sale_order.note,"Note is not correspond with sale order."
|
||||||
assert picking.invoice_state == (sale_order.order_policy=='picking' and '2binvoiced') or 'none',"Invoice policy is not correspond with sale order."
|
assert picking.invoice_state == (sale_order.order_policy=='picking' and '2binvoiced') or 'none',"Invoice policy is not correspond with sale order."
|
||||||
assert len(picking.move_lines) == len(sale_order.order_line), "Total move of delivery order are not corresposning with total sale order lines."
|
assert len(picking.move_lines) == len(sale_order.order_line) - 1, "Total move of delivery order are not corresposning with total sale order lines."
|
||||||
location_id = sale_order.warehouse_id.lot_stock_id.id
|
location_id = sale_order.warehouse_id.lot_stock_id.id
|
||||||
output_id = sale_order.warehouse_id.lot_output_id.id
|
output_id = sale_order.warehouse_id.lot_output_id.id
|
||||||
for move in picking.move_lines:
|
for move in picking.move_lines:
|
||||||
|
|
|
@ -144,7 +144,7 @@ class stock_partial_picking(osv.osv_memory):
|
||||||
def _partial_move_for(self, cr, uid, move):
|
def _partial_move_for(self, cr, uid, move):
|
||||||
partial_move = {
|
partial_move = {
|
||||||
'product_id' : move.product_id.id,
|
'product_id' : move.product_id.id,
|
||||||
'quantity' : move.product_qty if move.state == 'assigned' else 0,
|
'quantity' : move.product_qty if move.state == 'assigned' or move.picking_id.type == 'in' else 0,
|
||||||
'product_uom' : move.product_uom.id,
|
'product_uom' : move.product_uom.id,
|
||||||
'prodlot_id' : move.prodlot_id.id,
|
'prodlot_id' : move.prodlot_id.id,
|
||||||
'move_id' : move.id,
|
'move_id' : move.id,
|
||||||
|
|
Loading…
Reference in New Issue