[ADD]: Multi Branch : Sale, Account.

This commit is contained in:
Kunjal 2018-01-17 15:53:19 +05:30
parent dbdbad7ab1
commit 5993da4d2a
44 changed files with 813 additions and 17 deletions

View File

@ -45,6 +45,7 @@ class AccountAccountTag(models.Model):
class AccountAccount(models.Model):
_name = "account.account"
_description = "Account"
_inherit = ['ir.branch.company.mixin']
_order = "code"
@api.multi
@ -84,6 +85,17 @@ class AccountAccount(models.Model):
('code_company_uniq', 'unique (code,company_id)', 'The code of the account must be unique per company !')
]
@api.multi
@api.constrains('branch_id', 'company_id')
def _check_company_branch(self):
for record in self:
if record.branch_id and record.company_id != record.branch_id.company_id:
raise ValidationError(_(
'Configuration Error of Company:\n'
'The Account Company (%s) and the Company (%s) of '
'Branch must be the same!') % (
record.company_id.name, record.branch_id.company_id.name))
def _compute_opening_debit_credit(self):
for record in self:
opening_debit = opening_credit = 0.0
@ -305,6 +317,7 @@ class AccountGroup(models.Model):
class AccountJournal(models.Model):
_name = "account.journal"
_inherit = ['ir.branch.company.mixin']
_description = "Journal"
_order = 'sequence, type, code'
@ -387,6 +400,17 @@ class AccountJournal(models.Model):
('code_company_uniq', 'unique (code, name, company_id)', 'The code and name of the journal must be unique per company !'),
]
@api.multi
@api.constrains('branch_id', 'company_id')
def _check_company_branch(self):
for record in self:
if record.branch_id and record.company_id != record.branch_id.company_id:
raise ValidationError(_(
'Configuration Error of Company:\n'
'The Account Company (%s) and the Company (%s) of '
'Branch must be the same!') % (
record.company_id.name, record.branch_id.company_id.name))
@api.multi
# do not depend on 'sequence_id.date_range_ids', because
# sequence_id._get_current_sequence() may invalidate it!
@ -720,6 +744,7 @@ class AccountTaxGroup(models.Model):
class AccountTax(models.Model):
_name = 'account.tax'
_inherit = ['ir.branch.company.mixin']
_description = 'Tax'
_order = 'sequence,id'
@ -1008,6 +1033,7 @@ class AccountTax(models.Model):
class AccountReconcileModel(models.Model):
_name = "account.reconcile.model"
_inherit = ['ir.branch.company.mixin']
_description = "Preset to create journal entries during a invoices and payments matching"
name = fields.Char(string='Button Label', required=True)

View File

@ -144,6 +144,8 @@ class AccountBankStatement(models.Model):
journal_type = fields.Selection(related='journal_id.type', help="Technical field used for usability purposes")
company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', store=True, readonly=True,
default=lambda self: self.env['res.company']._company_default_get('account.bank.statement'))
branch_id = fields.Many2one(related='journal_id.branch_id',
string='Branch', store=True, readonly=True)
total_entry_encoding = fields.Monetary('Transactions Subtotal', compute='_end_balance', store=True, help="Total of transaction lines.")
balance_end = fields.Monetary('Computed Balance', compute='_end_balance', store=True, help='Balance as calculated based on Opening Balance and transaction lines')
@ -366,6 +368,8 @@ class AccountBankStatementLine(models.Model):
note = fields.Text(string='Notes')
sequence = fields.Integer(index=True, help="Gives the sequence order when displaying a list of bank statement lines.", default=1)
company_id = fields.Many2one('res.company', related='statement_id.company_id', string='Company', store=True, readonly=True)
branch_id = fields.Many2one(related='statement_id.branch_id',
string='Company', store=True, readonly=True)
journal_entry_ids = fields.One2many('account.move.line', 'statement_line_id', 'Journal Items', copy=False, readonly=True)
amount_currency = fields.Monetary(help="The amount expressed in an optional other currency if it is a multi-currency entry.")
currency_id = fields.Many2one('res.currency', string='Currency', help="The optional other currency if it is a multi-currency entry.")

View File

