[IMP] account,sale:checked multi-company in accounting and sale module

bzr revid: mtr@mtr-20100608064531-6q96hu7uet2e5qc9
This commit is contained in:
mtr 2010-06-08 12:15:31 +05:30
parent fcc0296fff
commit af6e99a052
5 changed files with 158 additions and 118 deletions

View File

@ -513,6 +513,10 @@ class account_account(osv.osv):
self._check_moves(cr, uid, ids, "write", context) self._check_moves(cr, uid, ids, "write", context)
if 'type' in vals.keys(): if 'type' in vals.keys():
self._check_allow_type_change(cr, uid, ids, vals['type'], context=context) self._check_allow_type_change(cr, uid, ids, vals['type'], context=context)
if 'company_id' in vals:
obj=self.pool.get('account.move.line').search(cr, uid, [('account_id', '=', ids)])
if obj:
raise osv.except_osv(_('Warning !'), _('You cannot update Company as its related record exist in Entry Lines'))
return super(account_account, self).write(cr, uid, ids, vals, context=context) return super(account_account, self).write(cr, uid, ids, vals, context=context)
def unlink(self, cr, uid, ids, context={}): def unlink(self, cr, uid, ids, context={}):
@ -711,7 +715,7 @@ class account_period(osv.osv):
'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True), 'fiscalyear_id': fields.many2one('account.fiscalyear', 'Fiscal Year', required=True, states={'done':[('readonly',True)]}, select=True),
'state': fields.selection([('draft','Draft'), ('done','Done')], 'State', readonly=True, 'state': fields.selection([('draft','Draft'), ('done','Done')], 'State', readonly=True,
help='When monthly periods are created. The state is \'Draft\'. At the end of monthly period it is in \'Done\' state.'), help='When monthly periods are created. The state is \'Draft\'. At the end of monthly period it is in \'Done\' state.'),
'company_id': fields.many2one('res.company', 'Company', required=True) 'company_id': fields.related('fiscalyear_id','company_id',type='many2one',relation='res.company',string='Company',store=True)
} }
_defaults = { _defaults = {
'state': lambda *a: 'draft', 'state': lambda *a: 'draft',
@ -783,7 +787,15 @@ class account_period(osv.osv):
if not ids: if not ids:
ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit) ids = self.search(cr, user, [('name',operator,name)]+ args, limit=limit)
return self.name_get(cr, user, ids, context=context) return self.name_get(cr, user, ids, context=context)
def write(self, cr, uid, ids, vals, context=None):
obj=[]
if 'company_id' in vals:
obj=self.pool.get('account.move.line').search(cr, uid, [('period_id', '=', ids)])
if obj:
raise osv.except_osv(_('Warning !'), _('You cannot update Company as its related record exist in Entry Lines'))
return super(account_period, self).write(cr, uid, ids, vals, context=context)
account_period() account_period()
class account_journal_period(osv.osv): class account_journal_period(osv.osv):
@ -809,7 +821,7 @@ class account_journal_period(osv.osv):
'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'State', required=True, readonly=True, 'state': fields.selection([('draft','Draft'), ('printed','Printed'), ('done','Done')], 'State', 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.'), 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'), 'fiscalyear_id': fields.related('period_id', 'fiscalyear_id', string='Fiscal Year', type='many2one', relation='account.fiscalyear'),
'company_id' : fields.many2one('res.company', 'Company') 'company_id': fields.related('journal_id','company_id',type='many2one',relation='res.company',string='Company')
} }
def _check(self, cr, uid, ids, context={}): def _check(self, cr, uid, ids, context={}):

View File

