diff --git a/addons/account/__terp__.py b/addons/account/__terp__.py index c7f1dc9e149..921dc8c8cb9 100644 --- a/addons/account/__terp__.py +++ b/addons/account/__terp__.py @@ -23,7 +23,7 @@ { "name" : "Accounting and Financial Management", "version" : "1.1", - "depends" : ["product", "base", "process"], + "depends" : ["product", "analytic", "process"], "author" : "Tiny", "description": """Financial and accounting module that covers: General accounting diff --git a/addons/account/account.py b/addons/account/account.py index 29ea824f171..ed460c041c7 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -1748,15 +1748,6 @@ class account_config_wizard(osv.osv_memory): _name = 'account.config.wizard' _inherit = 'res.config' - def _get_charts(self, cr, uid, context): - module_obj=self.pool.get('ir.module.module') - ids=module_obj.search(cr, uid, [('category_id', '=', 'Account Charts'), - ('state', '<>', 'installed')]) - res=[(m.id, m.shortdesc) for m in module_obj.browse(cr, uid, ids)] - res.append((-1, 'None')) - res.sort(key=lambda x: x[1]) - return res - _columns = { 'name':fields.char( 'Name', required=True, size=64, @@ -1768,7 +1759,6 @@ class account_config_wizard(osv.osv_memory): 'date2': fields.date('End Date', required=True), 'period':fields.selection([('month','Month'), ('3months','3 Months')], 'Periods', required=True), - 'charts' : fields.selection(_get_charts, 'Charts of Account',required=True) } _defaults = { 'code': lambda *a: time.strftime('%Y'), @@ -1777,14 +1767,6 @@ class account_config_wizard(osv.osv_memory): 'date2': lambda *a: time.strftime('%Y-12-31'), 'period':lambda *a:'month', } - def install_account_chart(self, cr, uid, ids, context=None): - for res in self.read(cr,uid,ids): - chart_id = res['charts'] - if chart_id > 0: - mod_obj = self.pool.get('ir.module.module') - mod_obj.button_install(cr, uid, [chart_id], context=context) - cr.commit() - db, pool = pooler.restart_pool(cr.dbname, update_module=True) def execute(self, cr, uid, ids, context=None): for res in self.read(cr,uid,ids): @@ -1804,7 +1786,6 @@ class account_config_wizard(osv.osv_memory): res_obj.create_period(cr,uid,[new_id]) elif res['period']=='3months': res_obj.create_period3(cr,uid,[new_id]) - self.install_account_chart(cr,uid,ids) account_config_wizard() diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml index 4a1a1274e9f..4c9742fd127 100644 --- a/addons/account/account_installer.xml +++ b/addons/account/account_installer.xml @@ -4,43 +4,31 @@ account.installer.view account.installer form - + -
- Accounting Modules Installation -
+
+ Accounting Modules Installation +
- - - - - - - - - Install Modules + + Configure Your Accounting System + + + You can enhance OpenERP's basic accounting support with a few additional OpenERP applications + + + + + + + + + +
@@ -57,7 +45,7 @@ - 1 + 3 diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index a76a7c015a6..9985e134fb0 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -355,8 +355,8 @@ - - Panding Invoice + + Pending Invoice account.invoice form tree,form,calendar,graph diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml index 709009f8481..4ab7e6329a9 100644 --- a/addons/account/account_view.xml +++ b/addons/account/account_view.xml @@ -1451,9 +1451,9 @@ -
- Account Configure -
+
+ Account Configure +
@@ -1461,8 +1461,6 @@ - -
@@ -1734,16 +1732,14 @@ -
- Generate Chart of Accounts from a Chart Template -
+
+ Generate Chart of Accounts from a Chart Template +
-
- - - - - wizard.company.setup.form - wizard.company.setup - form - - - -
- Overdue Payment Report Message -
- - - - - - -
-
-
- - - Overdue Payment Report Message - ir.actions.act_window - wizard.company.setup - - form - form - new - - - - - - - diff --git a/addons/account/i18n/ru.po b/addons/account/i18n/ru.po index 020c123a932..2a98f3b7c9a 100644 --- a/addons/account/i18n/ru.po +++ b/addons/account/i18n/ru.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.0\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-08-28 16:01+0000\n" -"PO-Revision-Date: 2010-01-15 22:28+0000\n" -"Last-Translator: Alex Mr.Brightside Demurine \n" +"PO-Revision-Date: 2010-02-06 19:29+0000\n" +"Last-Translator: Santjaga \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2010-01-16 04:35+0000\n" +"X-Launchpad-Export-Date: 2010-02-07 04:37+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account @@ -97,7 +97,7 @@ msgstr "Несогласованные проводки" #: field:account.tax,base_code_id:0 #: field:account.tax.template,base_code_id:0 msgid "Base Code" -msgstr "" +msgstr "Базовый Код" #. module: account #: view:account.account:0 @@ -157,7 +157,7 @@ msgstr "Проводки" #. module: account #: selection:account.move.line,centralisation:0 msgid "Debit Centralisation" -msgstr "" +msgstr "Централизация Дебета" #. module: account #: model:ir.actions.wizard,name:account.wizard_invoice_state_confirm @@ -343,7 +343,7 @@ msgstr "Номер счета" #. module: account #: rml:account.analytic.account.analytic.check:0 msgid "Delta Debit" -msgstr "" +msgstr "Дебетовое сальдо" #. module: account #: rml:account.invoice:0 @@ -369,7 +369,7 @@ msgstr "Счет аналитического учета" #: field:account.tax,child_depend:0 #: field:account.tax.template,child_depend:0 msgid "Tax on Children" -msgstr "" +msgstr "Налог на детей" #. module: account #: rml:account.central.journal:0 diff --git a/addons/account/installer.py b/addons/account/installer.py index 2e7ebb5ed44..35a09406891 100644 --- a/addons/account/installer.py +++ b/addons/account/installer.py @@ -18,21 +18,61 @@ # along with this program. If not, see . # ############################################################################## +from operator import itemgetter + from osv import fields, osv +import netsvc class account_installer(osv.osv_memory): _name = 'account.installer' _inherit = 'res.config.installer' + def _get_charts(self, cr, uid, context=None): + modules = self.pool.get('ir.module.module') + ids = modules.search(cr, uid, [('category_id','=','Account Charts')]) + return list( + sorted(((m.name, m.shortdesc) + for m in modules.browse(cr, uid, ids)), + key=itemgetter(1))) + _columns = { # Accounting - 'account_analytic_default':fields.boolean('Analytic Accounting'), - 'account_analytic_plans':fields.boolean('Multiple Analytic Plans'), - 'account_payment':fields.boolean('Suppliers Payment Management'), - 'account_followup':fields.boolean('Followups Management'), - 'account_asset':fields.boolean('Assets Management') + 'charts':fields.selection(_get_charts, 'Chart of Accounts', + required=True, + help="Installs localized accounting charts to match as closely as " + "possible the accounting needs of your company based on your " + "country."), + 'account_analytic_default':fields.boolean('Analytic Accounting', + help="Automatically selects analytic accounts based on various " + "criteria."), + 'account_analytic_plans':fields.boolean('Multiple Analytic Plans', + help="Allows invoice lines to impact multiple analytic accounts " + "simultaneously."), + 'account_payment':fields.boolean('Suppliers Payment Management', + help="Streamlines invoice payment and creates hooks to plug " + "automated payment systems in."), + 'account_followup':fields.boolean('Followups Management', + help="Helps you generate reminder letters for unpaid invoices, " + "including multiple levels of reminding and customized " + "per-partner policies."), + 'account_asset':fields.boolean('Assets Management', + help="Enables asset management in the accounting application, " + "including asset categories and usage periods.") } _defaults = { 'account_analytic_default':True, } + + def modules_to_install(self, cr, uid, ids, context=None): + modules = super(account_installer, self).modules_to_install( + cr, uid, ids, context=context) + + chart = self.read(cr, uid, ids, ['charts'], + context=context)[0]['charts'] + self.logger.notifyChannel( + 'installer', netsvc.LOG_DEBUG, + 'Installing chart of accounts %s'%chart) + return modules | set([chart]) + + account_installer() diff --git a/addons/account/process/customer_invoice_process.xml b/addons/account/process/customer_invoice_process.xml index 117b7723c68..b9710276509 100755 --- a/addons/account/process/customer_invoice_process.xml +++ b/addons/account/process/customer_invoice_process.xml @@ -18,7 +18,7 @@ - + diff --git a/addons/account/process/supplier_invoice_process.xml b/addons/account/process/supplier_invoice_process.xml index 80d57de1f41..26e1e9862e7 100755 --- a/addons/account/process/supplier_invoice_process.xml +++ b/addons/account/process/supplier_invoice_process.xml @@ -18,7 +18,7 @@ - + diff --git a/addons/account/project/project.py b/addons/account/project/project.py index a381f587f8a..7ad98b04b32 100644 --- a/addons/account/project/project.py +++ b/addons/account/project/project.py @@ -29,239 +29,6 @@ from osv import osv # Object definition # -class account_analytic_account(osv.osv): - _name = 'account.analytic.account' - _description = 'Analytic Accounts' - - def _credit_calc(self, cr, uid, ids, name, arg, context={}): - - where_date = '' - if context.get('from_date',False): - where_date += " AND l.date >= '" + context['from_date'] + "'" - if context.get('to_date',False): - where_date += " AND l.date <= '" + context['to_date'] + "'" - - cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount<0 and a.id =ANY(%s) GROUP BY a.id",(ids,)) - r = dict(cr.fetchall()) - for i in ids: - r.setdefault(i,0.0) - return r - - def _debit_calc(self, cr, uid, ids, name, arg, context={}): - - where_date = '' - if context.get('from_date',False): - where_date += " AND l.date >= '" + context['from_date'] + "'" - if context.get('to_date',False): - where_date += " AND l.date <= '" + context['to_date'] + "'" - - cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount>0 and a.id =ANY(%s) GROUP BY a.id" ,(ids,)) - r= dict(cr.fetchall()) - for i in ids: - r.setdefault(i,0.0) - return r - - def _balance_calc(self, cr, uid, ids, name, arg, context={}): - res = {} - ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)]) - for i in ids: - res.setdefault(i,0.0) - if not ids2: - return res - - where_date = '' - if context.get('from_date',False): - where_date += " AND l.date >= '" + context['from_date'] + "'" - if context.get('to_date',False): - where_date += " AND l.date <= '" + context['to_date'] + "'" - - cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE a.id =ANY(%s) GROUP BY a.id",(ids2,)) - - for account_id, sum in cr.fetchall(): - res[account_id] = sum - - cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id =ANY(%s)",(ids2,)) - - currency= dict(cr.fetchall()) - - res_currency= self.pool.get('res.currency') - for id in ids: - if id not in ids2: - continue - for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]): - if child <> id: - res.setdefault(id, 0.0) - if currency[child]<>currency[id]: - res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context) - else: - res[id] += res.get(child, 0.0) - - cur_obj = res_currency.browse(cr,uid,currency.values(),context) - cur_obj = dict([(o.id, o) for o in cur_obj]) - for id in ids: - if id in ids2: - res[id] = res_currency.round(cr,uid,cur_obj[currency[id]],res.get(id,0.0)) - - return dict([(i, res[i]) for i in ids ]) - - def _quantity_calc(self, cr, uid, ids, name, arg, context={}): - #XXX must convert into one uom - res = {} - ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)]) - acc_set = ",".join(map(str, ids2)) - - for i in ids: - res.setdefault(i,0.0) - - if not acc_set: - return res - - where_date = '' - if context.get('from_date',False): - where_date += " AND l.date >= '" + context['from_date'] + "'" - if context.get('to_date',False): - where_date += " AND l.date <= '" + context['to_date'] + "'" - - cr.execute('SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \ - FROM account_analytic_account a \ - LEFT JOIN account_analytic_line l ON (a.id = l.account_id ' + where_date + ') \ - WHERE a.id =ANY(%s) GROUP BY a.id',(ids2,)) - - for account_id, sum in cr.fetchall(): - res[account_id] = sum - - for id in ids: - if id not in ids2: - continue - for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]): - if child <> id: - res.setdefault(id, 0.0) - res[id] += res.get(child, 0.0) - return dict([(i, res[i]) for i in ids]) - - def name_get(self, cr, uid, ids, context={}): - if not len(ids): - return [] - reads = self.read(cr, uid, ids, ['name','parent_id'], context) - res = [] - for record in reads: - name = record['name'] - if record['parent_id']: - name = record['parent_id'][1]+' / '+name - res.append((record['id'], name)) - return res - - def _complete_name_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict): - res = self.name_get(cr, uid, ids) - return dict(res) - - def _get_company_currency(self, cr, uid, ids, field_name, arg, context={}): - result = {} - for rec in self.browse(cr, uid, ids, context): - result[rec.id] = (rec.company_id.currency_id.id,rec.company_id.currency_id.code) or False - return result - - _columns = { - 'name' : fields.char('Account Name', size=128, required=True), - 'complete_name': fields.function(_complete_name_calc, method=True, type='char', string='Full Account Name'), - 'code' : fields.char('Account Code', size=24), -# 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the analytic account without removing it."), - 'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type'), - 'description' : fields.text('Description'), - 'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2), - 'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts'), - 'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries'), - 'balance' : fields.function(_balance_calc, method=True, type='float', string='Balance'), - 'debit' : fields.function(_debit_calc, method=True, type='float', string='Debit'), - 'credit' : fields.function(_credit_calc, method=True, type='float', string='Credit'), - 'quantity': fields.function(_quantity_calc, method=True, type='float', string='Quantity'), - 'quantity_max': fields.float('Maximum Quantity', help='Sets the higher limit of quantity of hours.'), - 'partner_id' : fields.many2one('res.partner', 'Associated Partner'), - 'contact_id' : fields.many2one('res.partner.address', 'Contact'), - 'user_id' : fields.many2one('res.users', 'Account Manager'), - 'date_start': fields.date('Date Start'), - 'date': fields.date('Date End'), - 'company_id': fields.many2one('res.company', 'Company', required=True), - 'company_currency_id': fields.function(_get_company_currency, method=True, type='many2one', relation='res.currency', string='Currency'), - 'state': fields.selection([('draft','Draft'),('open','Open'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Close'),('template', 'Template')], 'State', required=True,readonly=True, - help='* When an account is created its in \'Draft\' state.\ - \n* If any associated partner is there, it can be in \'Open\' state.\ - \n* If any pending balance is there it can be in \'Pending\'. \ - \n* And finally when all the transactions are over, it can be in \'Close\' state. \ - \n* The project can be in either if the states \'Template\' and \'Running\'.\n If it is template then we can make projects based on the template projects. If its in \'Running\' state it is a normal project.\ - \n If it is to be reviewed then the state is \'Pending\'.\n When the project is completed the state is set to \'Done\'.'), - } - - def _default_company(self, cr, uid, context={}): - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - if user.company_id: - return user.company_id.id - return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0] - _defaults = { -# 'active' : lambda *a : True, - 'type' : lambda *a : 'normal', - 'company_id': _default_company, - 'state' : lambda *a : 'open', - 'user_id' : lambda self,cr,uid,ctx : uid, - 'partner_id': lambda self,cr, uid, ctx: ctx.get('partner_id', False), - 'contact_id': lambda self,cr, uid, ctx: ctx.get('contact_id', False), - 'date_start': lambda *a: time.strftime('%Y-%m-%d') - } - - def check_recursion(self, cr, uid, ids, parent=None): - return super(account_analytic_account, self).check_recursion(cr, uid, ids, parent=parent) - - _order = 'parent_id desc,code' - _constraints = [ - (check_recursion, 'Error! You can not create recursive analytic accounts.', ['parent_id']) - ] - - def create(self, cr, uid, vals, context=None): - parent_id = vals.get('parent_id', 0) - if ('code' not in vals or not vals['code']) and not parent_id: - vals['code'] = self.pool.get('ir.sequence').get(cr, uid, 'account.analytic.account') - return super(account_analytic_account, self).create(cr, uid, vals, context=context) - - def copy(self, cr, uid, id, default=None, context={}): - if not default: - default = {} - default['code'] = False - default['line_ids'] = [] - return super(account_analytic_account, self).copy(cr, uid, id, default, context=context) - - - def on_change_parent(self, cr, uid, id, parent_id): - if not parent_id: - return {} - parent = self.read(cr, uid, [parent_id], ['partner_id','code'])[0] - childs = self.search(cr, uid, [('parent_id', '=', parent_id), ('active', 'in', [True, False])]) - numchild = len(childs) - if parent['partner_id']: - partner = parent['partner_id'][0] - else: - partner = False - res = {'value' : {'code' : '%s - %03d' % (parent['code'] or '', numchild + 1),}} - if partner: - res['value']['partner_id'] = partner - return res - - def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): - if not args: - args=[] - if not context: - context={} - account = self.search(cr, uid, [('code', '=', name)]+args, limit=limit, context=context) - if not account: - account = self.search(cr, uid, [('name', 'ilike', '%%%s%%' % name)]+args, limit=limit, context=context) - newacc = account - while newacc: - newacc = self.search(cr, uid, [('parent_id', 'in', newacc)]+args, limit=limit, context=context) - account+=newacc - return self.name_get(cr, uid, account, context=context) - -account_analytic_account() - - class account_analytic_journal(osv.osv): _name = 'account.analytic.journal' _columns = { diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv index bb7ffbae946..4cf67851760 100644 --- a/addons/account/security/ir.model.access.csv +++ b/addons/account/security/ir.model.access.csv @@ -34,7 +34,7 @@ "access_account_bank_statement_line","account.bank.statement.line","model_account_bank_statement_line","account.group_account_user",1,1,1,1 "access_account_analytic_line","account.analytic.line","model_account_analytic_line","account.group_account_user",1,1,1,1 "access_report_hr_timesheet_invoice_journal","report.hr.timesheet.invoice.journal","model_report_hr_timesheet_invoice_journal","account.group_account_manager",1,0,0,0 -"access_account_analytic_account","account.analytic.account","model_account_analytic_account","base.group_user",1,0,0,0 +"access_account_analytic_account","account.analytic.account","analytic.model_account_analytic_account","base.group_user",1,0,0,0 "access_account_analytic_journal","account.analytic.journal","model_account_analytic_journal","account.group_account_user",1,0,0,0 "access_account_invoice_uinvoice","account.invoice","model_account_invoice","account.group_account_invoice",1,1,1,1 "access_account_invoice_line_uinvoice","account.invoice.line","model_account_invoice_line","account.group_account_invoice",1,1,1,1 @@ -58,7 +58,7 @@ "access_account_tax_code_manager","account.tax.code","model_account_tax_code","account.group_account_manager",1,1,1,1 "access_account_tax_manager","account.tax","model_account_tax","account.group_account_manager",1,1,1,1 "access_account_invoice_group_invoice","account.invoice group invoice","model_account_invoice","account.group_account_invoice",1,1,1,1 -"access_account_analytic_account_manager","account.analytic.account","model_account_analytic_account","account.group_account_manager",1,1,1,1 +"access_account_analytic_account_manager","account.analytic.account","analytic.model_account_analytic_account","account.group_account_manager",1,1,1,1 "access_account_analytic_journal_manager","account.analytic.journal","model_account_analytic_journal","account.group_account_manager",1,1,1,1 "access_account_fiscalyear","account.fiscalyear","model_account_fiscalyear","account.group_account_manager",1,1,1,1 "access_account_fiscalyear_user","account.fiscalyear.user","model_account_fiscalyear","account.group_account_user",1,0,0,0 @@ -87,6 +87,3 @@ "access_account_fiscal_position_account_template","account.fiscal.position.account.template","model_account_fiscal_position_account_template","account.group_account_manager",1,1,1,1 "access_account_sequence_fiscal_year","account.sequence.fiscalyear","model_account_sequence_fiscalyear","account.group_account_user",1,1,1,1 "access_account_sequence_fiscal_year_user","account.sequence.fiscalyear user","model_account_sequence_fiscalyear","base.group_user",1,0,0,0 -"access_wizard_company_setup_manager","wizard.company.setup manager","model_wizard_company_setup","account.group_account_manager",1,1,1,1 -"access_wizard_company_setup","wizard.company.setup","model_wizard_company_setup","account.group_account_user",1,0,0,0 -"access_wizard_company_setup_user","wizard.company.setup user","model_wizard_company_setup","base.group_user",1,0,0,0 diff --git a/addons/account_analytic_default/i18n/ar.po b/addons/account_analytic_default/i18n/ar.po index c27e4e2f3bb..943a3f94d31 100644 --- a/addons/account_analytic_default/i18n/ar.po +++ b/addons/account_analytic_default/i18n/ar.po @@ -7,13 +7,13 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2009-08-28 16:01+0000\n" -"PO-Revision-Date: 2009-02-03 06:23+0000\n" -"Last-Translator: <>\n" +"PO-Revision-Date: 2010-02-06 17:39+0000\n" +"Last-Translator: omar \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2009-12-16 05:18+0000\n" +"X-Launchpad-Export-Date: 2010-02-07 04:38+0000\n" "X-Generator: Launchpad (build Unknown)\n" #. module: account_analytic_default @@ -77,7 +77,7 @@ msgstr "" #. module: account_analytic_default #: field:account.analytic.default,user_id:0 msgid "User" -msgstr "" +msgstr "المستخدم" #. module: account_analytic_default #: constraint:ir.actions.act_window:0 diff --git a/addons/account_anglo_saxon/__terp__.py b/addons/account_anglo_saxon/__terp__.py index 31818e213ef..a601d56b1d1 100644 --- a/addons/account_anglo_saxon/__terp__.py +++ b/addons/account_anglo_saxon/__terp__.py @@ -18,17 +18,18 @@ # ############################################################################## { - "name" : "Stock Account", - "version" : "1.1", - "author" : "Tiny", - "website" : "http://tinyerp.com", + "name" : "Stock Accounting for Anglo Saxon countries", + "version" : "1.2", + "author" : "Tiny, Veritos", + "website" : "http://tinyerp.com - http://veritos.nl", "description" : """This module will support the Anglo-Saxons accounting methodology by changing the accounting logic with stock transactions. The difference between the Anglo-Saxon accounting countries and the Rhine or also called Continental accounting countries is the moment of taking the Cost of Goods Sold versus Cost of Sales. Anglo-Saxons accounting does take the cost when sales invoice is created, Continental accounting will take the cost at he moment the goods are shipped. This module will add this functionality by using a interim account, to store the value of shipped goods and will contra book this interim account - when the invoice is created to transfer this amount to the debtor or creditor account.""", - "depends" : ["product", "account", "sale", "purchase"], + when the invoice is created to transfer this amount to the debtor or creditor account. + Secondly, price differences between actual purchase price and fixed product standard price are booked on a seperate account""", + "depends" : ["product", "account", "sale", "purchase", "stock"], "category" : "Generic Modules/Inventory Control", "init_xml" : [], "demo_xml" : [], diff --git a/addons/account_anglo_saxon/invoice.py b/addons/account_anglo_saxon/invoice.py index 3904cd6b01e..7c1ecbab758 100644 --- a/addons/account_anglo_saxon/invoice.py +++ b/addons/account_anglo_saxon/invoice.py @@ -1,7 +1,10 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). +# Copyright (C) +# 2004-2010 Tiny SPRL (). +# 2009-2010 Veritos (http://veritos.nl). +# All Rights Reserved # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -30,14 +33,20 @@ class account_invoice_line(osv.osv): for i_line in inv.invoice_line: if i_line.product_id: if inv.type == 'out_invoice': + # debit account dacc will be the output account + # first check the product, if empty check the category dacc = i_line.product_id.product_tmpl_id.property_stock_account_output and i_line.product_id.product_tmpl_id.property_stock_account_output.id if not dacc: dacc = i_line.product_id.categ_id.property_stock_account_output_categ and i_line.product_id.categ_id.property_stock_account_output_categ.id else: + # = out_refund + # debit account dacc will be the input account + # first check the product, if empty check the category dacc = i_line.product_id.product_tmpl_id.property_stock_account_input and i_line.product_id.product_tmpl_id.property_stock_account_input.id if not dacc: dacc = i_line.product_id.categ_id.property_stock_account_input_categ and i_line.product_id.categ_id.property_stock_account_input_categ.id - + # in both cases the credit account cacc will be the expense account + # first check the product, if empty check the category cacc = i_line.product_id.product_tmpl_id.property_account_expense and i_line.product_id.product_tmpl_id.property_account_expense.id if not cacc: cacc = i_line.product_id.categ_id.property_account_expense_categ and i_line.product_id.categ_id.property_account_expense_categ.id @@ -71,27 +80,36 @@ class account_invoice_line(osv.osv): for i_line in inv.invoice_line: if i_line.product_id: if i_line.product_id.product_tmpl_id.type != 'service': + # get the price difference account at the product acc = i_line.product_id.product_tmpl_id.property_account_creditor_price_difference and i_line.product_id.product_tmpl_id.property_account_creditor_price_difference.id if not acc: + # if not found on the product get the price difference account at the category acc = i_line.product_id.categ_id.property_account_creditor_price_difference_categ and i_line.product_id.categ_id.property_account_creditor_price_difference_categ.id a = None if inv.type == 'in_invoice': + # oa will be the stock input account + # first check the product, if empty check the category oa = i_line.product_id.product_tmpl_id.property_stock_account_input and i_line.product_id.product_tmpl_id.property_stock_account_input.id if not oa: oa = i_line.product_id.categ_id.property_stock_account_input_categ and i_line.product_id.categ_id.property_stock_account_input_categ.id else: + # = in_refund + # oa will be the stock output account + # first check the product, if empty check the category oa = i_line.product_id.product_tmpl_id.property_stock_account_output and i_line.product_id.product_tmpl_id.property_stock_account_output.id if not oa: oa = i_line.product_id.categ_id.property_stock_account_output_categ and i_line.product_id.categ_id.property_stock_account_output_categ.id if oa: + # get the fiscal position fpos = i_line.invoice_id.fiscal_position or False a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa) diff_res = [] + # calculate and write down the possible price difference between invoice price and product price for line in res: if a == line['account_id'] and i_line.product_id.id == line['product_id']: uom = i_line.product_id.uos_id or i_line.product_id.uom_id standard_price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.product_tmpl_id.standard_price, i_line.uos_id.id) - if standard_price != i_line.price_unit and line['price'] == i_line.price_unit and acc: + if standard_price != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc: price_diff = i_line.price_unit - standard_price line.update({'price':standard_price * line['quantity']}) diff_res.append({ diff --git a/addons/account_anglo_saxon/stock.py b/addons/account_anglo_saxon/stock.py index ad091364fd8..ac0dbeadcec 100644 --- a/addons/account_anglo_saxon/stock.py +++ b/addons/account_anglo_saxon/stock.py @@ -43,6 +43,18 @@ class stock_picking(osv.osv): fpos = ol.invoice_id.fiscal_position or False a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa) self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a}) + + elif type == 'in_invoice': + for inv in self.pool.get('account.invoice').browse(cr, uid, res.values(), context=context): + for ol in inv.invoice_line: + if ol.product_id: + oa = ol.product_id.product_tmpl_id.property_stock_account_input and ol.product_id.product_tmpl_id.property_stock_account_input.id + if not oa: + oa = ol.product_id.categ_id.property_stock_account_input_categ and ol.product_id.categ_id.property_stock_account_input_categ.id + if oa: + fpos = ol.invoice_id.fiscal_position or False + a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa) + self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a}) return res stock_picking() diff --git a/addons/base_setup/wizard/__init__.py b/addons/analytic/__init__.py similarity index 97% rename from addons/base_setup/wizard/__init__.py rename to addons/analytic/__init__.py index a322ae346b3..dc48b6f4001 100644 --- a/addons/base_setup/wizard/__init__.py +++ b/addons/analytic/__init__.py @@ -19,8 +19,7 @@ # ############################################################################## -import wizard_base_setup - +import project # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/analytic/__terp__.py b/addons/analytic/__terp__.py new file mode 100644 index 00000000000..6ccdf3564d8 --- /dev/null +++ b/addons/analytic/__terp__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + "name" : "Analytic Account", + "version": "1.1", + "author" : "Tiny", + "website" : "http://www.openerp.com", + "category" : "Generic Modules/Projects & Services", + "depends" : ["base"], + "description": """Module for defining analytic accounting object. + """, + "init_xml" : [], + "update_xml": ["security/ir.model.access.csv", + ], + 'demo_xml': [ + ], + 'installable': True, + 'active': False, + 'certificate': '', +} +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/analytic/project.py b/addons/analytic/project.py new file mode 100644 index 00000000000..7e0ab40c63a --- /dev/null +++ b/addons/analytic/project.py @@ -0,0 +1,262 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import time +import operator + +from osv import fields +from osv import osv + +# +# Object definition +# + +class account_analytic_account(osv.osv): + _name = 'account.analytic.account' + _description = 'Analytic Accounts' + + def _credit_calc(self, cr, uid, ids, name, arg, context={}): + + where_date = '' + if context.get('from_date',False): + where_date += " AND l.date >= '" + context['from_date'] + "'" + if context.get('to_date',False): + where_date += " AND l.date <= '" + context['to_date'] + "'" + + cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount<0 and a.id =ANY(%s) GROUP BY a.id",(ids,)) + r = dict(cr.fetchall()) + for i in ids: + r.setdefault(i,0.0) + return r + + def _debit_calc(self, cr, uid, ids, name, arg, context={}): + + where_date = '' + if context.get('from_date',False): + where_date += " AND l.date >= '" + context['from_date'] + "'" + if context.get('to_date',False): + where_date += " AND l.date <= '" + context['to_date'] + "'" + + cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE l.amount>0 and a.id =ANY(%s) GROUP BY a.id" ,(ids,)) + r= dict(cr.fetchall()) + for i in ids: + r.setdefault(i,0.0) + return r + + def _balance_calc(self, cr, uid, ids, name, arg, context={}): + res = {} + ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)]) + for i in ids: + res.setdefault(i,0.0) + if not ids2: + return res + + where_date = '' + if context.get('from_date',False): + where_date += " AND l.date >= '" + context['from_date'] + "'" + if context.get('to_date',False): + where_date += " AND l.date <= '" + context['to_date'] + "'" + + cr.execute("SELECT a.id, COALESCE(SUM(l.amount),0) FROM account_analytic_account a LEFT JOIN account_analytic_line l ON (a.id=l.account_id "+where_date+") WHERE a.id =ANY(%s) GROUP BY a.id",(ids2,)) + + for account_id, sum in cr.fetchall(): + res[account_id] = sum + + cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id =ANY(%s)",(ids2,)) + + currency= dict(cr.fetchall()) + + res_currency= self.pool.get('res.currency') + for id in ids: + if id not in ids2: + continue + for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]): + if child <> id: + res.setdefault(id, 0.0) + if currency[child]<>currency[id]: + res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context) + else: + res[id] += res.get(child, 0.0) + + cur_obj = res_currency.browse(cr,uid,currency.values(),context) + cur_obj = dict([(o.id, o) for o in cur_obj]) + for id in ids: + if id in ids2: + res[id] = res_currency.round(cr,uid,cur_obj[currency[id]],res.get(id,0.0)) + + return dict([(i, res[i]) for i in ids ]) + + def _quantity_calc(self, cr, uid, ids, name, arg, context={}): + #XXX must convert into one uom + res = {} + ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)]) + acc_set = ",".join(map(str, ids2)) + + for i in ids: + res.setdefault(i,0.0) + + if not acc_set: + return res + + where_date = '' + if context.get('from_date',False): + where_date += " AND l.date >= '" + context['from_date'] + "'" + if context.get('to_date',False): + where_date += " AND l.date <= '" + context['to_date'] + "'" + + cr.execute('SELECT a.id, COALESCE(SUM(l.unit_amount), 0) \ + FROM account_analytic_account a \ + LEFT JOIN account_analytic_line l ON (a.id = l.account_id ' + where_date + ') \ + WHERE a.id =ANY(%s) GROUP BY a.id',(ids2,)) + + for account_id, sum in cr.fetchall(): + res[account_id] = sum + + for id in ids: + if id not in ids2: + continue + for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]): + if child <> id: + res.setdefault(id, 0.0) + res[id] += res.get(child, 0.0) + return dict([(i, res[i]) for i in ids]) + + def name_get(self, cr, uid, ids, context={}): + if not len(ids): + return [] + reads = self.read(cr, uid, ids, ['name','parent_id'], context) + res = [] + for record in reads: + name = record['name'] + if record['parent_id']: + name = record['parent_id'][1]+' / '+name + res.append((record['id'], name)) + return res + + def _complete_name_calc(self, cr, uid, ids, prop, unknow_none, unknow_dict): + res = self.name_get(cr, uid, ids) + return dict(res) + + def _get_company_currency(self, cr, uid, ids, field_name, arg, context={}): + result = {} + for rec in self.browse(cr, uid, ids, context): + result[rec.id] = (rec.company_id.currency_id.id,rec.company_id.currency_id.code) or False + return result + + _columns = { + 'name' : fields.char('Account Name', size=128, required=True), + 'complete_name': fields.function(_complete_name_calc, method=True, type='char', string='Full Account Name'), + 'code' : fields.char('Account Code', size=24), +# 'active' : fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the analytic account without removing it."), + 'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type'), + 'description' : fields.text('Description'), + 'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2), + 'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts'), + 'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries'), + 'balance' : fields.function(_balance_calc, method=True, type='float', string='Balance'), + 'debit' : fields.function(_debit_calc, method=True, type='float', string='Debit'), + 'credit' : fields.function(_credit_calc, method=True, type='float', string='Credit'), + 'quantity': fields.function(_quantity_calc, method=True, type='float', string='Quantity'), + 'quantity_max': fields.float('Maximum Quantity', help='Sets the higher limit of quantity of hours.'), + 'partner_id' : fields.many2one('res.partner', 'Associated Partner'), + 'contact_id' : fields.many2one('res.partner.address', 'Contact'), + 'user_id' : fields.many2one('res.users', 'Account Manager'), + 'date_start': fields.date('Date Start'), + 'date': fields.date('Date End'), + 'company_id': fields.many2one('res.company', 'Company', required=True), + 'company_currency_id': fields.function(_get_company_currency, method=True, type='many2one', relation='res.currency', string='Currency'), + 'state': fields.selection([('draft','Draft'),('open','Open'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Close'),('template', 'Template')], 'State', required=True,readonly=True, + help='* When an account is created its in \'Draft\' state.\ + \n* If any associated partner is there, it can be in \'Open\' state.\ + \n* If any pending balance is there it can be in \'Pending\'. \ + \n* And finally when all the transactions are over, it can be in \'Close\' state. \ + \n* The project can be in either if the states \'Template\' and \'Running\'.\n If it is template then we can make projects based on the template projects. If its in \'Running\' state it is a normal project.\ + \n If it is to be reviewed then the state is \'Pending\'.\n When the project is completed the state is set to \'Done\'.'), + } + + def _default_company(self, cr, uid, context={}): + user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + if user.company_id: + return user.company_id.id + return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0] + _defaults = { +# 'active' : lambda *a : True, + 'type' : lambda *a : 'normal', + 'company_id': _default_company, + 'state' : lambda *a : 'open', + 'user_id' : lambda self,cr,uid,ctx : uid, + 'partner_id': lambda self,cr, uid, ctx: ctx.get('partner_id', False), + 'contact_id': lambda self,cr, uid, ctx: ctx.get('contact_id', False), + 'date_start': lambda *a: time.strftime('%Y-%m-%d') + } + + def check_recursion(self, cr, uid, ids, parent=None): + return super(account_analytic_account, self).check_recursion(cr, uid, ids, parent=parent) + + _order = 'parent_id desc,code' + _constraints = [ + (check_recursion, 'Error! You can not create recursive analytic accounts.', ['parent_id']) + ] + + def create(self, cr, uid, vals, context=None): + parent_id = vals.get('parent_id', 0) + if ('code' not in vals or not vals['code']) and not parent_id: + vals['code'] = self.pool.get('ir.sequence').get(cr, uid, 'account.analytic.account') + return super(account_analytic_account, self).create(cr, uid, vals, context=context) + + def copy(self, cr, uid, id, default=None, context={}): + if not default: + default = {} + default['code'] = False + default['line_ids'] = [] + return super(account_analytic_account, self).copy(cr, uid, id, default, context=context) + + + def on_change_parent(self, cr, uid, id, parent_id): + if not parent_id: + return {} + parent = self.read(cr, uid, [parent_id], ['partner_id','code'])[0] + childs = self.search(cr, uid, [('parent_id', '=', parent_id), ('active', 'in', [True, False])]) + numchild = len(childs) + if parent['partner_id']: + partner = parent['partner_id'][0] + else: + partner = False + res = {'value' : {'code' : '%s - %03d' % (parent['code'] or '', numchild + 1),}} + if partner: + res['value']['partner_id'] = partner + return res + + def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): + if not args: + args=[] + if not context: + context={} + account = self.search(cr, uid, [('code', '=', name)]+args, limit=limit, context=context) + if not account: + account = self.search(cr, uid, [('name', 'ilike', '%%%s%%' % name)]+args, limit=limit, context=context) + newacc = account + while newacc: + newacc = self.search(cr, uid, [('parent_id', 'in', newacc)]+args, limit=limit, context=context) + account+=newacc + return self.name_get(cr, uid, account, context=context) + +account_analytic_account() diff --git a/addons/analytic/security/ir.model.access.csv b/addons/analytic/security/ir.model.access.csv new file mode 100644 index 00000000000..0343f29f43a --- /dev/null +++ b/addons/analytic/security/ir.model.access.csv @@ -0,0 +1 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index 9849a5b012d..689d2d08459 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -421,6 +421,16 @@ class basic_calendar_line(osv.osv): 'domain': lambda *a: '[]', } + def create(self, cr, uid, vals, context={}): + cr.execute("Select count(id) from basic_calendar_lines \ + where name='%s' and calendar_id=%s" % (vals.get('name'), vals.get('calendar_id'))) + res = cr.fetchone() + if res: + if res[0] > 0: + raise osv.except_osv(_('Warning !'), _('Can not create \ +line "%s" more than once' % (vals.get('name')))) + return super(basic_calendar_line, self).create(cr, uid, vals, context=context) + basic_calendar_line() class basic_calendar_attribute(osv.osv): @@ -482,7 +492,7 @@ class basic_calendar_fields(osv.osv): res = cr.fetchone() if res: if res[0] > 0: - raise osv.except_osv(_('Warning !'), _('Can not map same field more than once')) + raise osv.except_osv(_('Warning !'), _('Can not map the field more than once')) return super(basic_calendar_fields, self).create(cr, uid, vals, context=context) def write(self, cr, uid, ids, vals, context=None): diff --git a/addons/base_setup/__init__.py b/addons/base_setup/__init__.py index 2e2da2196e5..22e81a488b0 100644 --- a/addons/base_setup/__init__.py +++ b/addons/base_setup/__init__.py @@ -20,7 +20,62 @@ ############################################################################## import installer +import todo import wizard +from osv import osv +import netsvc + +class base_setup_config_choice(osv.osv_memory): + """ + """ + _name = 'base.setup.config' + logger = netsvc.Logger() + + def set_default_menu(self, cr, uid, menu, context=None): + user = self.pool.get('res.users')\ + .browse(cr, uid, uid, context=context) + + user.write({'action_id': menu.id, + 'menu_id': menu.id}) + + def get_default_menu(self, cr, uid, context=None): + actions = self.pool.get('ir.actions.act_window') + + current_menu_id = actions.search(cr, uid, [('name','=','Menu')], + context=context) + assert len(current_menu_id) == 1,\ + 'A given user should only have one menu item' + return actions.browse(cr, uid, current_menu_id[0], context=context) + + def menu(self, cr, uid, ids, context=None): + menu = self.get_default_menu(cr, uid, context=context) + self.set_default_menu(cr, uid, menu, context=context) + + if menu.view_id.id: + view_id = (menu.view_id.id, menu.view_id.name) + else: + view_id = False + + return { + 'name': menu.name, + 'type': menu.type, + 'view_id': view_id, + 'domain': menu.domain, + 'res_users': menu.res_model, + 'src_model': menu.src_model, + 'view_type': menu.view_type, + 'view_mode': menu.view_mode, + 'views': menu.views, + } + def config(self, cr, uid, ids, context=None): + menu = self.get_default_menu(cr, uid, context=context) + self.set_default_menu(cr, uid, menu, context=context) + + return self.pool.get('res.config').next(cr, uid, [], context=context) + +base_setup_config_choice() + + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/base_setup/__terp__.py b/addons/base_setup/__terp__.py index 6f7f4337740..c6dd64d7bcc 100644 --- a/addons/base_setup/__terp__.py +++ b/addons/base_setup/__terp__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2004-2010 Tiny SPRL (). # @@ -15,7 +15,7 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . +# along with this program. If not, see . # ############################################################################## @@ -42,8 +42,8 @@ 'depends': ['base'], 'init_xml': ['base_setup_data.xml'], 'update_xml': ['security/ir.model.access.csv', - 'base_setup_wizard.xml', - 'base_setup_installer.xml'], + 'base_setup_installer.xml', + 'base_setup_todo.xml',], 'demo_xml': ['base_setup_demo.xml'], 'installable': True, 'active': True, diff --git a/addons/base_setup/base_setup_data.xml b/addons/base_setup/base_setup_data.xml index c715dbb6992..a28c7744158 100644 --- a/addons/base_setup/base_setup_data.xml +++ b/addons/base_setup/base_setup_data.xml @@ -1,17 +1,41 @@ - - - - Setup - ir.actions.wizard - base_setup.base_setup - - - - - - - - + + + Setup + base.setup.config + form + +
+ + + + + + +