@ -41,7 +41,8 @@ MAGIC_COLUMNS = ('id', 'create_uid', 'create_date', 'write_uid', 'write_date')
class AccountInvoice(models.Model):
_name = "account.invoice"
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin']
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin',
'ir.branch.company.mixin']
_description = "Invoice"
_order = "date_invoice desc, number desc, id desc"
@ -383,6 +384,18 @@ class AccountInvoice(models.Model):
domain += [('journal_id', '=', self.journal_id.id), ('state', 'not in', ['draft', 'cancel'])]
return journal_sequence, domain
@api.constrains('company_id', 'branch_id')
def _check_company(self):
for order in self:
if order.branch_id and order.company_id != order.branch_id.company_id:
raise ValidationError(
_('Configuration Error of Company:\n'
'The Invoice Company (%s) and '
'the Company (%s) of Branch must '
'be the same company!') % (order.company_id.name,
order.branch_id.company_id.name)
)
def _compute_portal_url(self):
super(AccountInvoice, self)._compute_portal_url()
for order in self:
@ -1131,6 +1144,7 @@ class AccountInvoice(models.Model):
date = inv.date or inv.date_invoice
move_vals = {
'ref': inv.reference,
'branch_id': inv.branch_id and inv.branch_id.id,
'line_ids': line,
'journal_id': journal.id,
'date': date,
@ -1493,6 +1507,9 @@ class AccountInvoiceLine(models.Model):
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags')
company_id = fields.Many2one('res.company', string='Company',
related='invoice_id.company_id', store=True, readonly=True, related_sudo=False)
branch_id = fields.Many2one(string='Company',
related='invoice_id.branch_id', store=True,
readonly=True, related_sudo=False)
partner_id = fields.Many2one('res.partner', string='Partner',
related='invoice_id.partner_id', store=True, readonly=True, related_sudo=False)
currency_id = fields.Many2one('res.currency', related='invoice_id.currency_id', store=True, related_sudo=False)
@ -1676,6 +1693,9 @@ class AccountInvoiceTax(models.Model):
manual = fields.Boolean(default=True)
sequence = fields.Integer(help="Gives the sequence order when displaying a list of invoice tax.")
company_id = fields.Many2one('res.company', string='Company', related='account_id.company_id', store=True, readonly=True)
branch_id = fields.Many2one(string='Branch',
related='account_id.branch_id', store=True,
readonly=True)
currency_id = fields.Many2one('res.currency', related='invoice_id.currency_id', store=True, readonly=True)
base = fields.Monetary(string='Base', compute='_compute_base_amount', store=True)
@ -1687,6 +1707,7 @@ class AccountInvoiceTax(models.Model):
class AccountPaymentTerm(models.Model):
_name = "account.payment.term"
_inherit = ['ir.branch.company.mixin']
_description = "Payment Terms"
_order = "sequence, id"

View File

@ -19,6 +19,7 @@ class AccountMove(models.Model):
_name = "account.move"
_description = "Account Entry"
_order = 'date desc, id desc'
_inherit = ['ir.branch.company.mixin']
@api.multi
@api.depends('name', 'state')
@ -445,6 +446,8 @@ class AccountMoveLine(models.Model):
analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic tags')
company_id = fields.Many2one('res.company', related='account_id.company_id', string='Company', store=True)
branch_id = fields.Many2one(related='move_id.branch_id', string='Branch',
store=True)
counterpart = fields.Char("Counterpart", compute='_get_counterpart', help="Compute the counter part accounts of this journal item for this journal entry. This can be needed in reports.")
# TODO: put the invoice link and partner_id on the account_move
@ -463,6 +466,31 @@ class AccountMoveLine(models.Model):
('credit_debit2', 'CHECK (credit+debit>=0)', 'Wrong credit or debit value in accounting entry !'),
]
@api.constrains('move_id', 'branch_id')
def _check_branch(self):
for order in self:
move_branch_id = order.move_id.branch_id
if order.branch_id and move_branch_id != order.branch_id:
raise ValidationError(
_('Configuration Error of Branch:\n'
'The Move Line Branch (%s) and '
'the Branch (%s) of Journal Entry must '
'be the same branch!') % (order.branch_id.name,
move_branch_id.name)
)
@api.constrains('company_id', 'branch_id')
def _check_company(self):
for order in self:
if order.branch_id and order.company_id != order.branch_id.company_id:
raise ValidationError(
_('Configuration Error of Company:\n'
'The Move Line Company (%s) and '
'the Company (%s) of Branch must '
'be the same company!') % (order.company_id.name,
order.branch_id.company_id.name)
)
@api.model
def default_get(self, fields):
rec = super(AccountMoveLine, self).default_get(fields)
@ -1446,6 +1474,7 @@ class AccountMoveLine(models.Model):
return {
'name': self.name,
'date': self.date,
'branch_id': self.branch_id and self.branch_id.id,
'account_id': self.analytic_account_id.id,
'tag_ids': [(6, 0, self.analytic_tag_ids.ids)],
'unit_amount': self.quantity,
@ -1538,6 +1567,8 @@ class AccountPartialReconcile(models.Model):
company_currency_id = fields.Many2one('res.currency', related='company_id.currency_id', readonly=True,
help='Utility field to express amount currency')
company_id = fields.Many2one('res.company', related='debit_move_id.company_id', store=True, string='Currency')
branch_id = fields.Many2one(related='debit_move_id.branch_id', store=True,
string='Branch')
full_reconcile_id = fields.Many2one('account.full.reconcile', string="Full Reconcile", copy=False)
max_date = fields.Date(string='Max Date of Matched Lines', compute='_compute_max_date',
readonly=True, copy=False, store=True,

View File

@ -49,6 +49,8 @@ class account_abstract_payment(models.AbstractModel):
communication = fields.Char(string='Memo')
journal_id = fields.Many2one('account.journal', string='Payment Journal', required=True, domain=[('type', 'in', ('bank', 'cash'))])
company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', readonly=True)
branch_id = fields.Many2one(related='journal_id.branch_id',
string='Branch', readonly=True)
hide_payment_method = fields.Boolean(compute='_compute_hide_payment_method',
help="Technical field used to hide the payment method if the selected journal has only one available which is 'manual'")
@ -238,7 +240,7 @@ class account_register_payments(models.TransientModel):
class account_payment(models.Model):
_name = "account.payment"
_inherit = ['mail.thread', 'account.abstract.payment']
_inherit = ['mail.thread', 'account.abstract.payment', 'ir.branch.company.mixin']
_description = "Payments"
_order = "payment_date desc, name desc"

View File

@ -57,6 +57,7 @@ def preserve_existing_tags_on_taxes(cr, registry, module):
class AccountAccountTemplate(models.Model):
_name = "account.account.template"
_description = 'Templates for Accounts'
_inherit = ['ir.branch.company.mixin']
_order = "code"
name = fields.Char(required=True, index=True)
@ -498,6 +499,7 @@ class AccountChartTemplate(models.Model):
class AccountTaxTemplate(models.Model):
_name = 'account.tax.template'
_inherit = ['ir.branch.company.mixin']
_description = 'Templates for Taxes'
_order = 'id'
@ -621,6 +623,7 @@ class AccountTaxTemplate(models.Model):
class AccountFiscalPositionTemplate(models.Model):
_name = 'account.fiscal.position.template'
_inherit = ['ir.branch.company.mixin']
_description = 'Template for Fiscal Position'
sequence = fields.Integer()
@ -642,6 +645,7 @@ class AccountFiscalPositionTemplate(models.Model):
class AccountFiscalPositionTaxTemplate(models.Model):
_name = 'account.fiscal.position.tax.template'
_inherit = ['ir.branch.company.mixin']
_description = 'Template Tax Fiscal Position'
_rec_name = 'position_id'
@ -653,6 +657,7 @@ class AccountFiscalPositionTaxTemplate(models.Model):
class AccountFiscalPositionAccountTemplate(models.Model):
_name = 'account.fiscal.position.account.template'
_description = 'Template Account Fiscal Mapping'
_inherit = ['ir.branch.company.mixin']
_rec_name = 'position_id'
position_id = fields.Many2one('account.fiscal.position.template', string='Fiscal Mapping', required=True, ondelete='cascade')
@ -961,6 +966,7 @@ class AccountBankAccountsWizard(models.TransientModel):
class AccountReconcileModelTemplate(models.Model):
_name = "account.reconcile.model.template"
_inherit = ['ir.branch.company.mixin']
chart_template_id = fields.Many2one('account.chart.template', string='Chart Template', required=True)
name = fields.Char(string='Button Label', required=True)

View File

@ -11,6 +11,7 @@ from flectra.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP
class AccountFiscalPosition(models.Model):
_name = 'account.fiscal.position'
_inherit = ['ir.branch.company.mixin']
_description = 'Fiscal Position'
_order = 'sequence'
@ -164,6 +165,7 @@ class AccountFiscalPosition(models.Model):
class AccountFiscalPositionTax(models.Model):
_name = 'account.fiscal.position.tax'
_inherit = ['ir.branch.company.mixin']
_description = 'Taxes Fiscal Position'
_rec_name = 'position_id'
@ -182,6 +184,7 @@ class AccountFiscalPositionTax(models.Model):
class AccountFiscalPositionAccount(models.Model):
_name = 'account.fiscal.position.account'
_description = 'Accounts Fiscal Position'
_inherit = ['ir.branch.company.mixin']
_rec_name = 'position_id'
position_id = fields.Many2one('account.fiscal.position', string='Fiscal Position',

View File

@ -29,6 +29,10 @@ class ReportAgedPartnerBalance(models.AbstractModel):
cr = self.env.cr
user_company = self.env.user.company_id.id
move_state = ['draft', 'posted']
branch_id = data['form'].get('branch_id', False)
branch = ''
if branch_id:
branch = 'AND (l.branch_id =' + str(branch_id[0]) + ')'
if target_move == 'posted':
move_state = ['posted']
arg_list = (tuple(move_state), tuple(account_type))
@ -49,7 +53,7 @@ class ReportAgedPartnerBalance(models.AbstractModel):
AND (l.move_id = am.id)
AND (am.state IN %s)
AND (account_account.internal_type IN %s)
AND ''' + reconciliation_clause + '''
AND ''' + reconciliation_clause + branch +'''
AND (l.date <= %s)
AND l.company_id = %s
ORDER BY UPPER(res_partner.name)'''
@ -75,7 +79,7 @@ class ReportAgedPartnerBalance(models.AbstractModel):
AND (account_account.internal_type IN %s)
AND (COALESCE(l.date_maturity,l.date) > %s)\
AND ((l.partner_id IN %s) OR (l.partner_id IS NULL))
AND (l.date <= %s)
AND (l.date <= %s) ''' + branch + '''
AND l.company_id = %s'''
cr.execute(query, (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from, user_company))
aml_ids = cr.fetchall()
@ -125,7 +129,7 @@ class ReportAgedPartnerBalance(models.AbstractModel):
AND (am.state IN %s)
AND (account_account.internal_type IN %s)
AND ((l.partner_id IN %s) OR (l.partner_id IS NULL))
AND ''' + dates_query + '''
AND ''' + dates_query + branch +'''
AND (l.date <= %s)
AND l.company_id = %s'''
cr.execute(query, args_list)

View File

@ -6,6 +6,7 @@ from flectra import models, fields, api
class AccountInvoiceReport(models.Model):
_name = "account.invoice.report"
_inherit = ['ir.branch.company.mixin']
_description = "Invoices Statistics"
_auto = False
_rec_name = 'date'
@ -72,7 +73,7 @@ class AccountInvoiceReport(models.Model):
_depends = {
'account.invoice': [
'account_id', 'amount_total_company_signed', 'commercial_partner_id', 'company_id',
'account_id', 'amount_total_company_signed', 'commercial_partner_id', 'company_id', 'branch_id',
'currency_id', 'date_due', 'date_invoice', 'fiscal_position_id',
'journal_id', 'partner_bank_id', 'partner_id', 'payment_term_id',
'residual', 'state', 'type', 'user_id',
@ -92,7 +93,7 @@ class AccountInvoiceReport(models.Model):
select_str = """
SELECT sub.id, sub.date, sub.product_id, sub.partner_id, sub.country_id, sub.account_analytic_id,
sub.payment_term_id, sub.uom_name, sub.currency_id, sub.journal_id,
sub.fiscal_position_id, sub.user_id, sub.company_id, sub.nbr, sub.type, sub.state,
sub.fiscal_position_id, sub.user_id, sub.company_id, sub.branch_id, sub.nbr, sub.type, sub.state,
sub.categ_id, sub.date_due, sub.account_id, sub.account_line_id, sub.partner_bank_id,
sub.product_qty, sub.price_total as price_total, sub.price_average as price_average,
COALESCE(cr.rate, 1) as currency_rate, sub.residual as residual, sub.commercial_partner_id as commercial_partner_id
@ -105,7 +106,7 @@ class AccountInvoiceReport(models.Model):
ai.date_invoice AS date,
ail.product_id, ai.partner_id, ai.payment_term_id, ail.account_analytic_id,
u2.name AS uom_name,
ai.currency_id, ai.journal_id, ai.fiscal_position_id, ai.user_id, ai.company_id,
ai.currency_id, ai.journal_id, ai.fiscal_position_id, ai.user_id, ai.company_id, ai.branch_id,
1 AS nbr,
ai.type, ai.state, pt.categ_id, ai.date_due, ai.account_id, ail.account_id AS account_line_id,
ai.partner_bank_id,
@ -148,7 +149,7 @@ class AccountInvoiceReport(models.Model):
group_by_str = """
GROUP BY ail.id, ail.product_id, ail.account_analytic_id, ai.date_invoice, ai.id,
ai.partner_id, ai.payment_term_id, u2.name, u2.id, ai.currency_id, ai.journal_id,
ai.fiscal_position_id, ai.user_id, ai.company_id, ai.type, invoice_type.sign, ai.state, pt.categ_id,
ai.fiscal_position_id, ai.user_id, ai.company_id, ai.branch_id, ai.type, invoice_type.sign, ai.state, pt.categ_id,
ai.date_due, ai.account_id, ail.account_id, ai.partner_bank_id, ai.residual_company_signed,
ai.amount_total_company_signed, ai.commercial_partner_id, partner.country_id
"""

View File

@ -44,6 +44,73 @@
<field name="groups_id" eval="[(4,ref('account.group_account_manager'))]"/>
</record>
<!-- Multi Branch -->
<record id="account_move_multi_branch_rule" model="ir.rule">
<field name="name">Account Entry Multi Branch</field>
<field name="model_id" ref="model_account_move"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record id="account_move_line_multi_branch_rule" model="ir.rule">
<field name="name">Entry lines Multi Branch</field>
<field name="model_id" ref="model_account_move_line"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record id="invoice_multi_branch_rule" model="ir.rule">
<field name="name">Invoice multi-branch</field>
<field name="model_id" ref="model_account_invoice"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record id="invoice_analysis_multi_branch_rule" model="ir.rule">
<field name="name">Invoice Analysis multi-branch</field>
<field name="model_id" ref="model_account_invoice_report"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="account_invoice_line_multi_branch_rule">
<field name="name">Invoice Line branch rule</field>
<field name="model_id" ref="model_account_invoice_line"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="account_bank_statement_multi_branch_rule">
<field name="name">Account bank statement branch rule</field>
<field name="model_id" ref="model_account_bank_statement"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="account_bank_statement_line_multi_branch_rule">
<field name="name">Account bank statement line branch rule</field>
<field name="model_id" ref="model_account_bank_statement_line"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="account_reconcile_model_templatemulti_branch_rule">
<field name="name">Account reconcile model template company rule</field>
<field name="model_id" ref="model_account_reconcile_model"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="account_payment_multi_branch_rule">
<field name="name">Account payment company rule</field>
<field name="model_id" ref="model_account_payment"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<!-- Multi Company -->
<record id="account_move_comp_rule" model="ir.rule">
<field name="name">Account Entry</field>
<field name="model_id" ref="model_account_move"/>

View File

@ -18,3 +18,8 @@ from . import test_search
from . import test_setup_bar
from . import test_tax
from . import test_templates_consistency
from . import test_account_branch
from . import test_invoice_branch
from . import test_journal_entries_branch
from . import test_branch_moves
from . import test_payment_branch

View File

@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
from flectra.addons.account.tests.account_test_classes import AccountingTestCase
class TestAccountBranch(AccountingTestCase):
def setUp(self):
super(TestAccountBranch, self).setUp()
self.apple_product = self.env.ref('product.product_product_7')
self.keyboard_product = self.env.ref('product.product_product_9')
self.ipod_product = self.env.ref('product.product_product_11')
self.asset_account = self.env.ref('l10n_generic_coa.conf_stk')
self.model_account_journal = self.env['account.journal']
self.model_account = self.env['account.account']
self.main_company = self.env.ref('base.main_company')
self.manager_group = self.env.ref('account.group_account_manager')
self.model_user = self.env['res.users']
self.model_account_invoice = self.env['account.invoice']
self.account_partner = self.env.ref('base.res_partner_1')
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
self.branch_3 = self.env.ref('base_branch_company.data_branch_3')
user_type = self.env.ref('account.data_account_type_liquidity')
self.account_type = self.env.ref('account.data_account_type_expenses')
self.user_id = self.model_user.with_context(
{'no_reset_password': True}).create({
'company_id': self.main_company.id,
'branch_ids': [(4, self.branch_2.id), (4, self.branch_3.id)],
'company_ids': [(4, self.main_company.id)],
'groups_id': [(6, 0, [self.manager_group.id])],
'name': 'Test User 1',
'email': 'demo@yourcompany.com',
'password': '123',
'login': 'tes_user_1',
})
self.user_2 = self.model_user.with_context({
'no_reset_password': True}).create({
'company_id': self.main_company.id,
'branch_ids': [(4, self.branch_3.id)],
'company_ids': [(4, self.main_company.id)],
'groups_id': [(6, 0, [self.manager_group.id])],
'name': 'Test User',
'email': 'demo@yourcompany.com',
'password': '123',
'login': 'test_user_2',
})
self.cash_account = self.model_account.create({
'company_id': self.main_company.id,
'user_type_id': user_type.id,
'code': 'cash_test',
'name': 'Test Cash Account',
})
self.cash_journal = self.model_account_journal.create({
'company_id': self.main_company.id,
'branch_id': self.branch_1.id,
'name': 'Cash Journal - Branch 1',
'default_credit_account_id': self.cash_account.id,
'default_debit_account_id': self.cash_account.id,
'type': 'cash',
'code': 'cash_branch_1',
})
def invoice_values(self, branch_id):
products = [(self.apple_product, 1000),
(self.keyboard_product, 500),
(self.ipod_product, 800)]
lines_data = []
account_id = self.model_account.search([
('user_type_id', '=', self.account_type.id)], limit=1).id
for product_id, quantity in products:
values = {
'product_id': product_id.id,
'name': product_id.name,
'price_unit': 120,
'quantity': quantity,
'account_id': account_id
}
lines_data.append((0, 0, values))
vals = {
'partner_id': self.account_partner.id,
'type': 'in_invoice',
'name': "Supplier Invoice",
# 'reference_type': "none",
'account_id': self.account_partner.property_account_payable_id.id,
'invoice_line_ids': lines_data,
'branch_id': branch_id,
}
return vals

View File

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
from . import test_account_branch
class TestBranchJournalEntries(test_account_branch.TestAccountBranch):
def test_branch_security_move_line(self):
move_ids = self.env['account.move.line'].sudo(self.user_2.id).\
search([('branch_id', '=', self.branch_2.id)])
self.assertFalse(move_ids, 'USer 2 should not have access to move lines with Branch %s'
% self.branch_2.name)

View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from . import test_account_branch
class TestInvoiceBranch(test_account_branch.TestAccountBranch):
def test_invoice_create(self):
self.invoice_id = self.model_account_invoice.sudo(self.user_id.id).create(self.invoice_values(self.branch_2.id))
invoices = self.model_account_invoice.sudo(self.user_2.id).search([('branch_id', '=', self.branch_2.id)])
self.assertFalse(invoices, 'USer 2 should not have access to Invoice with Branch %s'
% self.branch_2.name)
self.invoice_id.sudo(self.user_id.id).action_invoice_open()
all_branch = all(move_line_id.branch_id.id == self.branch_2.id for
move_line_id in self.invoice_id.move_id.line_ids)
self.assertNotEqual(all_branch, False, 'Journal Entries have different Branch.')

View File

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
from . import test_account_branch
class TestJournalEntryBranch(test_account_branch.TestAccountBranch):
def test_journal_entries_branch(self):
journal_ids = self.model_account_journal.search([('code', '=', 'MISC')],
limit=1)
move_vals = self.env['account.move'].default_get([])
lines = [
(0, 0, {
'name': 'Test',
'account_id': self.asset_account.id,
'debit': 0,
'credit': 100,
'branch_id': self.branch_1.id,
}),
(0, 0, {
'name': 'Test',
'account_id': self.asset_account.id,
'debit': 100,
'credit': 0,
'branch_id': self.branch_1.id,
})
]
move_vals.update({
'journal_id': journal_ids and journal_ids.id,
'line_ids': lines,
})
move = self.env['account.move'].sudo(self.user_id.id).create(move_vals)
move.post()
def _check_balance(self, account_id, acc_type='clearing'):
domain = [('account_id', '=', account_id)]
balance = self._get_balance(domain)
self.assertEqual(balance, 0.0, 'Balance is 0 for all Branch.')
domain = [('account_id', '=', account_id),
('branch_id', '=', self.branch_2.id)]
balance = self._get_balance(domain)
if acc_type == 'other':
self.assertEqual(balance, -100,
'Balance is -100 for Branch.')
else:
self.assertEqual(balance, 100,
'Balance is 100 for Branch.')
domain = [('account_id', '=', account_id),
('branch_id', '=', self.branch_3.id)]
balance = self._get_balance(domain)
if acc_type == 'other':
self.assertEqual(balance, 100.0,
'Balance is 100 for Branch')
else:
self.assertEqual(balance, -100.0,
'Balance is -100 for Branch')
def _get_balance(self, domain):
aml_rec = self.env['account.move.line'].sudo(self.user_id.id).read_group(domain,['debit', 'credit', 'account_id'], ['account_id'])
if aml_rec:
aml_rec = aml_rec[0]
a = aml_rec.get('debit', 0) - aml_rec.get('credit', 0)
return a

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from flectra.addons.account.tests import test_account_branch
import time
class TestPaymentsBranch(test_account_branch.TestAccountBranch):
def test_payment_branch(self):
self.invoice_id = self.model_account_invoice.sudo(self.user_id.id).create(
self.invoice_values(self.branch_2.id))
self.invoice_id.sudo(self.user_id.id).action_invoice_open()
context = {'active_ids': [self.invoice_id.id], 'active_model': 'account.invoice'}
create_payments = self.env['account.register.payments'].sudo(self.user_id.id).with_context(context).create({
'payment_method_id': self.env.ref("account.account_payment_method_manual_in").id,
'journal_id': self.cash_journal.id,
'payment_date': time.strftime('%Y') + '-12-17',
})
create_payments.create_payments()
payment = self.env['account.payment'].sudo(self.user_2.id).search([('branch_id', '=', self.branch_2.id)])
self.assertFalse(payment, 'USer 2 should not have access to Payments with Branch %s'
% self.branch_2.name)

View File

@ -330,6 +330,7 @@
</group>
<group>
<field name="fiscal_position_id" options="{'no_create': True}" placeholder="Auto-detect"/>
<field name="branch_id" options="{'no_create': True, 'no_open': True}"/>
<field name="move_id" groups="account.group_account_user" attrs="{'invisible': [('move_id', '=', False)]}"/>
<field name="date" domain="[('state', '=', 'draft'), ('company_id', '=', company_id)]" groups="account.group_account_user"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
@ -477,6 +478,7 @@
<field domain="[('company_id', '=', company_id),('internal_type','=', 'receivable'), ('deprecated', '=', False)]"
name="account_id" groups="account.group_account_user"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="branch_id" options="{'no_create': True}"/>
<field domain="[('partner_id.ref_company_ids', 'in', [company_id])]" name="partner_bank_id" invisible="1"/>
</group>
<group>

View File

@ -1155,6 +1155,7 @@
<field name="move_id" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="statement_id" readonly="True" attrs="{'invisible': [('statement_id','=',False)]}"/>
<field name="invoice_id" attrs="{'invisible': [('invoice_id','=',False)]}"/>
<field name="branch_id"/>
</group>
<group string="Dates">
<field name="date_maturity"/>
@ -1227,6 +1228,7 @@
<field name="partner_id"/>
<field name="account_id" options='{"no_open":True}' domain="[('company_id', '=', company_id)]" groups="account.group_account_user"/>
<field name="analytic_account_id" groups="account.group_account_user"/>
<field name="branch_id"/>
<field name="reconciled" invisible="1"/>
<field name="full_reconcile_id"/>
<field name="debit" sum="Total Debit"/>
@ -1304,6 +1306,7 @@
<field name="move_id" string="Number (Move)"/>
<field name="tax_line_id"/>
<field name="tax_ids" />
<field name="branch_id"/>
<group expand="0" string="Group By">
<filter string="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Journal" domain="[]" context="{'group_by':'journal_id'}"/>
@ -1371,6 +1374,7 @@
<field name="partner_id"/>
<field name="ref"/>
<field name="journal_id"/>
<field name="branch_id"/>
<field name="amount" sum="Total Amount"/>
<field name="state"/>
<field name="currency_id" invisible="1"/>
@ -1452,6 +1456,7 @@
<group>
<field name="journal_id" options="{'no_open': True, 'no_create': True}"/>
<field name="company_id" required="1" groups="base.group_multi_company"/>
<field name="branch_id" options="{'no_create': True}"/>
<field name="amount" invisible="1"/>
<field name="currency_id" invisible="1"/>
</group>
@ -1465,6 +1470,7 @@
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"/>
<field name="name"/>
<field name="branch_id"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" groups="analytic.group_analytic_accounting"/>
<field name="amount_currency" groups="base.group_multi_currency"/>

View File

@ -40,6 +40,10 @@
<t t-if="data['date_from']"><strong>Date from :</strong> <span t-esc="data['date_from']"/><br/></t>
<t t-if="data['date_to']"><strong>Date to :</strong> <span t-esc="data['date_to']"/></t>
</div>
<div class="col-xs-4">
<strong>Branch:</strong>
<p t-if="data['branch_id']"><span t-esc="data['branch_id'][1]"/></p>
</div>
</div>
<table class="table table-condensed">

View File

@ -48,6 +48,10 @@
<strong>Reference:</strong>
<p t-field="o.reference"/>
</div>
<div name="branch" class="col-xs-2" t-if="o.branch_id">
<strong>Branch:</strong>
<p t-field="o.branch_id.name"/>
</div>
</div>
<!-- Is there a discount on at least one line? -->

View File

@ -24,6 +24,10 @@
<p t-if="data['form']['target_move'] == 'all'">All Entries</p>
<p t-if="data['form']['target_move'] == 'posted'">All Posted Entries</p>
</div>
<div class="col-xs-3">
<strong>Branch:</strong>
<p t-if="data['form']['branch_id']"><span t-esc="data['form']['branch_id'][1]"/></p>
</div>
</div>
<table class="table table-condensed">

View File

@ -12,6 +12,8 @@
<field name="date_from"/>
<field name="period_length"/>
<newline/>
<field name="branch_id"/>
<newline/>
<field name="result_selection" widget="radio"/>
<field name="target_move" widget="radio"/>
</group>

View File

@ -6,6 +6,7 @@ from flectra import api, fields, models, _
class AccountCommonReport(models.TransientModel):
_name = "account.common.report"
_description = "Account Common Report"
_inherit = ['ir.branch.company.mixin']
company_id = fields.Many2one('res.company', string='Company', readonly=True, default=lambda self: self.env.user.company_id)
journal_ids = fields.Many2many('account.journal', string='Journals', required=True, default=lambda self: self.env['account.journal'].search([]))
@ -21,6 +22,7 @@ class AccountCommonReport(models.TransientModel):
result['state'] = 'target_move' in data['form'] and data['form']['target_move'] or ''
result['date_from'] = data['form']['date_from'] or False
result['date_to'] = data['form']['date_to'] or False
result['branch_id'] = data['form']['branch_id'] or False
result['strict_range'] = True if result['date_from'] else False
return result
@ -33,7 +35,7 @@ class AccountCommonReport(models.TransientModel):
data = {}
data['ids'] = self.env.context.get('active_ids', [])
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move'])[0]
data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move', 'branch_id'])[0]
used_context = self._build_contexts(data)
data['form']['used_context'] = dict(used_context, lang=self.env.context.get('lang') or 'en_US')
return self._print_report(data)

View File

@ -12,6 +12,12 @@
<field name="date_from"/>
<field name="date_to"/>
</group>
<group col="2">
<group>
<field name="branch_id"/>
</group>
</group>
<group>
<field name="journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
</group>

View File

@ -4,7 +4,7 @@
from flectra import fields, models, api, _
from flectra.addons import decimal_precision as dp
from flectra.exceptions import UserError
from flectra.exceptions import UserError, ValidationError
class AccountVoucher(models.Model):
@ -46,7 +46,7 @@ class AccountVoucher(models.Model):
narration = fields.Text('Notes', readonly=True, states={'draft': [('readonly', False)]})
currency_id = fields.Many2one('res.currency', compute='_get_journal_currency',
string='Currency', readonly=True, required=True, default=lambda self: self._get_currency())
company_id = fields.Many2one('res.company', 'Company',
company_id = fields.Many2one('res.company', 'Company', store=True,
required=True, readonly=True, states={'draft': [('readonly', False)]},
related='journal_id.company_id', default=lambda self: self._get_company())
state = fields.Selection([
@ -74,6 +74,20 @@ class AccountVoucher(models.Model):
('pay_later', 'Pay Later'),
], 'Payment', index=True, readonly=True, states={'draft': [('readonly', False)]}, default='pay_later')
date_due = fields.Date('Due Date', readonly=True, index=True, states={'draft': [('readonly', False)]})
branch_id = fields.Many2one('res.branch', 'Branch', ondelete="restrict",
default=lambda self: self.env['res.users']._get_default_branch())
@api.constrains('company_id', 'branch_id')
def _check_company_branch(self):
for record in self:
if record.branch_id and record.company_id != record.branch_id.company_id:
raise ValidationError(
_('Configuration Error of Company:\n'
'The Company (%s) in the voucher and '
'the Company (%s) of Branch must '
'be the same company!') % (record.company_id.name,
record.branch_id.company_id.name)
)
@api.one
@api.depends('move_id.line_ids.reconciled', 'move_id.line_ids.account_id.internal_type')
@ -186,6 +200,7 @@ class AccountVoucher(models.Model):
'date': self.account_date,
'date_maturity': self.date_due,
'payment_id': self._context.get('payment_id'),
'branch_id': self.branch_id.id,
}
return move_line
@ -199,13 +214,13 @@ class AccountVoucher(models.Model):
name = self.journal_id.sequence_id.with_context(ir_sequence_date=self.date).next_by_id()
else:
raise UserError(_('Please define a sequence on the journal.'))
move = {
'name': name,
'journal_id': self.journal_id.id,
'narration': self.narration,
'date': self.account_date,
'ref': self.reference,
'branch_id': self.branch_id.id
}
return move
@ -361,6 +376,10 @@ class AccountVoucherLine(models.Model):
company_id = fields.Many2one('res.company', related='voucher_id.company_id', string='Company', store=True, readonly=True)
tax_ids = fields.Many2many('account.tax', string='Tax', help="Only for tax excluded from price")
currency_id = fields.Many2one('res.currency', related='voucher_id.currency_id')
branch_id = fields.Many2one('res.branch',
related='voucher_id.branch_id',
string='Branch',
readonly=True, store=True)
@api.one
@api.depends('price_unit', 'tax_ids', 'quantity', 'product_id', 'voucher_id.currency_id')

View File

@ -13,5 +13,20 @@
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="ir_rule_voucher_branch"
model="ir.rule">
<field name="model_id" ref="account_voucher.model_account_voucher"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
<field name="name">Vouchers Branch</field>
<field name="global" eval="True"/>
</record>
<record id="ir_rule_voucher_line_branch"
model="ir.rule">
<field name="model_id"
ref="account_voucher.model_account_voucher_line"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
<field name="name">Voucher lines branch</field>
<field name="global" eval="True"/>
</record>
</data>
</flectra>

View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import test_account_voucher_branch
from . import test_voucher_receipt_branch

View File

@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
from datetime import date
from flectra.tests import common
from flectra.api import Environment
class TestAccountVoucherBranch(common.TransactionCase):
def setUp(self):
super(TestAccountVoucherBranch, self).setUp()
self.account_user = self.env.ref('account.group_account_manager')
self.model_account = self.env['account.account']
self.main_company = self.env.ref('base.main_company')
self.model_journal = self.env['account.journal']
self.partner = self.env.ref('base.res_partner_1')
self.model_voucher = self.env['account.voucher']
self.apple_product = self.env.ref('product.product_product_7')
self.model_voucher_line = self.env['account.voucher.line']
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
self.model_users = self.env['res.users']
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
self.income_type = self.env['account.account.type'].search([('name', '=', 'Income')])
account_obj = self.env.ref['account.account']
self.account_receivable = account_obj.create(
{'code': 'X1012', 'name': 'Account Receivable - Test',
'user_type_id': self.env.ref('account.data_account_type_receivable').id,
'reconcile': True})
self.account_1 = self.account_create('acc_code_1', self.income_type.id, self.main_company.id)
self.account_2 = self.account_create('acc_code_2', self.income_type.id, self.main_company.id)
self.journal_1 = self.journal_create('journal_code_1', self.account_1, self.main_company.id)
self.journal_2 = self.journal_create('journal_code_2', self.account_2, self.main_company.id)
self.branch_user_1 = self.user_create(
'branch_user_1', self.branch_1, self.main_company,
[self.branch_1, self.branch_2], [self.account_user])
self.branch_user_2 = self.user_create('branch_user_2', self.branch_2, self.main_company, [self.branch_2],
[self.account_user])
self.account_voucher_1 = self.receipt_create(self.journal_1, self.branch_1)
self.account_voucher_2 = self.receipt_create(self.journal_2, self.branch_2)
def account_create(self, code, type, company_id):
data = {'code': code,
'name': 'Test Sales Account ' + code,
'company_id': company_id,
'user_type_id': type,
}
account_obj = self.model_account.create(data)
return account_obj.id
def journal_create(self, code, account_id, company_id):
data ={
'code': code,
'name': 'Test Sales Account ' + code,
'type': 'sale',
'default_debit_account_id': account_id,
'default_credit_account_id': account_id,
'company_id': company_id
}
journal_obj = self.model_journal.create(data)
return journal_obj.id
def user_create(self, user_name, branch_id, company_id, branch_ids, groups_ids ):
group_ids = [group.id for group in groups_ids]
data = {
'login': user_name,
'name': 'Test User ' + user_name,
'email': 'demo@yourcompany.com',
'branch_id':branch_id.id,
'password': 'test@123',
'company_id': company_id.id,
'groups_id': [(6, 0, group_ids)],
'company_ids': [(4, company_id.id)],
'branch_ids': [(4, branch.id) for branch in branch_ids],
}
user_obj = self.model_users.with_context({'no_reset_password': True}).create(data)
return user_obj.id
def receipt_create(self, journal_id, branch_id):
print ("@@@@@@@@@@@@@@@@",self.receivable_account )
vals = {
'name': 'Test Voucher',
'partner_id': self.partner.id,
'journal_id': journal_id,
'voucher_type': 'sale',
'account_id': self.receivable_account.id,
'branch_id': branch_id.id,
'company_id': self.main_company.id,
'date': date.today(),
}
voucher_obj = self.model_voucher.create(vals)
line_vals = {
'name': self.apple_product.name,
'product_id': self.apple_product.id,
'price_unit': 500,
'quantity': 10,
'account_id': self.receivable_account.id,
'voucher_id': voucher_obj.id,
}
self.model_voucher_line.create(line_vals)
return voucher_obj

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from . import test_account_voucher_branch as test_branch
class TestAccountVoucherReceiptBranch(test_branch.TestAccountVoucherBranch):
def test_account_receipt_voucher(self):
self.account_voucher_1.proforma_voucher()
self.account_voucher_2.proforma_voucher()
branch_1_ids = all(line_id_1.branch_id.id == self.account_voucher_1.branch_id.id
for line_id_1 in self.account_voucher_1.move_id.line_ids)
branch_2_ids = all(line_id_2.branch_id.id == self.account_voucher_2.branch_id.id
for line_id_2 in self.account_voucher_2.move_id.line_ids)
self.assertNotEqual(branch_1_ids, False, 'Journal Entries of receipt has different branch id.')
self.assertNotEqual(branch_2_ids, False, 'Journal Entries of receipt has different branch id.')
self.account_move = self.env['account.move']
account_move_id_1 = self.account_voucher_1.move_id
account_move_id_2 = self.account_voucher_2.move_id
account_move_ids = self.account_move.sudo(self.branch_user_1).search(
[('id', 'in', [account_move_id_1.id, account_move_id_2.id])])
self.assertEqual(len(account_move_ids), 2)
account_move_ids = self.account_move.sudo(self.branch_user_2).search(
[('id', 'in', [account_move_id_1.id, account_move_id_2.id]),
('branch_id', '=', self.branch_2.id)])
self.assertEqual(len(account_move_ids), 1)

View File

@ -233,6 +233,7 @@
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="partner_id" domain="[('customer','=',True)]" string="Customer" context="{'search_default_customer':1, 'show_address': 1}" options='{"always_reload": True}'/>
<field name="pay_now" required="1"/>
<field name="branch_id"/>
<field name="account_id" groups="account.group_account_user"/>
</group>
<group>
@ -346,6 +347,7 @@
<field name="account_id" groups="account.group_account_user"/>
<field name="name" colspan="2" attrs="{'invisible': [('pay_now', '=', 'pay_later')]}"/>
<field name="reference"/>
<field name="branch_id"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
<group>

View File

@ -14,7 +14,7 @@ class AccountAnalyticTag(models.Model):
class AccountAnalyticAccount(models.Model):
_name = 'account.analytic.account'
_inherit = ['mail.thread']
_inherit = ['mail.thread', 'ir.branch.company.mixin']
_description = 'Analytic Account'
_order = 'code, name asc'
@ -105,4 +105,6 @@ class AccountAnalyticLine(models.Model):
tag_ids = fields.Many2many('account.analytic.tag', 'account_analytic_line_tag_rel', 'line_id', 'tag_id', string='Tags', copy=True)
company_id = fields.Many2one(related='account_id.company_id', string='Company', store=True, readonly=True)
branch_id = fields.Many2one(related='account_id.branch_id',
string='Branch', store=True, readonly=True)
currency_id = fields.Many2one(related="company_id.currency_id", string="Currency", readonly=True)

View File

@ -15,6 +15,14 @@
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="account_analytic_account_multi_branch_rule" model="ir.rule">
<field name="name">Analytic Multi Branch</field>
<field name="model_id" ref="model_account_analytic_account"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
</data>
<data noupdate="0">

View File

@ -51,6 +51,7 @@
<field name="account_id"/>
<field name="currency_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="branch_id" />
<field name="unit_amount" sum="Quantity"/>
<field name="amount" sum="Total"/>
</tree>
@ -112,6 +113,7 @@
</group>
<group>
<field name="tag_ids" widget="many2many_tags"/>
<field name="branch_id" options="{'no_create': True}"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="currency_id" options="{'no_create': True}" groups="base.group_multi_currency"/>
</group>
@ -136,6 +138,7 @@
<field name="partner_id"/>
<field name="active" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="branch_id"/>
<field name="debit"/>
<field name="credit"/>
<field name="balance"/>
@ -229,6 +232,7 @@
<field name="tag_ids" widget="many2many_tags"/>
<field name="date"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="branch_id" options="{'no_create': True}"/>
</group>
<group string="Amount">
<field name="amount"/>

View File

@ -38,5 +38,10 @@
<field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),])]"/>
<field name='default_branch_id' ref='data_branch_1'/>
</record>
<record id="base.user_demo" model="res.users">
<field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),ref('data_branch_2'),ref('data_branch_3')])]"/>
<field name='default_branch_id' ref='data_branch_1'/>
</record>
</data>
</flectra>

View File

@ -328,6 +328,7 @@
<field name="partner_id" ref="base.res_partner_3"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="user_id" ref="base.user_demo"/>
<field name="pricelist_id" ref="product.list0"/>
<field name="team_id" ref="sales_team.crm_team_1"/>
@ -338,6 +339,7 @@
<field name="order_id" ref="sale_order_11"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="product_uom_qty">3</field>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">2450.00</field>
@ -345,6 +347,7 @@
<record id="sale_order_line_27" model="sale.order.line">
<field name="order_id" ref="sale_order_11"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
@ -354,6 +357,7 @@
<record id="sale_order_12" model="sale.order">
<field name="partner_id" ref="base.res_partner_3"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
@ -364,6 +368,7 @@
<record id="sale_order_line_28" model="sale.order.line">
<field name="order_id" ref="sale_order_12"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">1</field>
@ -373,6 +378,7 @@
<record id="sale_order_line_29" model="sale.order.line">
<field name="order_id" ref="sale_order_12"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
@ -381,6 +387,7 @@
</record>
<record id="sale_order_13" model="sale.order">
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
@ -392,6 +399,7 @@
<record id="sale_order_line_30" model="sale.order.line">
<field name="order_id" ref="sale_order_13"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">1</field>
@ -401,6 +409,7 @@
<record id="sale_order_line_31" model="sale.order.line">
<field name="order_id" ref="sale_order_13"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">1</field>
@ -411,6 +420,7 @@
<record id="sale_order_14" model="sale.order">
<field name="partner_id" ref="base.res_partner_3"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
<field name="pricelist_id" ref="product.list0"/>
@ -420,6 +430,7 @@
<record id="sale_order_line_32" model="sale.order.line">
<field name="order_id" ref="sale_order_14"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">4</field>
@ -429,6 +440,7 @@
<record id="sale_order_line_33" model="sale.order.line">
<field name="order_id" ref="sale_order_14"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">4</field>
@ -438,6 +450,7 @@
<record id="sale_order_15" model="sale.order">
<field name="partner_id" ref="base.res_partner_3"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
@ -448,6 +461,7 @@
<record id="sale_order_line_34" model="sale.order.line">
<field name="order_id" ref="sale_order_15"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">4</field>
@ -457,6 +471,7 @@
<record id="sale_order_line_35" model="sale.order.line">
<field name="order_id" ref="sale_order_15"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
@ -466,6 +481,7 @@
<record id="sale_order_16" model="sale.order">
<field name="partner_id" ref="base.res_partner_3"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
@ -476,6 +492,7 @@
<record id="sale_order_line_36" model="sale.order.line">
<field name="order_id" ref="sale_order_16"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">3</field>
@ -485,6 +502,7 @@
<record id="sale_order_line_37" model="sale.order.line">
<field name="order_id" ref="sale_order_16"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">3</field>
@ -494,6 +512,7 @@
<record id="sale_order_17" model="sale.order">
<field name="partner_id" ref="base.res_partner_3"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
@ -504,6 +523,7 @@
<record id="sale_order_line_38" model="sale.order.line">
<field name="order_id" ref="sale_order_17"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">2</field>
@ -513,6 +533,7 @@
<record id="sale_order_line_39" model="sale.order.line">
<field name="order_id" ref="sale_order_17"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>
@ -522,6 +543,7 @@
<record id="sale_order_18" model="sale.order">
<field name="partner_id" ref="base.res_partner_3"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
<field name="user_id" ref="base.user_demo"/>
@ -532,6 +554,7 @@
<record id="sale_order_line_40" model="sale.order.line">
<field name="order_id" ref="sale_order_18"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Laptop E5023</field>
<field name="product_id" ref="product.product_product_25"/>
<field name="product_uom_qty">2</field>
@ -541,6 +564,7 @@
<record id="sale_order_line_41" model="sale.order.line">
<field name="order_id" ref="sale_order_18"/>
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
<field name="name">Mouse, Wireless</field>
<field name="product_id" ref="product.product_product_12"/>
<field name="product_uom_qty">2</field>

View File

@ -13,13 +13,14 @@ from flectra.osv import expression
from flectra.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT
from flectra.tools.misc import formatLang
from flectra.exceptions import ValidationError
from flectra.addons import decimal_precision as dp
class SaleOrder(models.Model):
_name = "sale.order"
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin']
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin',
'ir.branch.company.mixin']
_description = "Quotation"
_order = 'date_order desc, id desc'
@ -164,6 +165,17 @@ class SaleOrder(models.Model):
product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product')
@api.multi
@api.constrains('branch_id', 'company_id')
def _check_company_branch(self):
for order in self:
if order.branch_id and order.company_id != order.branch_id.company_id:
raise ValidationError(_(
'Configuration Error of Company:\n'
'The Sales Order Company (%s) and the Company (%s) of '
'Branch must be the same!') % (
order.company_id.name, order.branch_id.company_id.name))
def _compute_portal_url(self):
super(SaleOrder, self)._compute_portal_url()
for order in self:
@ -354,6 +366,7 @@ class SaleOrder(models.Model):
invoice_vals = {
'name': self.client_order_ref or '',
'origin': self.name,
'branch_id': self.branch_id and self.branch_id.id,
'type': 'out_invoice',
'account_id': self.partner_invoice_id.property_account_receivable_id.id,
'partner_id': self.partner_invoice_id.id,
@ -548,6 +561,7 @@ class SaleOrder(models.Model):
analytic = self.env['account.analytic.account'].create({
'name': name,
'code': order.client_order_ref,
'branch_id': order.branch_id and order.branch_id.id,
'company_id': order.company_id.id,
'partner_id': order.partner_id.id
})
@ -907,6 +921,8 @@ class SaleOrderLine(models.Model):
salesman_id = fields.Many2one(related='order_id.user_id', store=True, string='Salesperson', readonly=True)
currency_id = fields.Many2one(related='order_id.currency_id', store=True, string='Currency', readonly=True)
company_id = fields.Many2one(related='order_id.company_id', string='Company', store=True, readonly=True)
branch_id = fields.Many2one(related='order_id.branch_id',
string='Branch', store=True, readonly=True)
order_partner_id = fields.Many2one(related='order_id.partner_id', store=True, string='Customer')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags')
is_downpayment = fields.Boolean(
@ -953,6 +969,7 @@ class SaleOrderLine(models.Model):
'name': self.name,
'sequence': self.sequence,
'origin': self.order_id.name,
'branch_id': self.branch_id and self.branch_id.id,
'account_id': account.id,
'price_unit': self.price_unit,
'quantity': qty,

View File

@ -6,6 +6,7 @@ from flectra import api, fields, models, tools
class PosSaleReport(models.Model):
_name = "report.all.channels.sales"
_inherit = ['ir.branch.company.mixin']
_description = "All sales orders grouped by sales channels"
_auto = False
@ -37,6 +38,7 @@ class PosSaleReport(models.Model):
so.user_id AS user_id,
pt.categ_id AS categ_id,
so.company_id AS company_id,
so.branch_id AS branch_id,
sol.price_total / COALESCE(cr.rate, 1.0) AS price_total,
so.pricelist_id AS pricelist_id,
rp.country_id AS country_id,
@ -75,6 +77,7 @@ class PosSaleReport(models.Model):
user_id,
categ_id,
company_id,
branch_id,
price_total,
pricelist_id,
analytic_account_id,

View File

@ -7,6 +7,7 @@ from flectra import api, fields, models
class SaleReport(models.Model):
_name = "sale.report"
_inherit = ['ir.branch.company.mixin']
_description = "Sales Orders Statistics"
_auto = False
_rec_name = 'date'
@ -68,6 +69,7 @@ class SaleReport(models.Model):
s.partner_id as partner_id,
s.user_id as user_id,
s.company_id as company_id,
s.branch_id as branch_id,
extract(epoch from avg(date_trunc('day',s.date_order)-date_trunc('day',s.create_date)))/(24*60*60)::decimal(16,2) as delay,
t.categ_id as categ_id,
s.pricelist_id as pricelist_id,
@ -111,6 +113,7 @@ class SaleReport(models.Model):
s.user_id,
s.state,
s.company_id,
s.branch_id,
s.pricelist_id,
s.analytic_account_id,
s.team_id,

View File

@ -60,6 +60,10 @@
<strong>Payment Terms:</strong>
<p t-field="doc.payment_term_id"/>
</div>
<div name="branch" t-if="doc.branch_id" class="col-xs-3">
<strong>Branch:</strong>
<p t-field="doc.branch_id"/>
</div>
</div>
<!-- Is there a discount on at least one line? -->

View File

@ -84,6 +84,30 @@
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<!-- Multi - Branch Rules -->
<record model="ir.rule" id="sale_order_multi_branch_rule">
<field name="name">Sales Order multi-branch</field>
<field name="model_id" ref="model_sale_order"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="sale_order_line_multi_branch_rule">
<field name="name">Sales Order Line multi-branch</field>
<field name="model_id" ref="model_sale_order_line"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<record model="ir.rule" id="sale_order_report_multi_branch_rule">
<field name="name">Sales Order Analysis multi-branch</field>
<field name="model_id" ref="model_sale_report"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
</record>
<!-- Portal Access Rules -->
<record id="sale_order_rule_portal" model="ir.rule">
<field name="name">Portal Personal Quotations/Sales Orders</field>

View File

@ -4,3 +4,4 @@ from . import test_sale_to_invoice
from . import test_sale_order
from . import test_product_id_change
from . import test_sale_to_invoice_and_to_be_invoiced
from . import test_sale_branch

View File

@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
from flectra.tests import common
class TestSaleBranch(common.TransactionCase):
def setUp(self):
super(TestSaleBranch, self).setUp()
self.sale_obj = self.env['sale.order']
self.main_company = self.env.ref('base.main_company')
self.payment_model_obj = self.env['sale.advance.payment.inv']
self.sale_user_group = self.env.ref('sales_team.group_sale_manager')
self.account_user_group = self.env.ref('account.group_account_invoice')
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
self.branch_3 = self.env.ref('base_branch_company.data_branch_3')
self.sale_customer = self.env.ref('base.res_partner_2')
self.sale_pricelist = self.env.ref('product.list0')
self.apple_product = self.env.ref('product.product_product_7')
self.apple_product.write({'invoice_policy': 'order'})
self.user_1 = self.create_sale_user(
self.main_company, 'user_1', self.branch_1,
[self.branch_1, self.branch_3],
[self.sale_user_group, self.account_user_group])
self.user_2 = self.create_sale_user(
self.main_company, 'user_2', self.branch_3,
[self.branch_3], [self.sale_user_group, self.account_user_group])
self.so_1 = self.create_so(
self.sale_customer, self.apple_product, self.user_1.id,
self.branch_1, self.sale_pricelist)
self.so_2 = self.create_so(
self.sale_customer, self.apple_product, self.user_2.id,
self.branch_3, self.sale_pricelist)
def create_sale_user(self, main_company, user_name,
branch_id, branch_ids, groups):
group_ids = [grp.id for grp in groups]
data = {
'company_ids': [(4, main_company.id)],
'branch_ids': [(4, ou.id) for ou in branch_ids],
'company_id': main_company.id,
'groups_id': [(6, 0, group_ids)],
'default_branch_id': branch_id.id,
'login': user_name,
'name': 'Ron Sales User',
'password': '123',
'email': 'ron@yourcompany.com',
}
user_obj = self.env['res.users'].create(data)
return user_obj
def create_so(self, customer_id, product_id,
user_id, branch_id, pricelist_id):
data = {
'partner_id': customer_id.id,
'branch_id': branch_id.id,
'pricelist_id': pricelist_id.id,
'partner_shipping_id': customer_id.id,
'partner_invoice_id': customer_id.id,
}
sale_id = self.sale_obj.sudo(user_id).create(data)
self.env['sale.order.line'].sudo(user_id).create({
'order_id': sale_id.id,
'product_id': product_id.id,
'name': 'Order Line'
})
return sale_id
def sale_order_confirm(self, sale_obj):
context = {
'open_invoices': True,
'active_id': sale_obj.id,
'active_model': 'sale.order',
'active_ids': sale_obj.ids,
}
sale_obj.action_confirm()
invoice = self.payment_model_obj.create({
'advance_payment_method': 'all',
})
result = invoice.with_context(context).create_invoices()
invoice = result['res_id']
return invoice
def get_sale_order(self, sale_order_id, branch_id):
sale = self.sale_obj.sudo(self.user_2.id).search(
[('id', '=', sale_order_id),
('branch_id', '=', branch_id)])
return sale
def test_user_authentication(self):
sale = self.get_sale_order(self.so_1.id, self.branch_1.id)
self.assertEqual(sale.ids, [], 'Test User 2 should not have access to '
'Branch %s' % self.branch_1.name)
self.sale_order_confirm(self.so_1)
branch_3_invoice_id = self.sale_order_confirm(self.so_2)
branch_3 = self.env['account.invoice'].sudo(self.user_2.id).search(
[('id', '=', branch_3_invoice_id),
('branch_id', '=', self.branch_3.id)])
self.assertNotEqual(branch_3.ids, [],
'Invoice should have branch_3 Branch')
def test_user_authentication_2(self):
sale = self.get_sale_order(self.so_1.id, self.branch_1.id)
self.assertEqual(sale.ids, [], 'Test User 2 should '
'not have access to Branch %s'
% self.branch_1.name)
sale = self.get_sale_order(self.so_2.id, self.branch_3.id)
self.assertEqual(len(sale.ids), 1, 'Test User 1 should'
' have access to Branch : %s'
% self.branch_3.name)

View File

@ -381,6 +381,7 @@
<field name="team_id" options="{'no_create': True}"/>
<field name="client_order_ref"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="branch_id" options="{'no_create': True}"/>
<field name="analytic_account_id" context="{'default_partner_id':partner_invoice_id, 'default_name':name}" attrs="{'readonly': ['|',('analytic_account_id','!=',False),('invoice_count','!=',0),('state','=','sale')]}" groups="analytic.group_analytic_accounting"/>
</group>
<group name="sale_pay" string="Invoicing">

View File

@ -84,7 +84,7 @@ class CrmTeam(models.Model):
@api.constrains('company_id', 'branch_id')
def _check_company_branch(self):
for record in self:
if record.company_id and record.company_id != record.branch_id.company_id:
if record.branch_id and record.company_id and record.company_id != record.branch_id.company_id:
raise ValidationError(
_('Configuration Error of Company:\n'
'The Company (%s) in the Team and '