@ -497,10 +497,18 @@ class account_move_line(osv.osv):
if l.account_id.type == 'closed': if l.account_id.type == 'closed':
return False return False
return True return True
def _check_company_id(self, cr, uid, ids):
lines = self.browse(cr, uid, ids)
for l in lines:
if l.company_id == l.account_id.company_id and l.company_id == l.period_id.company_id:
return True
return False
_constraints = [ _constraints = [
(_check_no_view, 'You can not create move line on view account.', ['account_id']), (_check_no_view, 'You can not create move line on view account.', ['account_id']),
(_check_no_closed, 'You can not create move line on closed account.', ['account_id']), (_check_no_closed, 'You can not create move line on closed account.', ['account_id']),
(_check_company_id,'Company must be same for its related account and period.',['company_id'] ),
] ]
#TODO: ONCHANGE_ACCOUNT_ID: set account_tax_id #TODO: ONCHANGE_ACCOUNT_ID: set account_tax_id
@ -574,28 +582,37 @@ class account_move_line(osv.osv):
unmerge = [] unmerge = []
total = 0.0 total = 0.0
merges_rec = [] merges_rec = []
for line in self.browse(cr, uid, ids, context): flag=False
if line.reconcile_id: for line in self.browse(cr, uid, ids, context.get('active_ids')):
raise osv.except_osv(_('Warning'), _('Already Reconciled!')) for line1 in self.browse(cr, uid, ids, context.get('active_ids')):
if line.reconcile_partial_id: if line1.company_id == line.company_id:
for line2 in line.reconcile_partial_id.line_partial_ids: flag=True
if not line2.reconcile_id: else:
if line2.id not in merges: raise osv.except_osv(_('Warning !'), _('To reconcile the records Company must be the same'))
merges.append(line2.id) if flag:
total += (line2.debit or 0.0) - (line2.credit or 0.0) for line in self.browse(cr, uid, ids, context):
merges_rec.append(line.reconcile_partial_id.id) if line.reconcile_id:
else: raise osv.except_osv(_('Warning'), _('Already Reconciled!'))
unmerge.append(line.id) if line.reconcile_partial_id:
total += (line.debit or 0.0) - (line.credit or 0.0) for line2 in line.reconcile_partial_id.line_partial_ids:
if not total: if not line2.reconcile_id:
res = self.reconcile(cr, uid, merges+unmerge, context=context) if line2.id not in merges:
return res merges.append(line2.id)
r_id = self.pool.get('account.move.reconcile').create(cr, uid, { total += (line2.debit or 0.0) - (line2.credit or 0.0)
'type': type, merges_rec.append(line.reconcile_partial_id.id)
'line_partial_ids': map(lambda x: (4,x,False), merges+unmerge) else:
}) unmerge.append(line.id)
self.pool.get('account.move.reconcile').reconcile_partial_check(cr, uid, [r_id] + merges_rec, context=context) total += (line.debit or 0.0) - (line.credit or 0.0)
return True
if not total:
res = self.reconcile(cr, uid, merges+unmerge, context=context)
return res
r_id = self.pool.get('account.move.reconcile').create(cr, uid, {
'type': type,
'line_partial_ids': map(lambda x: (4,x,False), merges+unmerge)
})
self.pool.get('account.move.reconcile').reconcile_partial_check(cr, uid, [r_id] + merges_rec, context=context)
return True
def reconcile(self, cr, uid, ids, type='auto', writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False, context={}): def reconcile(self, cr, uid, ids, type='auto', writeoff_acc_id=False, writeoff_period_id=False, writeoff_journal_id=False, context={}):
lines = self.browse(cr, uid, ids, context=context) lines = self.browse(cr, uid, ids, context=context)
@ -604,104 +621,112 @@ class account_move_line(osv.osv):
currency = 0.0 currency = 0.0
account_id = False account_id = False
partner_id = False partner_id = False
for line in unrec_lines: flag=False
if line.state <> 'valid': for line in self.browse(cr, uid, ids, context.get('active_ids')):
raise osv.except_osv(_('Error'), for line1 in self.browse(cr, uid, ids, context.get('active_ids')):
_('Entry "%s" is not valid !') % line.name) if line1.company_id == line.company_id:
credit += line['credit'] flag=True
debit += line['debit'] else:
currency += line['amount_currency'] or 0.0 raise osv.except_osv(_('Warning !'), _('To reconcile the records Company must be the same'))
account_id = line['account_id']['id'] if flag:
partner_id = (line['partner_id'] and line['partner_id']['id']) or False for line in unrec_lines:
writeoff = debit - credit if line.state <> 'valid':
# Ifdate_p in context => take this date raise osv.except_osv(_('Error'),
if context.has_key('date_p') and context['date_p']: _('Entry "%s" is not valid !') % line.name)
date=context['date_p'] credit += line['credit']
else: debit += line['debit']
date = time.strftime('%Y-%m-%d') currency += line['amount_currency'] or 0.0
account_id = line['account_id']['id']
cr.execute('SELECT account_id, reconcile_id \ partner_id = (line['partner_id'] and line['partner_id']['id']) or False
FROM account_move_line \ writeoff = debit - credit
WHERE id =ANY(%s) \ # Ifdate_p in context => take this date
GROUP BY account_id,reconcile_id',(ids,)) if context.has_key('date_p') and context['date_p']:
r = cr.fetchall() date=context['date_p']
#TODO: move this check to a constraint in the account_move_reconcile object
if (len(r) != 1) and not context.get('fy_closing', False):
raise osv.except_osv(_('Error'), _('Entries are not of the same account or already reconciled ! '))
if not unrec_lines:
raise osv.except_osv(_('Error'), _('Entry is already reconciled'))
account = self.pool.get('account.account').browse(cr, uid, account_id, context=context)
if not context.get('fy_closing', False) and not account.reconcile:
raise osv.except_osv(_('Error'), _('The account is not defined to be reconciled !'))
if r[0][1] != None:
raise osv.except_osv(_('Error'), _('Some entries are already reconciled !'))
if (not self.pool.get('res.currency').is_zero(cr, uid, account.company_id.currency_id, writeoff)) or \
(account.currency_id and (not self.pool.get('res.currency').is_zero(cr, uid, account.currency_id, currency))):
if not writeoff_acc_id:
raise osv.except_osv(_('Warning'), _('You have to provide an account for the write off entry !'))
if writeoff > 0:
debit = writeoff
credit = 0.0
self_credit = writeoff
self_debit = 0.0
else: else:
debit = 0.0 date = time.strftime('%Y-%m-%d')
credit = -writeoff
self_credit = 0.0
self_debit = -writeoff
# If comment exist in context, take it cr.execute('SELECT account_id, reconcile_id \
if 'comment' in context and context['comment']: FROM account_move_line \
libelle=context['comment'] WHERE id =ANY(%s) \
else: GROUP BY account_id,reconcile_id',(ids,))
libelle='Write-Off' r = cr.fetchall()
#TODO: move this check to a constraint in the account_move_reconcile object
if (len(r) != 1) and not context.get('fy_closing', False):
raise osv.except_osv(_('Error'), _('Entries are not of the same account or already reconciled ! '))
if not unrec_lines:
raise osv.except_osv(_('Error'), _('Entry is already reconciled'))
account = self.pool.get('account.account').browse(cr, uid, account_id, context=context)
if not context.get('fy_closing', False) and not account.reconcile:
raise osv.except_osv(_('Error'), _('The account is not defined to be reconciled !'))
if r[0][1] != None:
raise osv.except_osv(_('Error'), _('Some entries are already reconciled !'))
writeoff_lines = [ if (not self.pool.get('res.currency').is_zero(cr, uid, account.company_id.currency_id, writeoff)) or \
(0, 0, { (account.currency_id and (not self.pool.get('res.currency').is_zero(cr, uid, account.currency_id, currency))):
'name':libelle, if not writeoff_acc_id:
'debit':self_debit, raise osv.except_osv(_('Warning'), _('You have to provide an account for the write off entry !'))
'credit':self_credit, if writeoff > 0:
'account_id':account_id, debit = writeoff
credit = 0.0
self_credit = writeoff
self_debit = 0.0
else:
debit = 0.0
credit = -writeoff
self_credit = 0.0
self_debit = -writeoff
# If comment exist in context, take it
if 'comment' in context and context['comment']:
libelle=context['comment']
else:
libelle='Write-Off'
writeoff_lines = [
(0, 0, {
'name':libelle,
'debit':self_debit,
'credit':self_credit,
'account_id':account_id,
'date':date,
'partner_id':partner_id,
'currency_id': account.currency_id.id or False,
'amount_currency': account.currency_id.id and -currency or 0.0
}),
(0, 0, {
'name':libelle,
'debit':debit,
'credit':credit,
'account_id':writeoff_acc_id,
'analytic_account_id': context.get('analytic_id', False),
'date':date,
'partner_id':partner_id
})
]
writeoff_move_id = self.pool.get('account.move').create(cr, uid, {
'period_id': writeoff_period_id,
'journal_id': writeoff_journal_id,
'date':date, 'date':date,
'partner_id':partner_id, 'state': 'draft',
'currency_id': account.currency_id.id or False, 'line_id': writeoff_lines
'amount_currency': account.currency_id.id and -currency or 0.0
}),
(0, 0, {
'name':libelle,
'debit':debit,
'credit':credit,
'account_id':writeoff_acc_id,
'analytic_account_id': context.get('analytic_id', False),
'date':date,
'partner_id':partner_id
}) })
]
writeoff_move_id = self.pool.get('account.move').create(cr, uid, { writeoff_line_ids = self.search(cr, uid, [('move_id', '=', writeoff_move_id), ('account_id', '=', account_id)])
'period_id': writeoff_period_id, ids += writeoff_line_ids
'journal_id': writeoff_journal_id,
'date':date, r_id = self.pool.get('account.move.reconcile').create(cr, uid, {
'state': 'draft', #'name': date,
'line_id': writeoff_lines 'type': type,
'line_id': map(lambda x: (4,x,False), ids),
'line_partial_ids': map(lambda x: (3,x,False), ids)
}) })
wf_service = netsvc.LocalService("workflow")
writeoff_line_ids = self.search(cr, uid, [('move_id', '=', writeoff_move_id), ('account_id', '=', account_id)]) # the id of the move.reconcile is written in the move.line (self) by the create method above
ids += writeoff_line_ids # because of the way the line_id are defined: (4, x, False)
for id in ids:
r_id = self.pool.get('account.move.reconcile').create(cr, uid, { wf_service.trg_trigger(uid, 'account.move.line', id, cr)
#'name': date, return r_id
'type': type,
'line_id': map(lambda x: (4,x,False), ids),
'line_partial_ids': map(lambda x: (3,x,False), ids)
})
wf_service = netsvc.LocalService("workflow")
# the id of the move.reconcile is written in the move.line (self) by the create method above
# because of the way the line_id are defined: (4, x, False)
for id in ids:
wf_service.trg_trigger(uid, 'account.move.line', id, cr)
return r_id
def view_header_get(self, cr, user, view_id, view_type, context): def view_header_get(self, cr, user, view_id, view_type, context):
if context.get('account_id', False): if context.get('account_id', False):

View File

@ -39,6 +39,7 @@ class sale_shop(osv.osv):
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'), 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'),
'project_id': fields.many2one('account.analytic.account', 'Analytic Account'), 'project_id': fields.many2one('account.analytic.account', 'Analytic Account'),
'company_id': fields.many2one('res.company', 'Company'),
} }
sale_shop() sale_shop()
@ -277,7 +278,7 @@ class sale_order(osv.osv):
'invoice_quantity': fields.selection([('order', 'Ordered Quantities'), ('procurement', 'Shipped Quantities')], 'Invoice on', help="The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks.", required=True), 'invoice_quantity': fields.selection([('order', 'Ordered Quantities'), ('procurement', 'Shipped Quantities')], 'Invoice on', help="The sale order will automatically create the invoice proposition (draft invoice). Ordered and delivered quantities may not be the same. You have to choose if you invoice based on ordered or shipped quantities. If the product is a service, shipped quantities means hours spent on the associated tasks.", required=True),
'payment_term': fields.many2one('account.payment.term', 'Payment Term'), 'payment_term': fields.many2one('account.payment.term', 'Payment Term'),
'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position'), 'fiscal_position': fields.many2one('account.fiscal.position', 'Fiscal Position'),
'company_id': fields.many2one('res.company','Company',select=1), 'company_id': fields.related('shop_id','company_id',type='many2one',relation='res.company',string='Company',store=True)
} }
_defaults = { _defaults = {
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'sale.order', context=c), 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'sale.order', context=c),

