diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index 7fffc4f07d4..43aaa2f58c1 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -133,7 +133,9 @@ for a particular financial year and for preparation of vouchers there is a modul "static/src/xml/account_move_reconciliation.xml", "static/src/xml/account_move_line_quickadd.xml", ], - 'css':['static/src/css/account_move_reconciliation.css' + 'css':[ + 'static/src/css/account_move_reconciliation.css', + 'static/src/css/account_move_line_quickadd.css' ], 'demo': [ 'demo/account_demo.xml', diff --git a/addons/account/account.py b/addons/account/account.py index 22f2b3bda9c..a724ebc3cc7 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -19,19 +19,19 @@ # ############################################################################## -import time +import logging from datetime import datetime from dateutil.relativedelta import relativedelta from operator import itemgetter +import time -import logging -import pooler -from osv import fields, osv -import decimal_precision as dp -from tools.translate import _ -from tools.float_utils import float_round from openerp import SUPERUSER_ID -import tools +from openerp import pooler, tools +from openerp.osv import fields, osv +from openerp.tools.translate import _ +from openerp.tools.float_utils import float_round + +import openerp.addons.decimal_precision as dp _logger = logging.getLogger(__name__) @@ -1014,10 +1014,15 @@ class account_period(osv.osv): else: company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id args.append(('company_id', '=', company_id)) - ids = self.search(cr, uid, args, context=context) - if not ids: - raise osv.except_osv(_('Error!'), _('There is no period defined for this date: %s.\nPlease create one.')%dt) - return ids + result = [] + if context.get('account_period_prefer_normal'): + # look for non-special periods first, and fallback to all if no result is found + result = self.search(cr, uid, args + [('special', '=', False)], context=context) + if not result: + result = self.search(cr, uid, args, context=context) + if not result: + raise osv.except_osv(_('Error !'), _('There is no period defined for this date: %s.\nPlease create one.')%dt) + return result def action_draft(self, cr, uid, ids, *args): mode = 'draft' @@ -1191,10 +1196,9 @@ class account_move(osv.osv): return res def _get_period(self, cr, uid, context=None): - periods = self.pool.get('account.period').find(cr, uid) - if periods: - return periods[0] - return False + ctx = dict(context or {}, account_period_prefer_normal=True) + period_ids = self.pool.get('account.period').find(cr, uid, context=ctx) + return period_ids[0] def _amount_compute(self, cr, uid, ids, name, args, context, where =''): if not ids: return {} @@ -3348,10 +3352,25 @@ class wizard_multi_charts_accounts(osv.osv_memory): all the provided information to create the accounts, the banks, the journals, the taxes, the tax codes, the accounting properties... accordingly for the chosen company. ''' + obj_data = self.pool.get('ir.model.data') ir_values_obj = self.pool.get('ir.values') obj_wizard = self.browse(cr, uid, ids[0]) company_id = obj_wizard.company_id.id + self.pool.get('res.company').write(cr, uid, [company_id], {'currency_id': obj_wizard.currency_id.id}) + + # When we install the CoA of first company, set the currency to price types and pricelists + if company_id==1: + for ref in (('product','list_price'),('product','standard_price'),('product','list0'),('purchase','list0')): + try: + tmp2 = obj_data.get_object_reference(cr, uid, *ref) + if tmp2: + self.pool.get(tmp2[0]).write(cr, uid, tmp2[1], { + 'currency_id': obj_wizard.currency_id.id + }) + except ValueError, e: + pass + # If the floats for sale/purchase rates have been filled, create templates from them self._create_tax_templates_from_rates(cr, uid, obj_wizard, company_id, context=context) diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py index 066f8d1abec..f3617106f28 100644 --- a/addons/account/account_analytic_line.py +++ b/addons/account/account_analytic_line.py @@ -19,9 +19,9 @@ # ############################################################################## -from osv import fields -from osv import osv -from tools.translate import _ +from openerp.osv import fields +from openerp.osv import osv +from openerp.tools.translate import _ class account_analytic_line(osv.osv): _inherit = 'account.analytic.line' @@ -82,7 +82,7 @@ class account_analytic_line(osv.osv): if j_id.type == 'purchase': unit = prod.uom_po_id.id if j_id.type <> 'sale': - a = prod.product_tmpl_id.property_account_expense.id + a = prod.property_account_expense.id if not a: a = prod.categ_id.property_account_expense_categ.id if not a: @@ -91,7 +91,7 @@ class account_analytic_line(osv.osv): 'for this product: "%s" (id:%d).') % \ (prod.name, prod.id,)) else: - a = prod.product_tmpl_id.property_account_income.id + a = prod.property_account_income.id if not a: a = prod.categ_id.property_account_income_categ.id if not a: diff --git a/addons/account/account_bank.py b/addons/account/account_bank.py index f0da630ec1d..f2bc9a5c9a1 100644 --- a/addons/account/account_bank.py +++ b/addons/account/account_bank.py @@ -19,8 +19,8 @@ # ############################################################################## -from tools.translate import _ -from osv import fields, osv +from openerp.tools.translate import _ +from openerp.osv import fields, osv class bank(osv.osv): _inherit = "res.partner.bank" diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index e7e3f740067..d1e25029f4f 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -21,9 +21,9 @@ import time -from osv import fields, osv -from tools.translate import _ -import decimal_precision as dp +from openerp.osv import fields, osv +from openerp.tools.translate import _ +import openerp.addons.decimal_precision as dp class account_bank_statement(osv.osv): def create(self, cr, uid, vals, context=None): @@ -439,10 +439,11 @@ class account_bank_statement(osv.osv): for st in self.browse(cr, uid, ids, context=context): if st.state=='draft': continue - ids = [] + move_ids = [] for line in st.line_ids: - ids += [x.id for x in line.move_ids] - account_move_obj.unlink(cr, uid, ids, context) + move_ids += [x.id for x in line.move_ids] + account_move_obj.button_cancel(cr, uid, move_ids, context=context) + account_move_obj.unlink(cr, uid, move_ids, context) done.append(st.id) return self.write(cr, uid, done, {'state':'draft'}, context=context) @@ -546,7 +547,7 @@ class account_bank_statement_line(osv.osv): _name = "account.bank.statement.line" _description = "Bank Statement Line" _columns = { - 'name': fields.char('Communication', size=64, required=True), + 'name': fields.char('Communication', required=True), 'date': fields.date('Date', required=True), 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), 'type': fields.selection([ diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py index c1f30824461..a100c0e60ba 100644 --- a/addons/account/account_cash_statement.py +++ b/addons/account/account_cash_statement.py @@ -22,9 +22,9 @@ import time -from osv import osv, fields -from tools.translate import _ -import decimal_precision as dp +from openerp.osv import fields, osv +from openerp.tools.translate import _ +import openerp.addons.decimal_precision as dp class account_cashbox_line(osv.osv): diff --git a/addons/account/account_financial_report.py b/addons/account/account_financial_report.py index 62bcf9dcbcd..28b5e08dc99 100644 --- a/addons/account/account_financial_report.py +++ b/addons/account/account_financial_report.py @@ -24,11 +24,11 @@ from datetime import datetime from dateutil.relativedelta import relativedelta from operator import itemgetter -import netsvc -import pooler -from osv import fields, osv -import decimal_precision as dp -from tools.translate import _ +from openerp import netsvc +from openerp import pooler +from openerp.osv import fields, osv +import openerp.addons.decimal_precision as dp +from openerp.tools.translate import _ # --------------------------------------------------------- # Account Financial Report diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index cdd340ef551..7843a096940 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -21,12 +21,12 @@ import time from lxml import etree -import decimal_precision as dp +import openerp.addons.decimal_precision as dp -import netsvc -import pooler -from osv import fields, osv, orm -from tools.translate import _ +from openerp import netsvc +from openerp import pooler +from openerp.osv import fields, osv, orm +from openerp.tools.translate import _ class account_invoice(osv.osv): def _amount_all(self, cr, uid, ids, name, args, context=None): @@ -184,7 +184,14 @@ class account_invoice(osv.osv): _inherit = ['mail.thread'] _description = 'Invoice' _order = "id desc" - + _track = { + 'type': { + }, + 'state': { + 'account.mt_invoice_paid': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'paid' and obj['type'] in ('out_invoice', 'out_refund'), + 'account.mt_invoice_validated': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'open' and obj['type'] in ('out_invoice', 'out_refund'), + }, + } _columns = { 'name': fields.char('Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}), 'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}), @@ -194,7 +201,7 @@ class account_invoice(osv.osv): ('in_invoice','Supplier Invoice'), ('out_refund','Customer Refund'), ('in_refund','Supplier Refund'), - ],'Type', readonly=True, select=True, change_default=True), + ],'Type', readonly=True, select=True, change_default=True, track_visibility='always'), 'number': fields.related('move_id','name', type='char', readonly=True, size=64, relation='account.move', store=True, string='Number'), 'internal_number': fields.char('Invoice Number', size=32, readonly=True, help="Unique number of the invoice, computed automatically when the invoice is created."), @@ -210,7 +217,7 @@ class account_invoice(osv.osv): ('open','Open'), ('paid','Paid'), ('cancel','Cancelled'), - ],'Status', select=True, readonly=True, + ],'Status', select=True, readonly=True, track_visibility='onchange', help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed Invoice. \ \n* The \'Pro-forma\' when invoice is in Pro-forma status,invoice does not have an invoice number. \ \n* The \'Open\' status is used when user create invoice,a invoice number is generated.Its in open status till user does not pay invoice. \ @@ -221,7 +228,7 @@ class account_invoice(osv.osv): 'date_due': fields.date('Due Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, help="If you use payment terms, the due date will be computed automatically at the generation "\ "of accounting entries. The payment term may compute several due dates, for example 50% now and 50% in one month, but if you want to force a due date, make sure that the payment term is not set on the invoice. If you keep the payment term and the due date empty, it means direct payment."), - 'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}), + 'partner_id': fields.many2one('res.partner', 'Partner', change_default=True, readonly=True, required=True, states={'draft':[('readonly',False)]}, track_visibility='always'), 'payment_term': fields.many2one('account.payment.term', 'Payment Term',readonly=True, states={'draft':[('readonly',False)]}, help="If you use payment terms, the due date will be computed automatically at the generation "\ "of accounting entries. If you keep the payment term and the due date empty, it means direct payment. "\ @@ -233,7 +240,7 @@ class account_invoice(osv.osv): 'tax_line': fields.one2many('account.invoice.tax', 'invoice_id', 'Tax Lines', readonly=True, states={'draft':[('readonly',False)]}), 'move_id': fields.many2one('account.move', 'Journal Entry', readonly=True, select=1, ondelete='restrict', help="Link to the automatically generated Journal Items."), - 'amount_untaxed': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Untaxed', + 'amount_untaxed': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Untaxed', track_visibility='always', store={ 'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line'], 20), 'account.invoice.tax': (_get_invoice_tax, None, 20), @@ -254,7 +261,7 @@ class account_invoice(osv.osv): 'account.invoice.line': (_get_invoice_line, ['price_unit','invoice_line_tax_id','quantity','discount','invoice_id'], 20), }, multi='all'), - 'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}), + 'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}, track_visibility='always'), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'company_id': fields.many2one('res.company', 'Company', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}), 'check_total': fields.float('Verification Total', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}), @@ -278,7 +285,7 @@ class account_invoice(osv.osv): help="Remaining amount due."), 'payment_ids': fields.function(_compute_lines, relation='account.move.line', type="many2many", string='Payments'), 'move_name': fields.char('Journal Entry', size=64, readonly=True, states={'draft':[('readonly',False)]}), - 'user_id': fields.many2one('res.users', 'Salesperson', readonly=True, states={'draft':[('readonly',False)]}), + 'user_id': fields.many2one('res.users', 'Salesperson', readonly=True, track_visibility='onchange', states={'draft':[('readonly',False)]}), 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]}) } _defaults = { @@ -373,10 +380,7 @@ class account_invoice(osv.osv): if context is None: context = {} try: - res = super(account_invoice, self).create(cr, uid, vals, context) - if res: - self.create_send_note(cr, uid, [res], context=context) - return res + return super(account_invoice, self).create(cr, uid, vals, context) except Exception, e: if '"journal_id" viol' in e.args[0]: raise orm.except_orm(_('Configuration Error!'), @@ -440,7 +444,6 @@ class account_invoice(osv.osv): if context is None: context = {} self.write(cr, uid, ids, {'state':'paid'}, context=context) - self.confirm_paid_send_note(cr, uid, ids, context=context) return True def unlink(self, cr, uid, ids, context=None): @@ -994,7 +997,8 @@ class account_invoice(osv.osv): 'narration':inv.comment } period_id = inv.period_id and inv.period_id.id or False - ctx.update({'company_id': inv.company_id.id}) + ctx.update(company_id=inv.company_id.id, + account_period_prefer_normal=True) if not period_id: period_ids = period_obj.find(cr, uid, inv.date_invoice, context=ctx) period_id = period_ids and period_ids[0] or False @@ -1046,13 +1050,12 @@ class account_invoice(osv.osv): self.write(cr, uid, ids, {}) for obj_inv in self.browse(cr, uid, ids, context=context): - id = obj_inv.id invtype = obj_inv.type number = obj_inv.number move_id = obj_inv.move_id and obj_inv.move_id.id or False reference = obj_inv.reference or '' - self.write(cr, uid, ids, {'internal_number':number}) + self.write(cr, uid, ids, {'internal_number': number}) if invtype in ('in_invoice', 'in_refund'): if not reference: @@ -1073,13 +1076,6 @@ class account_invoice(osv.osv): 'WHERE account_move_line.move_id = %s ' \ 'AND account_analytic_line.move_id = account_move_line.id', (ref, move_id)) - - for inv_id, name in self.name_get(cr, uid, [id]): - ctx = context.copy() - if obj_inv.type in ('out_invoice', 'out_refund'): - ctx = self.get_log_context(cr, uid, context=ctx) - message = _("Invoice '%s' is validated.") % name - self.message_post(cr, uid, [inv_id], body=message, context=context) return True def action_cancel(self, cr, uid, ids, context=None): @@ -1108,7 +1104,6 @@ class account_invoice(osv.osv): # will be automatically deleted too account_move_obj.unlink(cr, uid, move_ids, context=context) self._log_event(cr, uid, ids, -1.0, 'Cancel Invoice') - self.invoice_cancel_send_note(cr, uid, ids, context=context) return True ################### @@ -1149,73 +1144,92 @@ class account_invoice(osv.osv): ids = self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context) return self.name_get(cr, user, ids, context) - def _refund_cleanup_lines(self, cr, uid, lines): + def _refund_cleanup_lines(self, cr, uid, lines, context=None): + clean_lines = [] for line in lines: - del line['id'] - del line['invoice_id'] - for field in ('company_id', 'partner_id', 'account_id', 'product_id', - 'uos_id', 'account_analytic_id', 'tax_code_id', 'base_code_id'): - if line.get(field): - line[field] = line[field][0] - if 'invoice_line_tax_id' in line: - line['invoice_line_tax_id'] = [(6,0, line.get('invoice_line_tax_id', [])) ] - return map(lambda x: (0,0,x), lines) + clean_line = {} + for field in line._all_columns.keys(): + if line._all_columns[field].column._type == 'many2one': + clean_line[field] = line[field].id + elif line._all_columns[field].column._type not in ['many2many','one2many']: + clean_line[field] = line[field] + elif field == 'invoice_line_tax_id': + tax_list = [] + for tax in line[field]: + tax_list.append(tax.id) + clean_line[field] = [(6,0, tax_list)] + clean_lines.append(clean_line) + return map(lambda x: (0,0,x), clean_lines) - def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None): - invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id', 'company_id', 'user_id', 'fiscal_position']) - obj_invoice_line = self.pool.get('account.invoice.line') - obj_invoice_tax = self.pool.get('account.invoice.tax') + def _prepare_refund(self, cr, uid, invoice, date=None, period_id=None, description=None, journal_id=None, context=None): + """Prepare the dict of values to create the new refund from the invoice. + This method may be overridden to implement custom + refund generation (making sure to call super() to establish + a clean extension chain). + + :param integer invoice_id: id of the invoice to refund + :param dict invoice: read of the invoice to refund + :param string date: refund creation date from the wizard + :param integer period_id: force account.period from the wizard + :param string description: description of the refund from the wizard + :param integer journal_id: account.journal from the wizard + :return: dict of value to create() the refund + """ obj_journal = self.pool.get('account.journal') - new_ids = [] - for invoice in invoices: - del invoice['id'] - type_dict = { - 'out_invoice': 'out_refund', # Customer Invoice - 'in_invoice': 'in_refund', # Supplier Invoice - 'out_refund': 'out_invoice', # Customer Refund - 'in_refund': 'in_invoice', # Supplier Refund - } - - invoice_lines = obj_invoice_line.read(cr, uid, invoice['invoice_line']) - invoice_lines = self._refund_cleanup_lines(cr, uid, invoice_lines) - - tax_lines = obj_invoice_tax.read(cr, uid, invoice['tax_line']) - tax_lines = filter(lambda l: l['manual'], tax_lines) - tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines) - if journal_id: - refund_journal_ids = [journal_id] - elif invoice['type'] == 'in_invoice': - refund_journal_ids = obj_journal.search(cr, uid, [('type','=','purchase_refund')]) + type_dict = { + 'out_invoice': 'out_refund', # Customer Invoice + 'in_invoice': 'in_refund', # Supplier Invoice + 'out_refund': 'out_invoice', # Customer Refund + 'in_refund': 'in_invoice', # Supplier Refund + } + invoice_data = {} + for field in ['name', 'reference', 'comment', 'date_due', 'partner_id', 'company_id', + 'account_id', 'currency_id', 'payment_term', 'user_id', 'fiscal_position']: + if invoice._all_columns[field].column._type == 'many2one': + invoice_data[field] = invoice[field].id else: - refund_journal_ids = obj_journal.search(cr, uid, [('type','=','sale_refund')]) + invoice_data[field] = invoice[field] if invoice[field] else False - if not date: - date = time.strftime('%Y-%m-%d') - invoice.update({ - 'type': type_dict[invoice['type']], - 'date_invoice': date, - 'state': 'draft', - 'number': False, - 'invoice_line': invoice_lines, - 'tax_line': tax_lines, - 'journal_id': refund_journal_ids - }) - if period_id: - invoice.update({ - 'period_id': period_id, - }) - if description: - invoice.update({ - 'name': description, - }) - # take the id part of the tuple returned for many2one fields - for field in ('partner_id', 'company_id', - 'account_id', 'currency_id', 'payment_term', 'journal_id', - 'user_id', 'fiscal_position'): - invoice[field] = invoice[field] and invoice[field][0] + invoice_lines = self._refund_cleanup_lines(cr, uid, invoice.invoice_line, context=context) + + tax_lines = filter(lambda l: l['manual'], invoice.tax_line) + tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines, context=context) + if journal_id: + refund_journal_ids = [journal_id] + elif invoice['type'] == 'in_invoice': + refund_journal_ids = obj_journal.search(cr, uid, [('type','=','purchase_refund')], context=context) + else: + refund_journal_ids = obj_journal.search(cr, uid, [('type','=','sale_refund')], context=context) + + if not date: + date = time.strftime('%Y-%m-%d') + invoice_data.update({ + 'type': type_dict[invoice['type']], + 'date_invoice': date, + 'state': 'draft', + 'number': False, + 'invoice_line': invoice_lines, + 'tax_line': tax_lines, + 'journal_id': refund_journal_ids and refund_journal_ids[0] or False, + }) + if period_id: + invoice_data['period_id'] = period_id + if description: + invoice_data['name'] = description + return invoice_data + + def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None, context=None): + new_ids = [] + for invoice in self.browse(cr, uid, ids, context=context): + invoice = self._prepare_refund(cr, uid, invoice, + date=date, + period_id=period_id, + description=description, + journal_id=journal_id, + context=context) # create the new invoice - new_ids.append(self.create(cr, uid, invoice)) + new_ids.append(self.create(cr, uid, invoice, context=context)) return new_ids @@ -1312,8 +1326,8 @@ class account_invoice(osv.osv): else: code = invoice.currency_id.symbol # TODO: use currency's formatting function - msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining).") % \ - (name, pay_amount, code, invoice.amount_total, code, total, code) + msg = _("Invoice partially paid: %s%s of %s%s (%s%s remaining).") % \ + (pay_amount, code, invoice.amount_total, code, total, code) self.message_post(cr, uid, [inv_id], body=msg, context=context) self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context) @@ -1321,35 +1335,6 @@ class account_invoice(osv.osv): self.pool.get('account.invoice').write(cr, uid, ids, {}, context=context) return True - # ----------------------------------------- - # OpenChatter notifications and need_action - # ----------------------------------------- - - def _get_document_type(self, type): - type_dict = { - # Translation markers will have no effect at runtime, only used to properly flag export - 'out_invoice': _('Customer invoice'), - 'in_invoice': _('Supplier invoice'), - 'out_refund': _('Customer Refund'), - 'in_refund': _('Supplier Refund'), - } - return type_dict.get(type, 'Invoice') - - 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 created.") % (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 paid.") % (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 cancelled.") % (self._get_document_type(obj.type)), - context=context) - class account_invoice_line(osv.osv): @@ -1456,11 +1441,11 @@ class account_invoice_line(osv.osv): res = self.pool.get('product.product').browse(cr, uid, product, context=context) if type in ('out_invoice','out_refund'): - a = res.product_tmpl_id.property_account_income.id + a = res.property_account_income.id if not a: a = res.categ_id.property_account_income_categ.id else: - a = res.product_tmpl_id.property_account_expense.id + a = res.property_account_expense.id if not a: a = res.categ_id.property_account_expense_categ.id a = fpos_obj.map_account(cr, uid, fpos, a) @@ -1759,12 +1744,13 @@ class res_partner(osv.osv): return super(res_partner, self).copy(cr, uid, id, default, context) -class mail_compose_message(osv.osv): +class mail_compose_message(osv.Model): _inherit = 'mail.compose.message' def send_mail(self, cr, uid, ids, context=None): context = context or {} if context.get('default_model') == 'account.invoice' and context.get('default_res_id') and context.get('mark_invoice_as_sent'): + context = dict(context, mail_post_autofollow=True) self.pool.get('account.invoice').write(cr, uid, [context['default_res_id']], {'sent': True}, context=context) return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 48fec608195..6ca7c21a6e4 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -145,7 +145,8 @@
- -