diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index fba1bd8736f..cd19c730a3f 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -23,7 +23,6 @@ "version" : "1.1", "author" : "OpenERP SA", "category": 'Accounting & Finance', - 'complexity': "easy", "description": """ Accounting and Financial Management. ==================================== @@ -106,6 +105,7 @@ module named account_voucher. 'partner_view.xml', 'data/account_data.xml', 'data/data_account_type.xml', + 'data/configurable_account_chart.xml', 'account_invoice_workflow.xml', 'project/project_view.xml', 'project/project_report.xml', diff --git a/addons/account/account.py b/addons/account/account.py index 75bfc891980..d501f35cbc7 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -893,7 +893,7 @@ class account_fiscalyear(osv.osv): 'date_start': fields.date('Start Date', required=True), 'date_stop': fields.date('End Date', required=True), 'period_ids': fields.one2many('account.period', 'fiscalyear_id', 'Periods'), - 'state': fields.selection([('draft','Open'), ('done','Closed')], 'State', readonly=True), + 'state': fields.selection([('draft','Open'), ('done','Closed')], 'Status', readonly=True), } _defaults = { 'state': 'draft', @@ -990,7 +990,7 @@ class account_period(osv.osv): 'date_start': fields.date('Start of Period', required=True, states={'done':[('readonly',True)]}), 'date_stop': fields.date('End of Period', required=True, states={'done':[('readonly',True)]}), 'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True), - 'state': fields.selection([('draft','Open'), ('done','Closed')], 'State', readonly=True, + 'state': fields.selection([('draft','Open'), ('done','Closed')], 'Status', readonly=True, help='When monthly periods are created. The state is \'Draft\'. At the end of monthly period it is in \'Done\' state.'), 'company_id': fields.related('fiscalyear_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) } @@ -1117,7 +1117,7 @@ class account_journal_period(osv.osv): 'period_id': fields.many2one('account.period', 'Period', required=True, ondelete="cascade"), 'icon': fields.function(_icon_get, string='Icon', type='char', size=32), 'active': fields.boolean('Active', required=True, help="If the active field is set to False, it will allow you to hide the journal period without removing it."), - 'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'State', required=True, readonly=True, + 'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'Status', required=True, readonly=True, help='When journal period is created. The state is \'Draft\'. If a report is printed it comes to \'Printed\' state. When all transactions are done, it comes in \'Done\' state.'), 'fiscalyear_id': fields.related('period_id', 'fiscalyear_id', string='Fiscal Year', type='many2one', relation='account.fiscalyear'), 'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True) @@ -1264,7 +1264,7 @@ class account_move(osv.osv): 'ref': fields.char('Reference', size=64), 'period_id': fields.many2one('account.period', 'Period', required=True, states={'posted':[('readonly',True)]}), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'posted':[('readonly',True)]}), - 'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'State', required=True, readonly=True, + 'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'Status', required=True, readonly=True, help='All manually created new journal entries are usually in the state \'Unposted\', but you can set the option to skip that state on the related journal. In that case, they will be behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' state.'), 'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}), 'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'), @@ -2350,7 +2350,7 @@ class account_subscription(osv.osv): 'period_total': fields.integer('Number of Periods', required=True), 'period_nbr': fields.integer('Period', required=True), 'period_type': fields.selection([('day','days'),('month','month'),('year','year')], 'Period Type', required=True), - 'state': fields.selection([('draft','Draft'),('running','Running'),('done','Done')], 'State', required=True, readonly=True), + 'state': fields.selection([('draft','Draft'),('running','Running'),('done','Done')], 'Status', required=True, readonly=True), 'lines_id': fields.one2many('account.subscription.line', 'subscription_id', 'Subscription Lines') } _defaults = { @@ -2905,7 +2905,7 @@ class account_fiscal_position_template(osv.osv): obj_fiscal_position = self.pool.get('account.fiscal.position') fp_ids = self.search(cr, uid, [('chart_template_id', '=', chart_temp_id)]) for position in self.browse(cr, uid, fp_ids, context=context): - new_fp = obj_fiscal_position.create(cr, uid, {'company_id': company_id, 'name': position.name}) + new_fp = obj_fiscal_position.create(cr, uid, {'company_id': company_id, 'name': position.name, 'note': position.note}) for tax in position.tax_ids: obj_tax_fp.create(cr, uid, { 'tax_src_id': tax_template_ref[tax.tax_src_id.id], diff --git a/addons/account/account_analytic_line.py b/addons/account/account_analytic_line.py index da0bc96bda9..280b813380f 100644 --- a/addons/account/account_analytic_line.py +++ b/addons/account/account_analytic_line.py @@ -27,7 +27,7 @@ class account_analytic_line(osv.osv): _inherit = 'account.analytic.line' _description = 'Analytic Line' _columns = { - 'product_uom_id': fields.many2one('product.uom', 'UoM'), + 'product_uom_id': fields.many2one('product.uom', 'Unit of Measure'), 'product_id': fields.many2one('product.product', 'Product'), 'general_account_id': fields.many2one('account.account', 'General Account', required=True, ondelete='restrict'), 'move_id': fields.many2one('account.move.line', 'Move Line', ondelete='cascade', select=True), diff --git a/addons/account/account_bank_statement.py b/addons/account/account_bank_statement.py index 5601179e0fc..1f47a6be9bd 100644 --- a/addons/account/account_bank_statement.py +++ b/addons/account/account_bank_statement.py @@ -127,6 +127,7 @@ class account_bank_statement(osv.osv): _order = "date desc, id desc" _name = "account.bank.statement" _description = "Bank Statement" + _inherit = ['mail.thread'] _columns = { 'name': fields.char('Name', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement 'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True), @@ -153,7 +154,7 @@ class account_bank_statement(osv.osv): 'state': fields.selection([('draft', 'New'), ('open','Open'), # used by cash statements ('confirm', 'Closed')], - 'State', required=True, readonly="1", + 'Status', required=True, readonly="1", help='When new statement is created the state will be \'Draft\'.\n' 'And after getting confirmation from the bank it will be in \'Confirmed\' state.'), 'currency': fields.function(_currency, string='Currency', @@ -364,7 +365,7 @@ class account_bank_statement(osv.osv): 'name': st_number, 'balance_end_real': st.balance_end }, context=context) - self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,)) + self.message_append_note(cr, uid, [st.id], body=_('Statement %s is confirmed, journal items are created.') % (st_number,), context=context) return self.write(cr, uid, ids, {'state':'confirm'}, context=context) def button_cancel(self, cr, uid, ids, context=None): diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index d0f7579a86e..c6011979f8d 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -205,13 +205,14 @@ class account_invoice(osv.osv): ('proforma2','Pro-forma'), ('open','Open'), ('paid','Paid'), - ('cancel','Cancelled') + ('cancel','Cancelled'), ],'State', select=True, readonly=True, help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Invoice. \ \n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \ \n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \ \n* The \'Paid\' state is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \ \n* The \'Cancelled\' state is used when user cancel invoice.'), + 'sent': fields.boolean('Sent', readonly=True, help="It indicates that the invoice has been sent."), 'date_invoice': fields.date('Invoice Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, help="Keep empty to use the current date"), 'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True, help="If you use payment terms, the due date will be computed automatically at the generation "\ @@ -273,7 +274,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', 'Salesman', readonly=True, states={'draft':[('readonly',False)]}), + 'user_id': fields.many2one('res.users', 'Salesperson', readonly=True, states={'draft':[('readonly',False)]}), 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position', readonly=True, states={'draft':[('readonly',False)]}) } _defaults = { @@ -286,6 +287,7 @@ class account_invoice(osv.osv): 'check_total': 0.0, 'internal_number': False, 'user_id': lambda s, cr, u, c: u, + 'sent': False, } _sql_constraints = [ ('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'), @@ -366,6 +368,47 @@ class account_invoice(osv.osv): else: raise orm.except_orm(_('Unknown Error'), str(e)) + def invoice_print(self, cr, uid, ids, context=None): + ''' + This function prints the invoice and mark it as sent, so that we can see more easily the next step of the workflow + ''' + assert len(ids) == 1, 'This option should only be used for a single id at a time' + self.write(cr, uid, ids, {'sent': True}, context=context) + datas = { + 'ids': ids, + 'model': 'account.invoice', + 'form': self.read(cr, uid, ids[0], context=context) + } + return { + 'type': 'ir.actions.report.xml', + 'report_name': 'account.invoice', + 'datas': datas, + 'nodestroy' : True + } + + def action_invoice_sent(self, cr, uid, ids, context=None): + ''' + This function opens a window to compose an email, with the edi invoice template message loaded by default + ''' + mod_obj = self.pool.get('ir.model.data') + template = mod_obj.get_object_reference(cr, uid, 'account', 'email_template_edi_invoice') + template_id = template and template[1] or False + res = mod_obj.get_object_reference(cr, uid, 'mail', 'email_compose_message_wizard_form') + res_id = res and res[1] or False + ctx = dict(context, active_model='account.invoice', active_id=ids[0]) + ctx.update({'mail.compose.template_id': template_id}) + return { + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(res_id, 'form')], + 'view_id': res_id, + 'type': 'ir.actions.act_window', + 'target': 'new', + 'context': ctx, + 'nodestroy': True, + } + def confirm_paid(self, cr, uid, ids, context=None): if context is None: context = {} @@ -604,6 +647,7 @@ class account_invoice(osv.osv): 'move_name':False, 'internal_number': False, 'period_id': False, + 'sent': False, }) if 'date_invoice' not in default: default.update({ @@ -938,7 +982,6 @@ class account_invoice(osv.osv): def invoice_validate(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state':'open'}, context=context) - self.invoice_validate_send_note(cr, uid, ids, context=context) return True def line_get_convert(self, cr, uid, x, part, date, context=None): @@ -1002,7 +1045,7 @@ class account_invoice(osv.osv): 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.log(cr, uid, inv_id, message, context=ctx) + self.message_append_note(cr, uid, [inv_id], body=message, context=context) return True def action_cancel(self, cr, uid, ids, *args): @@ -1232,7 +1275,7 @@ class account_invoice(osv.osv): # 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) - self.log(cr, uid, inv_id, msg) + self.message_append_note(cr, uid, [inv_id], body=msg, context=context) self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context) # Update the stored value (fields.function), so we write to trigger recompute @@ -1256,10 +1299,6 @@ class account_invoice(osv.osv): for obj in self.browse(cr, uid, ids, context=context): self.message_append_note(cr, uid, [obj.id],body=_("%s created.") % (self._get_document_type(obj.type)), context=context) - def invoice_validate_send_note(self, cr, uid, ids, context=None): - for obj in self.browse(cr, uid, ids, context=context): - self.message_append_note(cr, uid, [obj.id], body=_("%s validated.") % (self._get_document_type(obj.type)), 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_append_note(cr, uid, [obj.id], body=_("%s paid.") % (self._get_document_type(obj.type)), context=context) @@ -1307,7 +1346,7 @@ class account_invoice_line(osv.osv): _description = "Invoice Line" _columns = { 'name': fields.char('Description', size=256, required=True), - 'origin': fields.char('Origin', size=256, help="Reference of the document that produced this invoice."), + 'origin': fields.char('Source', size=256, help="Reference of the document that produced this invoice."), 'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True), 'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'), 'product_id': fields.many2one('product.product', 'Product', ondelete='set null'), @@ -1669,4 +1708,14 @@ class res_partner(osv.osv): res_partner() +class mail_message(osv.osv): + _name = 'mail.message' + _inherit = 'mail.message' + + def _postprocess_sent_message(self, cr, uid, message, context=None): + if message.model == 'account.invoice': + self.pool.get('account.invoice').write(cr, uid, [message.res_id], {'sent':True}, context=context) + return super(mail_message, self)._postprocess_sent_message(cr, uid, message=message, context=context) + +mail_message() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 5a9e808bf2d..8254d5183be 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -132,8 +132,6 @@ - - @@ -19,7 +19,7 @@ diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml index e519d23b09e..a1ff581006b 100644 --- a/addons/account_voucher/account_voucher_view.xml +++ b/addons/account_voucher/account_voucher_view.xml @@ -17,7 +17,6 @@ -