View File

@ -16,6 +16,7 @@
<field model="res.company" name="name" search="[]" use="name"/> <field model="res.company" name="name" search="[]" use="name"/>
<field model="stock.warehouse" name="warehouse_id" search="[]"/> <field model="stock.warehouse" name="warehouse_id" search="[]"/>
<field model="account.payment.term" name="payment_default_id" search="[]"/> <field model="account.payment.term" name="payment_default_id" search="[]"/>
<field model="res.company" name="company_id" search="[]"/>
</record> </record>
<function eval="('default',False,'shop_id', [('sale.order', False)], shop, True, False, False, False, True)" id="sale_default_set" model="ir.values" name="set"/> <function eval="('default',False,'shop_id', [('sale.order', False)], shop, True, False, False, False, True)" id="sale_default_set" model="ir.values" name="set"/>

View File

@ -14,6 +14,7 @@
<form string="Sale Shop"> <form string="Sale Shop">
<field name="name" select="1"/> <field name="name" select="1"/>
<field name="warehouse_id" required="1" select="1" widget="selection"/> <field name="warehouse_id" required="1" select="1" widget="selection"/>
<field name="company_id"/>
<separator colspan="4" string="Accounting"/> <separator colspan="4" string="Accounting"/>
<field name="payment_default_id"/> <field name="payment_default_id"/>
<field domain="[('type','=','sale')]" name="pricelist_id" select="1"/> <field domain="[('type','=','sale')]" name="pricelist_id" select="1"/>