[MERGE]:with latest addons

bzr revid: ksa@tinyerp.com-20111208095313-3ny0iufhiyc9vtsy
This commit is contained in:
Kirti Savalia (OpenERP) 2011-12-08 15:23:13 +05:30
commit 67b8003b83
438 changed files with 6283 additions and 6109 deletions

View File

@ -19,11 +19,11 @@
#
##############################################################################
{
"name" : "Accounting and Financial Management",
"name" : "eInvoicing",
"version" : "1.1",
"author" : "OpenERP SA",
"category": 'Accounting & Finance',
'complexity': "normal",
'complexity': "easy",
"description": """
Accounting and Financial Management.
====================================

View File

@ -789,9 +789,11 @@ class account_journal(osv.osv):
result = self.browse(cr, user, ids, context=context)
res = []
for rs in result:
name = rs.name
if rs.currency:
name = "%s (%s)" % (rs.name, rs.currency.name)
currency = rs.currency
else:
currency = rs.company_id.currency_id
name = "%s (%s)" % (rs.name, currency.name)
res += [(rs.id, name)]
return res
@ -880,7 +882,7 @@ class account_fiscalyear(osv.osv):
for fy in self.browse(cr, uid, ids, context=context):
ds = datetime.strptime(fy.date_start, '%Y-%m-%d')
period_obj.create(cr, uid, {
'name': _('Opening Period'),
'name': "%s %s" % (_('Opening Period'), ds.strftime('%Y')),
'code': ds.strftime('00/%Y'),
'date_start': ds,
'date_stop': ds,
@ -1223,7 +1225,7 @@ class account_move(osv.osv):
'period_id': fields.many2one('account.period', 'Period', required=True, states={'posted':[('readonly',True)]}),
'journal_id': fields.many2one('account.journal', 'Journal', required=True, states={'posted':[('readonly',True)]}),
'state': fields.selection([('draft','Unposted'), ('posted','Posted')], 'State', required=True, readonly=True,
help='All manually created new journal entry are usually in the state \'Unposted\', but you can set the option to skip that state on the related journal. In that case, they will be behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' state.'),
help='All manually created new journal entries are usually in the state \'Unposted\', but you can set the option to skip that state on the related journal. In that case, they will be behave as journal entries automatically created by the system on document validation (invoices, bank statements...) and will be created in \'Posted\' state.'),
'line_id': fields.one2many('account.move.line', 'move_id', 'Entries', states={'posted':[('readonly',True)]}),
'to_check': fields.boolean('To Review', help='Check this box if you are unsure of that journal entry and if you want to note it as \'to be reviewed\' by an accounting expert.'),
'partner_id': fields.related('line_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True),
@ -3154,7 +3156,7 @@ class wizard_multi_charts_accounts(osv.osv_memory):
'type': line.account_type == 'cash' and 'cash' or 'bank',
'company_id': company_id,
'analytic_journal_id': False,
'currency_id': False,
'currency': False,
}
if line.currency_id:
vals_journal['view_id'] = view_id_cur

View File

@ -99,7 +99,6 @@ class bank(osv.osv):
'type': 'bank',
'company_id': bank.company_id.id,
'analytic_journal_id': False,
'currency_id': False,
'default_credit_account_id': acc_bank_id,
'default_debit_account_id': acc_bank_id,
'view_id': view_id_cash

View File

@ -30,10 +30,12 @@ class account_bank_statement(osv.osv):
def create(self, cr, uid, vals, context=None):
seq = 0
if 'line_ids' in vals:
new_line_ids = []
for line in vals['line_ids']:
seq += 1
line[2]['sequence'] = seq
vals[seq - 1] = line
new_line_ids += tuple(line)
vals['line_ids'] = new_line_ids
return super(account_bank_statement, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):

View File

@ -207,7 +207,7 @@ class account_invoice(osv.osv):
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed Invoice. \
\n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \
\n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \
\n* The \'Paid\' state is set automatically when invoice is paid.\
\n* The \'Paid\' state is set automatically when the invoice is paid. Its related journal entries may or may not be reconciled. \
\n* The \'Cancelled\' state is used when user cancel invoice.'),
'date_invoice': fields.date('Invoice Date', readonly=True, states={'draft':[('readonly',False)]}, select=True, help="Keep empty to use the current date"),
'date_due': fields.date('Due Date', states={'paid':[('readonly',True)], 'open':[('readonly',True)], 'close':[('readonly',True)]}, select=True,
@ -257,7 +257,7 @@ class account_invoice(osv.osv):
'account.invoice': (lambda self, cr, uid, ids, c={}: ids, None, 50), # Check if we can remove ?
'account.move.line': (_get_invoice_from_line, None, 50),
'account.move.reconcile': (_get_invoice_from_reconcile, None, 50),
}, help="The Journal Entry of the invoice have been totally reconciled with one or several Journal Entries of payment."),
}, help="It indicates that the invoice has been paid and the journal entry of the invoice has been reconciled with one or several journal entries of payment."),
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',
help='Bank Account Number, Company bank account if Invoice is customer or supplier refund, otherwise Partner bank account number.', readonly=True, states={'draft':[('readonly',False)]}),
'move_lines':fields.function(_get_lines, type='many2many', relation='account.move.line', string='Entry Lines'),
@ -923,7 +923,6 @@ class account_invoice(osv.osv):
'line_id': line,
'journal_id': journal_id,
'date': date,
'type': entry_type,
'narration':inv.comment
}
period_id = inv.period_id and inv.period_id.id or False
@ -1081,7 +1080,8 @@ class account_invoice(osv.osv):
del line['invoice_id']
for field in ('company_id', 'partner_id', 'account_id', 'product_id',
'uos_id', 'account_analytic_id', 'tax_code_id', 'base_code_id'):
line[field] = line.get(field, False) and line[field][0]
if line.get(field):
line[field] = line[field][0]
if 'invoice_line_tax_id' in line:
line['invoice_line_tax_id'] = [(6,0, line.get('invoice_line_tax_id', [])) ]
return map(lambda x: (0,0,x), lines)
@ -1209,7 +1209,7 @@ class account_invoice(osv.osv):
l2['name'] = name
lines = [(0, 0, l1), (0, 0, l2)]
move = {'ref': ref, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'date': date, 'type': entry_type}
move = {'ref': ref, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'date': date}
move_id = self.pool.get('account.move').create(cr, uid, move, context=context)
line_ids = []

View File

@ -171,8 +171,8 @@
<field name="user_type" select="1"/>
<field name="active" groups="base.group_extended" />
<newline/>
<field name="debit" invisible="context.get('config_invisible', True)"/>
<field name="credit" invisible="context.get('config_invisible', True)"/>
<field name="debit" invisible="context.get('config_invisible', True)" attrs="{'readonly':[('type','=','view')]}"/>
<field name="credit" invisible="context.get('config_invisible', True)" attrs="{'readonly':[('type','=','view')]}"/>
<field name="balance" invisible="context.get('config_invisible', True)"/>
</group>
<notebook colspan="4">

File diff suppressed because it is too large Load Diff

View File

@ -103,6 +103,7 @@
<field name="type">normal</field>
<field name="state">open</field>
<field name="partner_id" ref="base.res_partner_seagate"/>
<field name="contact_id" ref="base.res_partner_address_seagate"/>
</record>
<record id="analytic_seagate_p2" model="account.analytic.account">
<field name="name">Seagate P2</field>
@ -111,6 +112,7 @@
<field name="parent_id" ref="analytic_integration"/>
<field name="state">open</field>
<field name="partner_id" ref="base.res_partner_seagate"/>
<field name="contact_id" ref="base.res_partner_address_seagate"/>
</record>
<record id="analytic_magasin_bml_1" model="account.analytic.account">
<field name="name">Magasin BML 1</field>
@ -118,6 +120,7 @@
<field name="parent_id" ref="analytic_integration"/>
<field name="type">normal</field>
<field name="partner_id" ref="base.res_partner_15"/>
<field name="contact_id" ref="base.res_partner_address_14"/>
</record>
<record id="analytic_integration_c2c" model="account.analytic.account">
<field name="name">CampToCamp</field>
@ -127,6 +130,7 @@
<field eval="time.strftime('%Y-12-31')" name="date"/>
<field name="parent_id" ref="analytic_integration"/>
<field name="partner_id" ref="base.res_partner_c2c"/>
<field name="contact_id" ref="base.res_partner_address_Camptocamp"/>
<field name="state">open</field>
</record>
<record id="analytic_agrolait" model="account.analytic.account">
@ -135,13 +139,15 @@
<field name="parent_id" ref="analytic_customers"/>
<field name="type">normal</field>
<field name="partner_id" ref="base.res_partner_agrolait"/>
<field name="contact_id" ref="base.res_partner_address_8"/>
</record>
<record id="analytic_asustek" model="account.analytic.account">
<field name="name">Asustek</field>
<field name="code">4</field>
<field name="type">normal</field>
<field name="parent_id" ref="analytic_customers"/>
<field name="parent_id" ref="analytic_customers"/>
<field name="partner_id" ref="base.res_partner_asus"/>
<field name="contact_id" ref="base.res_partner_address_tang"/>
</record>
<record id="analytic_distripc" model="account.analytic.account">
<field name="name">DistriPC</field>
@ -149,6 +155,7 @@
<field name="parent_id" ref="analytic_customers"/>
<field name="type">normal</field>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="contact_id" ref="base.res_partner_address_7"/>
</record>
<record id="analytic_sednacom" model="account.analytic.account">
<field name="name">Sednacom</field>
@ -158,6 +165,7 @@
<field name="parent_id" ref="analytic_partners"/>
<field name="type">normal</field>
<field name="partner_id" ref="base.res_partner_sednacom"/>
<field name="contact_id" ref="base.res_partner_address_11"/>
<field name="state">open</field>
</record>
<record id="analytic_thymbra" model="account.analytic.account">
@ -168,6 +176,7 @@
<field name="type">normal</field>
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_thymbra"/>
<field name="contact_id" ref="base.res_partner_address_thymbra"/>
<field name="state">open</field>
</record>
<record id="analytic_leclerc" model="account.analytic.account">
@ -178,6 +187,7 @@
<field name="type">normal</field>
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_11"/>
<field name="contact_id" ref="base.res_partner_address_15"/>
</record>
<record id="analytic_desertic_hispafuentes" model="account.analytic.account">
<field name="name">Desertic - Hispafuentes</field>
@ -187,6 +197,7 @@
<field name="type">normal</field>
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_desertic_hispafuentes"/>
<field name="contact_id" ref="base.res_partner_address_3000"/>
</record>
<record id="analytic_tiny_at_work" model="account.analytic.account">
<field name="name">OpenERP SA AT Work</field>
@ -194,6 +205,7 @@
<field name="type">normal</field>
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_tinyatwork"/>
<field name="contact_id" ref="base.res_partner_address_tinyatwork"/>
</record>
<record id="analytic_partners_camp_to_camp" model="account.analytic.account">
<field name="name">Camp to Camp</field>
@ -203,6 +215,7 @@
<field name="type">normal</field>
<field name="parent_id" ref="analytic_partners"/>
<field name="partner_id" ref="base.res_partner_c2c"/>
<field name="contact_id" ref="base.res_partner_address_Camptocamp"/>
<field name="state">open</field>
</record>
<record id="analytic_project_2_support" model="account.analytic.account">

View File

@ -8,16 +8,16 @@
<field name="type">tree</field>
<field eval="8" name="priority"/>
<field name="arch" type="xml">
<tree toolbar="1" colors="red:(date&lt;current_date);black:(date&gt;=current_date);black:(date==False)" string="Analytic Accounts">
<tree toolbar="1" colors="red:state=='pending';grey:state=='done';blue:type=='view'" string="Analytic Accounts">
<field name="code"/>
<field name="complete_name"/>
<field name="quantity"/>
<field name="quantity_max"/>
<field name="date"/>
<field name="user_id" invisible="1"/>
<field name="parent_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="state" invisible="1"/>
<field name="type" invisible="1"/>
</tree>
</field>
</record>
@ -57,11 +57,10 @@
<field name="type">tree</field>
<field name="field_parent">child_complete_ids</field>
<field name="arch" type="xml">
<tree colors="blue:type == 'view';red:(date&lt;current_date);black:(date&gt;=current_date);black:(date==False)" string="Analytic account" toolbar="1">
<tree colors="red:state=='pending';grey:state=='done';blue:type=='view'" string="Analytic account" toolbar="1">
<field name="name"/>
<field name="code"/>
<field name="quantity"/>
<field name="quantity_max"/>
<field name="debit"/>
<field name="credit"/>
<field name="balance"/>
@ -85,7 +84,7 @@
<group colspan="4" col="6">
<field name="name" select="1" colspan="4"/>
<field name="code" select="1"/>
<field name="parent_id" on_change="on_change_parent(parent_id)" groups="base.group_extended" domain="[('type','=','view')]"/>
<field name="parent_id" on_change="on_change_parent(parent_id)" groups="base.group_extended"/>
<field name="company_id" on_change="on_change_company(company_id)" select="2" widget="selection" groups="base.group_multi_company" attrs="{'required': [('type','&lt;&gt;','view')]}"/>
<field name="type" select="2"/>
</group>
@ -194,7 +193,7 @@
<field name="journal_id" invisible="context.get('to_invoice', False)"/>
<field name="amount" sum="Total" invisible="context.get('to_invoice', False)"/>
<field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id, journal_id)" invisible="not context.get('to_invoice', False)"/>
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)" sum="Total Quantity" invisible="not context.get('to_invoice', False)"/>
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)" sum="Total Quantity"/>
<field name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, company_id, product_uom_id)" invisible="not context.get('to_invoice', False)"/>
<field domain="[('type','=','normal')]" name="account_id"/>
<field name="general_account_id" invisible="context.get('to_invoice', False)"/>

View File

@ -162,11 +162,7 @@
</td>
<td>
<para style="terp_default_8">[[ (o.partner_id and o.partner_id.title and o.partner_id.title.name) or '' ]] [[ (o.partner_id and o.partner_id.name) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.street) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.street2) or removeParentNode('para') ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.zip) or '' ]] [[ (o.address_invoice_id and o.address_invoice_id.city) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.state_id and o.address_invoice_id.state_id.name) or removeParentNode('para') ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.country_id and o.address_invoice_id.country_id.name) or '' ]]</para>
<para style="terp_default_8">[[ display_address(o.address_invoice_id) ]]</para>
<para style="terp_default_8">
<font color="white"> </font>
</para>
@ -198,7 +194,7 @@
<para style="terp_tblheader_General_Centre">Origin</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Your Reference</para>
<para style="terp_tblheader_General_Centre">Customer Code</para>
</td>
</tr>
</blockTable>

View File

@ -49,13 +49,6 @@
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="analytic_journal_comp_rule_false" model="ir.rule">
<field name="name">Analytic journal multi-company</field>
<field model="ir.model" name="model_id" ref="model_account_analytic_journal"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="period_comp_rule" model="ir.rule">
<field name="name">Period multi-company</field>
<field model="ir.model" name="model_id" ref="model_account_period"/>

View File

@ -19,10 +19,10 @@
#
##############################################################################
{
"name" : "Accountant Access",
"name" : "Accounting and Finance",
"version" : "1.1",
"author" : "OpenERP SA",
"category": 'Hidden',
"category": 'Accounting & Finance',
'complexity': "normal",
"description": """
Accounting Access Rights.
@ -45,6 +45,7 @@ user rights to Demo user.
'test': [],
'installable': True,
'active': False,
'core': True,
'certificate': '00395091383933390541',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,37 @@
# Azerbaijani translation for openobject-addons
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2011-01-11 11:14+0000\n"
"PO-Revision-Date: 2011-12-06 05:22+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Azerbaijani <az@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-12-07 04:52+0000\n"
"X-Generator: Launchpad (build 14435)\n"
#. module: account_accountant
#: model:ir.module.module,description:account_accountant.module_meta_information
msgid ""
"\n"
"This module gives the admin user the access to all the accounting features "
"like the journal\n"
"items and the chart of accounts.\n"
" "
msgstr ""
"\n"
"Bu modul jurnal yazıları, hesab qrafikləri kimi mühasibat uçotu "
"funksiyalarına idarəçilik imkanı verir.\n"
" "
#. module: account_accountant
#: model:ir.module.module,shortdesc:account_accountant.module_meta_information
msgid "Accountant"
msgstr "Mühasib"

View File

@ -21,7 +21,7 @@
{
'name' : 'Sales Contract Management',
'name' : 'Contracts Management',
'version' : '1.1',
'category' : 'Sales Management',
'complexity': "normal",
@ -46,6 +46,7 @@ user-wise as well as month wise.
],
'demo_xml' : [],
'installable': True,
'core': True,
'active' : False,
'certificate': '0042927202589',
}

View File

@ -406,25 +406,25 @@ class account_analytic_account(osv.osv):
'ca_theorical': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Theoretical Revenue',
help="Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist.",
digits_compute=dp.get_precision('Account')),
'hours_quantity': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Hours Tot',
help="Number of hours you spent on the analytic account (from timesheet). It computes on all journal of type 'general'."),
'hours_quantity': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Total Duration',
help="Number of time you spent on the analytic account (from timesheet). It computes quantities on all journal of type 'general'."),
'last_invoice_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Last Invoice Date',
help="If invoice from the costs, this is the date of the latest invoiced."),
'last_worked_invoiced_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Date of Last Invoiced Cost',
help="If invoice from the costs, this is the date of the latest work or cost that have been invoiced."),
'last_worked_date': fields.function(_analysis_all, multi='analytic_analysis', type='date', string='Date of Last Cost/Work',
help="Date of the latest work done on this account."),
'hours_qtt_non_invoiced': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Uninvoiced Hours',
help="Number of hours (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, type='float', string='Invoiced Hours',
help="Number of hours that can be invoiced plus those that already have been invoiced."),
'remaining_hours': fields.function(_remaining_hours_calc, type='float', string='Remaining Hours',
help="Computed using the formula: Maximum Quantity - Hours Tot."),
'hours_qtt_non_invoiced': fields.function(_analysis_all, multi='analytic_analysis', type='float', string='Uninvoiced Time',
help="Number of time (hours/days) (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, type='float', string='Invoiced Time',
help="Number of time (hours/days) that can be invoiced plus those that already have been invoiced."),
'remaining_hours': fields.function(_remaining_hours_calc, type='float', string='Remaining Time',
help="Computed using the formula: Maximum Duration - Total Time"),
'remaining_ca': fields.function(_remaining_ca_calc, type='float', string='Remaining Revenue',
help="Computed using the formula: Max Invoice Price - Invoiced Amount.",
digits_compute=dp.get_precision('Account')),
'revenue_per_hour': fields.function(_revenue_per_hour_calc, type='float', string='Revenue per Hours (real)',
help="Computed using the formula: Invoiced Amount / Hours Tot.",
'revenue_per_hour': fields.function(_revenue_per_hour_calc, type='float', string='Revenue per Time (real)',
help="Computed using the formula: Invoiced Amount / Total Duration",
digits_compute=dp.get_precision('Account')),
'real_margin': fields.function(_real_margin_calc, type='float', string='Real Margin',
help="Computed using the formula: Invoiced Amount - Total Costs.",

View File

@ -117,8 +117,8 @@
<field eval="20" name="priority"/>
<field name="arch" type="xml">
<tree string="Analytic accounts">
<field name="code"/>
<field name="complete_name"/>
<field name="code"/>
<field name="hours_qtt_non_invoiced"/>
<field name="remaining_hours"/>
<field name="ca_to_invoice"/>

View File

@ -22,7 +22,7 @@
{
'name' : 'Account Analytic Defaults',
'version' : '1.0',
'category' : 'Hidden',
"category": 'Accounting & Finance',
'complexity': "normal",
'description': """Set default values for your analytic accounts
Allows to automatically select analytic accounts based on criterions:

View File

@ -49,6 +49,7 @@
],
"active": False,
"installable": True,
"core": True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -32,11 +32,11 @@
<field name="prorata"/>
<field name="open_asset"/>
</group>
<group col="2" colspan="2" groups="analytic.group_analytic_accounting">
<separator string="Analytic information" colspan="4"/>
<newline/>
<field name="account_analytic_id"/>
</group>
<group col="2" colspan="2" groups="analytic.group_analytic_accounting">
<separator string="Analytic information" colspan="4"/>
<newline/>
<field name="account_analytic_id"/>
</group>
<separator string="Notes" colspan="4"/>
<field name="note" colspan="4" nolabel="1"/>
</form>
@ -317,7 +317,7 @@
<field name="name">Review Asset Categories</field>
<field name="res_model">account.asset.category</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_mode">tree,form</field>
</record>
<record id="asset_category_form_view_todo" model="ir.actions.todo">

View File

@ -0,0 +1,529 @@
# Spanish (Argentina) translation for openobject-addons
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-11-24 12:54+0000\n"
"PO-Revision-Date: 2011-11-30 23:41+0000\n"
"Last-Translator: Gustavo Earnshaw <gustavoear@gmail.com>\n"
"Language-Team: Spanish (Argentina) <es_AR@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2011-12-02 04:47+0000\n"
"X-Generator: Launchpad (build 14414)\n"
#. module: account_asset
#: model:ir.actions.act_window,name:account_asset.action_account_asset_asset_list_normal
#: model:ir.ui.menu,name:account_asset.menu_action_account_asset_asset_list_normal
msgid "Open Assets"
msgstr ""
#. module: account_asset
#: field:account.asset.property,method_end:0
#: field:account.asset.property.history,method_end:0
msgid "Ending date"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation board"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
#: field:account.asset.asset,name:0
#: field:account.asset.board,asset_id:0
#: field:account.asset.property,asset_id:0
#: field:account.invoice.line,asset_id:0
#: field:account.move.line,asset_id:0
#: model:ir.actions.act_window,name:account_asset.action_account_asset_asset_form
#: model:ir.model,name:account_asset.model_account_asset_asset
#: model:ir.ui.menu,name:account_asset.menu_action_account_asset_asset_form
msgid "Asset"
msgstr ""
#. module: account_asset
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr ""
#. module: account_asset
#: selection:account.asset.property,method:0
msgid "Linear"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Change duration"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,child_ids:0
msgid "Child assets"
msgstr ""
#. module: account_asset
#: field:account.asset.board,value_asset:0
msgid "Asset Value"
msgstr "valor de activos"
#. module: account_asset
#: wizard_field:account.asset.modify,init,name:0
msgid "Reason"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
#: field:account.asset.asset,entry_ids:0
#: wizard_field:account.asset.compute,asset_compute,move_ids:0
msgid "Entries"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.compute,asset_compute:0
msgid "Generated entries"
msgstr ""
#. module: account_asset
#: wizard_field:account.asset.modify,init,method_delay:0
#: field:account.asset.property,method_delay:0
#: field:account.asset.property.history,method_delay:0
msgid "Number of interval"
msgstr ""
#. module: account_asset
#: wizard_button:account.asset.compute,asset_compute,asset_open:0
msgid "Open entries"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
#: model:ir.actions.act_window,name:account_asset.action_account_asset_asset_list
#: model:ir.ui.menu,name:account_asset.menu_action_account_asset_asset_list
#: model:ir.ui.menu,name:account_asset.menu_finance_Assets
#: model:ir.ui.menu,name:account_asset.menu_finance_config_Assets
msgid "Assets"
msgstr ""
#. module: account_asset
#: selection:account.asset.property,method:0
msgid "Progressive"
msgstr ""
#. module: account_asset
#: model:ir.actions.act_window,name:account_asset.action_account_asset_asset_list_draft
#: model:ir.ui.menu,name:account_asset.menu_action_account_asset_asset_list_draft
msgid "Draft Assets"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.modify,init:0
#: wizard_field:account.asset.modify,init,note:0
#: view:account.asset.property.history:0
msgid "Notes"
msgstr "Notas"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Change history"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation entries"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Methods"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.modify,init:0
msgid "Asset properties to modify"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,partner_id:0
msgid "Partner"
msgstr ""
#. module: account_asset
#: wizard_field:account.asset.modify,init,method_period:0
#: field:account.asset.property,method_period:0
#: field:account.asset.property.history,method_period:0
msgid "Period per interval"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation duration"
msgstr ""
#. module: account_asset
#: field:account.asset.property,account_analytic_id:0
msgid "Analytic account"
msgstr ""
#. module: account_asset
#: field:account.asset.property,state:0
msgid "State"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation methods"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Other information"
msgstr ""
#. module: account_asset
#: field:account.asset.board,value_asset_cumul:0
msgid "Cumul. value"
msgstr ""
#. module: account_asset
#: view:account.asset.property:0
msgid "Assets methods"
msgstr ""
#. module: account_asset
#: constraint:ir.ui.view:0
msgid "Invalid XML for View Architecture!"
msgstr ""
#. module: account_asset
#: model:ir.model,name:account_asset.model_account_asset_property
msgid "Asset property"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.compute,asset_compute:0
#: wizard_view:account.asset.compute,init:0
#: wizard_button:account.asset.compute,init,asset_compute:0
#: model:ir.actions.wizard,name:account_asset.wizard_asset_compute
#: model:ir.ui.menu,name:account_asset.menu_wizard_asset_compute
msgid "Compute assets"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.modify,init:0
#: wizard_button:account.asset.modify,init,asset_modify:0
#: model:ir.actions.wizard,name:account_asset.wizard_asset_modify
msgid "Modify asset"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Confirm asset"
msgstr ""
#. module: account_asset
#: view:account.asset.property.history:0
#: model:ir.model,name:account_asset.model_account_asset_property_history
msgid "Asset history"
msgstr ""
#. module: account_asset
#: field:account.asset.property,date:0
msgid "Date created"
msgstr ""
#. module: account_asset
#: model:ir.module.module,description:account_asset.module_meta_information
msgid ""
"Financial and accounting asset management.\n"
" Allows to define\n"
" * Asset category. \n"
" * Assets.\n"
" *Asset usage period and property.\n"
" "
msgstr ""
#. module: account_asset
#: field:account.asset.board,value_gross:0
#: field:account.asset.property,value_total:0
msgid "Gross value"
msgstr ""
#. module: account_asset
#: selection:account.asset.property,method_time:0
msgid "Ending period"
msgstr ""
#. module: account_asset
#: field:account.asset.board,name:0
msgid "Asset name"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Accounts information"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,note:0
#: field:account.asset.category,note:0
#: field:account.asset.property.history,note:0
msgid "Note"
msgstr ""
#. module: account_asset
#: selection:account.asset.asset,state:0
#: selection:account.asset.property,state:0
msgid "Draft"
msgstr ""
#. module: account_asset
#: field:account.asset.property,type:0
msgid "Depr. method type"
msgstr ""
#. module: account_asset
#: field:account.asset.property,account_asset_id:0
msgid "Asset account"
msgstr ""
#. module: account_asset
#: field:account.asset.property.history,asset_property_id:0
msgid "Method"
msgstr ""
#. module: account_asset
#: selection:account.asset.asset,state:0
msgid "Normal"
msgstr ""
#. module: account_asset
#: field:account.asset.property,method_progress_factor:0
msgid "Progressif factor"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,localisation:0
msgid "Localisation"
msgstr ""
#. module: account_asset
#: field:account.asset.property,method:0
msgid "Computation method"
msgstr ""
#. module: account_asset
#: field:account.asset.property,method_time:0
msgid "Time method"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,active:0
msgid "Active"
msgstr ""
#. module: account_asset
#: field:account.asset.property.history,user_id:0
msgid "User"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,property_ids:0
msgid "Asset method name"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,date:0
#: field:account.asset.property.history,date:0
msgid "Date"
msgstr ""
#. module: account_asset
#: field:account.asset.board,value_net:0
msgid "Net value"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.close,init:0
#: model:ir.actions.wizard,name:account_asset.wizard_asset_close
msgid "Close asset"
msgstr ""
#. module: account_asset
#: field:account.asset.property,history_ids:0
msgid "History"
msgstr ""
#. module: account_asset
#: field:account.asset.property,account_actif_id:0
msgid "Depreciation account"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,period_id:0
#: wizard_field:account.asset.compute,init,period_id:0
msgid "Period"
msgstr ""
#. module: account_asset
#: model:ir.actions.act_window,name:account_asset.action_account_asset_category_form
#: model:ir.ui.menu,name:account_asset.menu_action_account_asset_category_form
msgid "Asset Category"
msgstr ""
#. module: account_asset
#: wizard_button:account.asset.close,init,end:0
#: wizard_button:account.asset.compute,init,end:0
#: wizard_button:account.asset.modify,init,end:0
msgid "Cancel"
msgstr ""
#. module: account_asset
#: selection:account.asset.asset,state:0
#: wizard_button:account.asset.compute,asset_compute,end:0
#: selection:account.asset.property,state:0
msgid "Close"
msgstr ""
#. module: account_asset
#: selection:account.asset.property,state:0
msgid "Open"
msgstr ""
#. module: account_asset
#: constraint:ir.model:0
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
#. module: account_asset
#: model:ir.module.module,shortdesc:account_asset.module_meta_information
msgid "Asset management"
msgstr ""
#. module: account_asset
#: view:account.asset.board:0
#: field:account.asset.property,board_ids:0
#: model:ir.model,name:account_asset.model_account_asset_board
msgid "Asset board"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,state:0
msgid "Global state"
msgstr ""
#. module: account_asset
#: selection:account.asset.property,method_time:0
msgid "Delay"
msgstr ""
#. module: account_asset
#: wizard_view:account.asset.close,init:0
msgid "General information"
msgstr ""
#. module: account_asset
#: field:account.asset.property,journal_analytic_id:0
msgid "Analytic journal"
msgstr ""
#. module: account_asset
#: field:account.asset.property,name:0
msgid "Method name"
msgstr ""
#. module: account_asset
#: field:account.asset.property,journal_id:0
msgid "Journal"
msgstr ""
#. module: account_asset
#: field:account.asset.property.history,name:0
msgid "History name"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Close method"
msgstr ""
#. module: account_asset
#: field:account.asset.property,entry_asset_ids:0
msgid "Asset Entries"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,category_id:0
#: view:account.asset.category:0
#: field:account.asset.category,name:0
#: model:ir.model,name:account_asset.model_account_asset_category
msgid "Asset category"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,code:0
#: field:account.asset.category,code:0
msgid "Asset code"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,value_total:0
msgid "Total value"
msgstr ""
#. module: account_asset
#: selection:account.asset.asset,state:0
msgid "View"
msgstr ""
#. module: account_asset
#: view:account.asset.asset:0
msgid "General info"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,sequence:0
msgid "Sequence"
msgstr ""
#. module: account_asset
#: field:account.asset.property,value_residual:0
msgid "Residual value"
msgstr ""
#. module: account_asset
#: wizard_button:account.asset.close,init,asset_close:0
msgid "End of asset"
msgstr ""
#. module: account_asset
#: selection:account.asset.property,type:0
msgid "Direct"
msgstr ""
#. module: account_asset
#: selection:account.asset.property,type:0
msgid "Indirect"
msgstr ""
#. module: account_asset
#: field:account.asset.asset,parent_id:0
msgid "Parent asset"
msgstr ""
#. module: account_asset
#: model:ir.actions.act_window,name:account_asset.action_account_asset_asset_tree
#: model:ir.ui.menu,name:account_asset.menu_action_account_asset_asset_tree
msgid "Asset Hierarchy"
msgstr ""

View File

@ -23,7 +23,7 @@
"name" : "Cancel Entries",
"version" : "1.1",
"author" : "OpenERP SA",
"category": 'Hidden',
"category": 'Accounting & Finance',
'complexity': "normal",
"description": """
Allows cancelling accounting entries.

View File

@ -21,9 +21,9 @@
{
'name': 'Charts of Accounts',
'name': 'Template of Charts of Accounts',
'version': '1.1',
'category': 'Hidden',
"category": 'Accounting & Finance',
'description': """
Remove minimal account chart.
=============================

View File

@ -20,10 +20,10 @@
##############################################################################
{
"name" : "Account CODA - import bank statements from coda file",
"name" : "CODA Bank Statements",
"version" : "1.0",
"author" : "OpenERP SA",
"category" : "Hidden",
"category": 'Accounting & Finance',
'complexity': "normal",
"description": """
Module provides functionality to import bank statements from coda files.

View File

@ -64,9 +64,9 @@ class report_rappel(report_sxw.rml_parse):
line_cur = {base_currency.id: {'line': []}}
for line in movelines:
if line.account_id.currency_id and (not line.account_id.currency_id.id in line_cur):
line_cur[line.account_id.currency_id.id] = {'line': []}
currency = line.account_id.currency_id or line.company_id.currency_id
if line.currency_id and (not line.currency_id.id in line_cur):
line_cur[line.currency_id.id] = {'line': []}
currency = line.currency_id or line.company_id.currency_id
line_data = {
'name': line.move_id.name,
'ref': line.ref,

View File

@ -21,9 +21,9 @@
{
'name': 'Improve Invoice Layout',
'name': 'Invoice Layouts',
'version': '1.0',
'category': 'Hidden',
"category": 'Accounting & Finance',
'complexity': "easy",
'description': """
This module provides some features to improve the layout of the invoices.

View File

@ -193,11 +193,7 @@
</td>
<td>
<para style="terp_default_8">[[ (o.partner_id and o.partner_id.title and o.partner_id.title.name) or '' ]] [[ (o.partner_id and o.partner_id.name) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.street) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.street2) or removeParentNode('para') ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.zip) or '' ]] [[ (o.address_invoice_id and o.address_invoice_id.city) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.state_id and o.address_invoice_id.state_id.name) or removeParentNode('para') ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.country_id and o.address_invoice_id.country_id.name) or '' ]]</para>
<para style="terp_default_8">[[ display_address(o.address_invoice_id) ]]</para>
<para style="terp_default_8">
<font color="white"> </font>
</para>
@ -235,7 +231,7 @@
<para style="terp_tblheader_General_Centre">Origin</para>
</td>
<td>
<para style="terp_tblheader_General_Centre">Your Reference</para>
<para style="terp_tblheader_General_Centre">Customer Code</para>
</td>
</tr>
</blockTable>

View File

@ -197,11 +197,7 @@
</td>
<td>
<para style="terp_default_8">[[ (o.partner_id and o.partner_id.title and o.partner_id.title.name) or '' ]] [[ (o.partner_id and o.partner_id.name) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.street) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.street2) or removeParentNode('para') ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.zip) or '' ]] [[ (o.address_invoice_id and o.address_invoice_id.city) or '' ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.state_id and o.address_invoice_id.state_id.name) or removeParentNode('para') ]]</para>
<para style="terp_default_8">[[ (o.address_invoice_id and o.address_invoice_id.country_id and o.address_invoice_id.country_id.name) or '' ]]</para>
<para style="terp_default_8">[[ display_address(o.address_invoice_id) ]]</para>
<para style="terp_default_8">
<font color="white"> </font>
</para>

View File

@ -22,7 +22,7 @@
{
'name': 'Entries Sequence Numbering',
'version': '1.1',
'category': 'Hidden',
"category": 'Accounting & Finance',
'complexity': "easy",
'description': """
This module maintains internal sequence number for accounting entries.

View File

@ -20,7 +20,7 @@
##############################################################################
{
"name" : "Accounting Voucher Entries",
"name" : "eInvoicing & Payments",
"version" : "1.0",
"author" : 'OpenERP SA',
'complexity': "normal",
@ -32,7 +32,7 @@ Account Voucher module includes all the basic requirements of Voucher Entries fo
* Voucher Receipt
* Cheque Register
""",
"category" : "Hidden",
"category": 'Accounting & Finance',
"website" : "http://tinyerp.com",
"images" : ["images/customer_payment.jpeg","images/journal_voucher.jpeg","images/sales_receipt.jpeg","images/supplier_voucher.jpeg"],
"depends" : ["account"],
@ -68,6 +68,7 @@ Account Voucher module includes all the basic requirements of Voucher Entries fo
],
'certificate': '0037580727101',
"active": False,
"core": True,
"installable": True,
}

View File

@ -90,6 +90,21 @@ class account_voucher(osv.osv):
return tax_id
return False
def _get_payment_rate_currency(self, cr, uid, context=None):
'''
Return the default value for field payment_rate_currency_id: the currency of the journal
if there is one, otherwise the currency of the user's company
'''
if context is None: context = {}
journal_pool = self.pool.get('account.journal')
journal_id = context.get('journal_id', False)
if journal_id:
journal = journal_pool.browse(cr, uid, journal_id, context=context)
if journal.currency:
return journal.currency.id
#no journal given in the context, use company currency as default
return self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id.id
def _get_currency(self, cr, uid, context=None):
if context is None: context = {}
journal_pool = self.pool.get('account.journal')
@ -143,11 +158,12 @@ class account_voucher(osv.osv):
res = super(account_voucher, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
doc = etree.XML(res['arch'])
nodes = doc.xpath("//field[@name='partner_id']")
if context.get('type', 'sale') in ('purchase', 'payment'):
nodes = doc.xpath("//field[@name='partner_id']")
for node in nodes:
node.set('domain', "[('supplier', '=', True)]")
res['arch'] = etree.tostring(doc)
res['arch'] = etree.tostring(doc)
return res
def _compute_writeoff_amount(self, cr, uid, line_dr_ids, line_cr_ids, amount):
@ -158,17 +174,25 @@ class account_voucher(osv.osv):
credit += l['amount']
return abs(amount - abs(credit - debit))
def onchange_line_ids(self, cr, uid, ids, line_dr_ids, line_cr_ids, amount, context=None):
def onchange_line_ids(self, cr, uid, ids, line_dr_ids, line_cr_ids, amount, voucher_currency, context=None):
context = context or {}
if not line_dr_ids and not line_cr_ids:
return {'value':{}}
line_osv = self.pool.get("account.voucher.line")
line_dr_ids = resolve_o2m_operations(cr, uid, line_osv, line_dr_ids, ['amount'], context)
line_cr_ids = resolve_o2m_operations(cr, uid, line_osv, line_cr_ids, ['amount'], context)
return {'value': {'writeoff_amount': self._compute_writeoff_amount(cr, uid, line_dr_ids, line_cr_ids, amount)}}
#loop into the lines to see if there is an amount allocated on a voucher line with a currency different than the voucher currency
is_multi_currency = False
for voucher_line in line_dr_ids+line_cr_ids:
if voucher_line.get('currency_id',False) != voucher_currency:
is_multi_currency = True
break
return {'value': {'writeoff_amount': self._compute_writeoff_amount(cr, uid, line_dr_ids, line_cr_ids, amount), 'is_multi_currency': is_multi_currency}}
def _get_writeoff_amount(self, cr, uid, ids, name, args, context=None):
if not ids: return {}
currency_obj = self.pool.get('res.currency')
res = {}
debit = credit = 0.0
for voucher in self.browse(cr, uid, ids, context=context):
@ -176,15 +200,24 @@ class account_voucher(osv.osv):
debit += l.amount
for l in voucher.line_cr_ids:
credit += l.amount
res[voucher.id] = abs(voucher.amount - abs(credit - debit))
currency = voucher.currency_id or voucher.company_id.currency_id
res[voucher.id] = currency_obj.round(cr, uid, currency, abs(voucher.amount - abs(credit - debit)))
return res
def _paid_amount_in_company_currency(self, cr, uid, ids, name, args, context=None):
if not ids: return {}
res = {}
debit = credit = 0.0
voucher_rate = company_currency_rate = 1.0
for voucher in self.browse(cr, uid, ids, context=context):
res[voucher.id] = voucher.amount / voucher.payment_rate
if voucher.currency_id:
ctx = context.copy()
ctx.update({'date': voucher.date})
voucher_rate = self.browse(cr, uid, voucher.id, context=ctx).currency_id.rate
if voucher.company_id.currency_id.id == voucher.payment_rate_currency_id.id:
company_currency_rate = voucher.payment_rate
else:
company_currency_rate = voucher.company_id.currency_id.rate
res[voucher.id] = voucher.amount / voucher_rate * company_currency_rate
return res
_name = 'account.voucher'
@ -241,15 +274,16 @@ class account_voucher(osv.osv):
'payment_option':fields.selection([
('without_writeoff', 'Keep Open'),
('with_writeoff', 'Reconcile Payment Balance'),
], 'Payment Difference', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'exchange_acc_id': fields.many2one('account.account', 'Exchange Diff. Account', readonly=True, states={'draft': [('readonly', False)]}),
], 'Payment Difference', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="This field helps you to choose what you want to do with the eventual difference between the paid amount and the sum of allocated amounts. You can either choose to keep open this difference on the partner's account, or reconcile it with the payment(s)"),
'writeoff_acc_id': fields.many2one('account.account', 'Counterpart Account', readonly=True, states={'draft': [('readonly', False)]}),
'comment': fields.char('Counterpart Comment', size=64, required=True, readonly=True, states={'draft': [('readonly', False)]}),
'analytic_id': fields.many2one('account.analytic.account','Write-Off Analytic Account', readonly=True, states={'draft': [('readonly', False)]}),
'writeoff_amount': fields.function(_get_writeoff_amount, string='Reconcile Amount', type='float', readonly=True),
'payment_rate': fields.float('Payment Rate', digits=(12,6), required=True, readonly=True, states={'draft': [('readonly', False)]},
help='The rate between the journal currency and the company currency for this particular payment.'),
'writeoff_amount': fields.function(_get_writeoff_amount, string='Difference Amount', type='float', readonly=True, help="Computed as the difference between the amount stated in the voucher and the sum of allocation on the voucher lines."),
'payment_rate_currency_id': fields.many2one('res.currency', 'Payment Rate Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'payment_rate': fields.float('Exchange Rate', digits=(12,6), required=True, readonly=True, states={'draft': [('readonly', False)]},
help='The specific rate that will be used, in this voucher, between the selected currency (in \'Payment Rate Currency\' field) and the voucher currency.'),
'paid_amount_in_company_currency': fields.function(_paid_amount_in_company_currency, string='Paid Amount in Company Currency', type='float', readonly=True),
'is_multi_currency': fields.boolean('Multi Currency Voucher', help='Fields with internal purpose only that depicts if the voucher is a multi currency one or not'),
}
_defaults = {
'period_id': _get_period,
@ -269,6 +303,7 @@ class account_voucher(osv.osv):
'payment_option': 'without_writeoff',
'comment': _('Write-Off'),
'payment_rate': 1.0,
'payment_rate_currency_id': _get_payment_rate_currency,
}
def compute_tax(self, cr, uid, ids, context=None):
@ -374,7 +409,7 @@ class account_voucher(osv.osv):
})
return {'value':default}
def onchange_journal_voucher(self, cr, uid, ids, line_ids=False, tax_id=False, price=0.0, partner_id=False, journal_id=False, ttype=False, context=None):
def onchange_journal_voucher(self, cr, uid, ids, line_ids=False, tax_id=False, price=0.0, partner_id=False, journal_id=False, ttype=False, company_id=False, context=None):
"""price
Returns a dict that contains new values and context
@ -413,25 +448,78 @@ class account_voucher(osv.osv):
default['value']['account_id'] = account_id
default['value']['type'] = ttype or tr_type
vals = self.onchange_journal(cr, uid, ids, journal_id, line_ids, tax_id, partner_id, context)
vals = self.onchange_journal(cr, uid, ids, journal_id, line_ids, tax_id, partner_id, company_id, context)
default['value'].update(vals.get('value'))
return default
def onchange_rate(self, cr, uid, ids, rate, amount, context=None):
res = {'value': {'paid_amount_in_company_currency': 0.0}}
if rate and amount:
res['value']['paid_amount_in_company_currency'] = amount / rate
def onchange_rate(self, cr, uid, ids, rate, amount, currency_id, payment_rate_currency_id, company_id, context=None):
res = {'value': {'paid_amount_in_company_currency': amount}}
company_currency = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id
if rate and amount and currency_id:# and currency_id == payment_rate_currency_id:
voucher_rate = self.pool.get('res.currency').browse(cr, uid, currency_id, context).rate
if company_currency.id == payment_rate_currency_id:
company_rate = rate
else:
company_rate = self.pool.get('res.company').browse(cr, uid, company_id, context=context).currency_id.rate
res['value']['paid_amount_in_company_currency'] = amount / voucher_rate * company_rate
return res
def onchange_amount(self, cr, uid, ids, amount, rate, partner_id, journal_id, currency_id, ttype, date, context=None):
res = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
vals = self.onchange_rate(cr, uid, ids, rate, amount, context=context)
def onchange_amount(self, cr, uid, ids, amount, rate, partner_id, journal_id, currency_id, ttype, date, payment_rate_currency_id, company_id, context=None):
if context is None:
context = {}
res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
ctx = context.copy()
ctx.update({'date': date})
vals = self.onchange_rate(cr, uid, ids, rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
for key in vals.keys():
res[key].update(vals[key])
return res
def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context=None):
def recompute_payment_rate(self, cr, uid, ids, vals, currency_id, date, ttype, journal_id, amount, context=None):
if context is None:
context = {}
#on change of the journal, we need to set also the default value for payment_rate and payment_rate_currency_id
currency_obj = self.pool.get('res.currency')
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
company_id = journal.company_id.id
payment_rate = 1.0
payment_rate_currency_id = currency_id
ctx = context.copy()
ctx.update({'date': date})
o2m_to_loop = False
if ttype == 'receipt':
o2m_to_loop = 'line_cr_ids'
elif ttype == 'payment':
o2m_to_loop = 'line_dr_ids'
if o2m_to_loop and 'value' in vals and o2m_to_loop in vals['value']:
for voucher_line in vals['value'][o2m_to_loop]:
if voucher_line['currency_id'] != currency_id:
# we take as default value for the payment_rate_currency_id, the currency of the first invoice that
# is not in the voucher currency
payment_rate_currency_id = voucher_line['currency_id']
tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
voucher_currency_id = currency_id or journal.company_id.currency_id.id
payment_rate = tmp / currency_obj.browse(cr, uid, voucher_currency_id, context=ctx).rate
break
res = self.onchange_rate(cr, uid, ids, payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
for key in res.keys():
vals[key].update(res[key])
vals['value'].update({'payment_rate': payment_rate})
if payment_rate_currency_id:
vals['value'].update({'payment_rate_currency_id': payment_rate_currency_id})
return vals
def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=None):
if not journal_id:
return {}
res = self.recompute_voucher_lines(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context=context)
vals = self.recompute_payment_rate(cr, uid, ids, res, currency_id, date, ttype, journal_id, amount, context=context)
for key in vals.keys():
res[key].update(vals[key])
return res
def recompute_voucher_lines(self, cr, uid, ids, partner_id, journal_id, price, currency_id, ttype, date, context=None):
"""
Returns a dict that contains new values and context
@ -502,9 +590,9 @@ class account_voucher(osv.osv):
#order the lines by most old first
ids.reverse()
moves = move_line_pool.browse(cr, uid, ids, context=context)
account_move_lines = move_line_pool.browse(cr, uid, ids, context=context)
for line in moves:
for line in account_move_lines:
if line.credit and line.reconcile_partial_id and ttype == 'receipt':
continue
if line.debit and line.reconcile_partial_id and ttype == 'payment':
@ -533,7 +621,7 @@ class account_voucher(osv.osv):
total_debit += line.debit and line.amount_currency or 0.0
#voucher line creation
for line in moves:
for line in account_move_lines:
if line.credit and line.reconcile_partial_id and ttype == 'receipt':
continue
if line.debit and line.reconcile_partial_id and ttype == 'payment':
@ -544,6 +632,7 @@ class account_voucher(osv.osv):
else:
amount_original = currency_pool.compute(cr, uid, company_currency, currency_id, line.credit or line.debit or 0.0)
amount_unreconciled = currency_pool.compute(cr, uid, company_currency, currency_id, abs(line.amount_residual))
line_currency_id = line.currency_id and line.currency_id.id or company_currency
rs = {
'name':line.move_id.name,
'type': line.credit and 'dr' or 'cr',
@ -554,11 +643,11 @@ class account_voucher(osv.osv):
'date_original':line.date,
'date_due':line.date_maturity,
'amount_unreconciled': amount_unreconciled,
'currency_id': line_currency_id,
}
#split voucher amount by most old first, but only for lines in the same currency
if not move_line_found:
line_currency_id = line.currency_id and line.currency_id.id or company_currency
if currency_id == line_currency_id:
if line.credit:
amount = min(amount_unreconciled, abs(total_debit))
@ -569,7 +658,9 @@ class account_voucher(osv.osv):
rs['amount'] = amount
total_credit -= amount
default['value']['line_ids'].append(rs)
if rs['amount_unreconciled'] == rs['amount']:
rs['reconcile'] = True
if rs['type'] == 'cr':
default['value']['line_cr_ids'].append(rs)
else:
@ -582,30 +673,51 @@ class account_voucher(osv.osv):
default['value']['writeoff_amount'] = self._compute_writeoff_amount(cr, uid, default['value']['line_dr_ids'], default['value']['line_cr_ids'], price)
return default
def onchange_date(self, cr, uid, ids, date, currency_id, amount, context=None):
def onchange_payment_rate_currency(self, cr, uid, ids, currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=None):
if context is None:
context = {}
res = {'value': {}}
#set the default payment rate of the voucher and compute the paid amount in company currency
if currency_id and currency_id == payment_rate_currency_id:
ctx = context.copy()
ctx.update({'date': date})
vals = self.onchange_rate(cr, uid, ids, payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context=ctx)
for key in vals.keys():
res[key].update(vals[key])
return res
def onchange_date(self, cr, uid, ids, date, currency_id, payment_rate_currency_id, amount, company_id, context=None):
"""
@param date: latest value from user input for field date
@param args: other arguments
@param context: context arguments, like lang, time zone
@return: Returns a dict which contains new values, and context
"""
if context is None:
context ={}
res = {'value': {}}
#set the period of the voucher
period_pool = self.pool.get('account.period')
pids = period_pool.search(cr, uid, [('date_start', '<=', date), ('date_stop', '>=', date)])
currency_obj = self.pool.get('res.currency')
ctx = context.copy()
ctx.update({'company_id': company_id})
pids = period_pool.find(cr, uid, date, context=ctx)
if pids:
res['value'].update({'period_id':pids[0]})
#set the default payment rate of the voucher and compute the paid amount in company currency
payment_rate = 1.0
if currency_id:
payment_rate = self.pool.get('res.currency').browse(cr, uid, currency_id, context={'date': date}).rate
res['value'].update({'payment_rate': payment_rate})
vals = self.onchange_rate(cr, uid, ids, payment_rate, amount, context=context)
for key in vals.keys():
res[key].update(vals[key])
if payment_rate_currency_id:
ctx.update({'date': date})
payment_rate = 1.0
if payment_rate_currency_id != currency_id:
tmp = currency_obj.browse(cr, uid, payment_rate_currency_id, context=ctx).rate
voucher_currency_id = currency_id or self.pool.get('res.company').browse(cr, uid, company_id, context=ctx).currency_id.id
payment_rate = tmp / currency_obj.browse(cr, uid, voucher_currency_id, context=ctx).rate
vals = self.onchange_payment_rate_currency(cr, uid, ids, currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context=context)
vals['value'].update({'payment_rate': payment_rate})
for key in vals.keys():
res[key].update(vals[key])
return res
def onchange_journal(self, cr, uid, ids, journal_id, line_ids, tax_id, partner_id, date, amount, ttype, context=None):
def onchange_journal(self, cr, uid, ids, journal_id, line_ids, tax_id, partner_id, date, amount, ttype, company_id, context=None):
if not journal_id:
return False
journal_pool = self.pool.get('account.journal')
@ -620,11 +732,6 @@ class account_voucher(osv.osv):
currency_id = False
if journal.currency:
currency_id = journal.currency.id
payment_rate = self.pool.get('res.currency').browse(cr, uid, currency_id, context={'date': date}).rate
vals['value'].update({'payment_rate': payment_rate})
res = self.onchange_rate(cr, uid, ids, payment_rate, amount, context=context)
for key in res.keys():
vals[key].update(res[key])
vals['value'].update({'currency_id': currency_id})
res = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, amount, currency_id, ttype, date, context)
for key in res.keys():
@ -730,9 +837,9 @@ class account_voucher(osv.osv):
# TODO: Make this logic available.
# -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt
if voucher_brw.type in ('purchase', 'payment'):
credit = voucher_brw.amount / voucher_brw.payment_rate
credit = voucher_brw.paid_amount_in_company_currency
elif voucher_brw.type in ('sale', 'receipt'):
debit = voucher_brw.amount / voucher_brw.payment_rate
debit = voucher_brw.paid_amount_in_company_currency
if debit < 0: credit = -debit; debit = 0.0
if credit < 0: debit = -credit; credit = 0.0
sign = debit - credit < 0 and -1 or 1
@ -788,9 +895,10 @@ class account_voucher(osv.osv):
def _get_exchange_lines(self, cr, uid, line, move_id, amount_residual, company_currency, current_currency, context=None):
'''
Prepare the two lines due to currency rate difference.
Prepare the two lines in company currency due to currency rate difference.
:param line: browse record of the voucher.line for which we want to create currency rate difference accounting entries
:param line: browse record of the voucher.line for which we want to create currency rate difference accounting
entries
:param move_id: Account move wher the move lines will be.
:param amount_residual: Amount to be posted.
:param company_currency: id of currency of the company to which the voucher belong
@ -798,9 +906,17 @@ class account_voucher(osv.osv):
:return: the account move line and its counterpart to create, depicted as mapping between fieldname and value
:rtype: tuple of dict
'''
if not line.voucher_id.exchange_acc_id.id:
raise osv.except_osv(_('Error!'), _('You must provide an account for the exchange difference.'))
if amount_residual > 0:
account_id = line.voucher_id.company_id.expense_currency_exchange_account_id
if not account_id:
raise osv.except_osv(_('Warning'),_("Unable to create accounting entry for currency rate difference. You have to configure the field 'Income Currency Rate' on the company! "))
else:
account_id = line.voucher_id.company_id.income_currency_exchange_account_id
if not account_id:
raise osv.except_osv(_('Warning'),_("Unable to create accounting entry for currency rate difference. You have to configure the field 'Expense Currency Rate' on the company! "))
# Even if the amount_currency is never filled, we need to pass the foreign currency because otherwise
# the receivable/payable account may have a secondary currency, which render this field mandatory
account_currency_id = company_currency <> current_currency and current_currency or False
move_line = {
'journal_id': line.voucher_id.journal_id.id,
'period_id': line.voucher_id.period_id.id,
@ -808,7 +924,7 @@ class account_voucher(osv.osv):
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': line.voucher_id.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'currency_id': account_currency_id,
'amount_currency': 0.0,
'quantity': 1,
'credit': amount_residual > 0 and amount_residual or 0.0,
@ -819,11 +935,11 @@ class account_voucher(osv.osv):
'journal_id': line.voucher_id.journal_id.id,
'period_id': line.voucher_id.period_id.id,
'name': _('change')+': '+(line.name or '/'),
'account_id': line.voucher_id.exchange_acc_id.id,
'account_id': account_id.id,
'move_id': move_id,
'amount_currency': 0.0,
'partner_id': line.voucher_id.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'currency_id': account_currency_id,
'quantity': 1,
'debit': amount_residual > 0 and amount_residual or 0.0,
'credit': amount_residual < 0 and -amount_residual or 0.0,
@ -831,6 +947,31 @@ class account_voucher(osv.osv):
}
return (move_line, move_line_counterpart)
def _convert_amount(self, cr, uid, amount, voucher_id, context=None):
'''
This function convert the amount given in company currency. It takes either the rate in the voucher (if the
payment_rate_currency_id is relevant) either the rate encoded in the system.
:param amount: float. The amount to convert
:param voucher: id of the voucher on which we want the conversion
:param context: to context to use for the conversion. It may contain the key 'date' set to the voucher date
field in order to select the good rate to use.
:return: the amount in the currency of the voucher's company
:rtype: float
'''
currency_obj = self.pool.get('res.currency')
voucher = self.browse(cr, uid, voucher_id, context=context)
res = amount
if voucher.payment_rate_currency_id.id == voucher.company_id.currency_id.id:
# the rate specified on the voucher is for the company currency
rate_between_voucher_and_base = voucher.currency_id.rate or 1.0
rate_between_base_and_company = voucher.payment_rate or 1.0
res = currency_obj.round(cr, uid, voucher.company_id.currency_id, (amount / rate_between_voucher_and_base * rate_between_base_and_company))
else:
# the rate specified on the voucher is not relevant, we use all the rates in the system
res = currency_obj.compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, amount, context=context)
return res
def voucher_move_line_create(self, cr, uid, voucher_id, line_total, move_id, company_currency, current_currency, context=None):
'''
Create one account move line, on the given account move, per voucher line where amount is not 0.0.
@ -843,25 +984,30 @@ class account_voucher(osv.osv):
:param company_currency: id of currency of the company to which the voucher belong
:param current_currency: id of currency of the voucher
:return: Tuple build as (remaining amount not allocated on voucher lines, list of account_move_line created in this method)
:rtype: tuple(int, list of int)
:rtype: tuple(float, list of int)
'''
if context is None:
context = {}
move_line_obj = self.pool.get('account.move.line')
currency_obj = self.pool.get('res.currency')
tot_line = line_total
rec_lst_ids = []
voucher_brw = self.pool.get('account.voucher').browse(cr,uid,voucher_id,context)
voucher_brw = self.pool.get('account.voucher').browse(cr, uid, voucher_id, context)
ctx = context.copy()
ctx.update({'date': voucher_brw.date})
for line in voucher_brw.line_ids:
#create one move line per voucher line where amount is not 0.0
if not line.amount:
continue
#we check if the voucher line is fully paid or not and create a move line to balance the payment and initial invoice if needed
# convert the amount set on the voucher line into the currency of the voucher's company
amount = self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher_brw.id, context=ctx)
# if the amount encoded in voucher is equal to the amount unreconciled, we need to compute the
# currency rate difference
if line.amount == line.amount_unreconciled:
amount = (line.untax_amount or line.amount) / voucher_brw.payment_rate
amount_residual = line.move_line_id.amount_residual - amount #residual amount in company currency
currency_rate_difference = line.move_line_id.amount_residual - amount
else:
amount = (line.untax_amount or line.amount) / voucher_brw.payment_rate
amount_residual = 0.0
currency_rate_difference = 0.0
move_line = {
'journal_id': voucher_brw.journal_id.id,
'period_id': voucher_brw.period_id.id,
@ -869,7 +1015,7 @@ class account_voucher(osv.osv):
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': voucher_brw.partner_id.id,
'currency_id': company_currency <> current_currency and current_currency or False,
'currency_id': line.move_line_id and (company_currency <> line.move_line_id.currency_id.id and line.move_line_id.currency_id.id) or False,
'analytic_account_id': line.account_analytic_id and line.account_analytic_id.id or False,
'quantity': 1,
'credit': 0.0,
@ -900,18 +1046,58 @@ class account_voucher(osv.osv):
if not (tax_data.base_code_id and tax_data.tax_code_id):
raise osv.except_osv(_('No Account Base Code and Account Tax Code!'),_("You have to configure account base code and account tax code on the '%s' tax!") % (tax_data.name))
sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
move_line['amount_currency'] = company_currency <> current_currency and sign * line.amount or False
# compute the amount in foreign currency
foreign_currency_diff = 0.0
amount_currency = False
if line.move_line_id:
voucher_currency = voucher_brw.currency_id and voucher_brw.currency_id.id or voucher_brw.journal_id.company_id.currency_id.id
# We want to set it on the account move line as soon as the original line had a foreign currency
if line.move_line_id.currency_id and line.move_line_id.currency_id.id != company_currency:
# we compute the amount in that foreign currency.
if line.move_line_id.currency_id.id == current_currency:
# if the voucher and the voucher line share the same currency, there is no computation to do
sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
amount_currency = sign * (line.amount)
elif line.move_line_id.currency_id.id == voucher_brw.payment_rate_currency_id.id:
# if the rate is specified on the voucher, we must use it
voucher_rate = currency_obj.browse(cr, uid, voucher_currency, context=ctx).rate
amount_currency = (move_line['debit'] - move_line['credit']) * voucher_brw.payment_rate * voucher_rate
else:
# otherwise we use the rates of the system (giving the voucher date in the context)
amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)
if line.amount == line.amount_unreconciled and line.move_line_id.currency_id.id == voucher_currency:
foreign_currency_diff = line.move_line_id.amount_residual_currency + amount_currency
move_line['amount_currency'] = amount_currency
voucher_line = move_line_obj.create(cr, uid, move_line)
rec_ids = [voucher_line, line.move_line_id.id]
if amount_residual:
# Change difference entry
exch_lines = self._get_exchange_lines(cr, uid, line, move_id, amount_residual, company_currency, current_currency, context=context)
if not currency_obj.is_zero(cr, uid, voucher_brw.company_id.currency_id, currency_rate_difference):
# Change difference entry in company currency
exch_lines = self._get_exchange_lines(cr, uid, line, move_id, currency_rate_difference, company_currency, current_currency, context=context)
new_id = move_line_obj.create(cr, uid, exch_lines[0],context)
move_line_obj.create(cr, uid, exch_lines[1], context)
rec_ids.append(new_id)
if line.move_line_id and line.move_line_id.currency_id and not currency_obj.is_zero(cr, uid, line.move_line_id.currency_id, foreign_currency_diff):
# Change difference entry in voucher currency
move_line_foreign_currency = {
'journal_id': line.voucher_id.journal_id.id,
'period_id': line.voucher_id.period_id.id,
'name': _('change')+': '+(line.name or '/'),
'account_id': line.account_id.id,
'move_id': move_id,
'partner_id': line.voucher_id.partner_id.id,
'currency_id': line.move_line_id.currency_id.id,
'amount_currency': -1 * foreign_currency_diff,
'quantity': 1,
'credit': 0.0,
'debit': 0.0,
'date': line.voucher_id.date,
}
new_id = move_line_obj.create(cr, uid, move_line_foreign_currency, context=context)
rec_ids.append(new_id)
if line.move_line_id.id:
rec_lst_ids.append(rec_ids)
@ -958,6 +1144,7 @@ class account_voucher(osv.osv):
'debit': diff < 0 and -diff or 0.0,
'amount_currency': company_currency <> current_currency and voucher_brw.writeoff_amount or False,
'currency_id': company_currency <> current_currency and current_currency or False,
'analytic_account_id': voucher_brw.analytic_id and voucher_brw.analytic_id.id or False,
}
return move_line
@ -999,28 +1186,32 @@ class account_voucher(osv.osv):
continue
company_currency = self._get_company_currency(cr, uid, voucher.id, context)
current_currency = self._get_current_currency(cr, uid, voucher.id, context)
# we select the context to use accordingly if it's a multicurrency case or not
context = self._sel_context(cr, uid, voucher.id, context)
#Create the account move record.
# But for the operations made by _convert_amount, we always need to give the date in the context
ctx = context.copy()
ctx.update({'date': voucher.date})
# Create the account move record.
move_id = move_pool.create(cr, uid, self.account_move_get(cr, uid, voucher.id, context=context), context=context)
# Get the name of the account_move just created
name = move_pool.browse(cr, uid, move_id, context=context).name
#Create the first line of the voucher
# Create the first line of the voucher
move_line_id = move_line_pool.create(cr, uid, self.first_move_line_get(cr,uid,voucher.id, move_id, company_currency, current_currency, context), context)
move_line_brw = move_line_pool.browse(cr, uid, move_line_id, context=context)
line_total = move_line_brw.debit - move_line_brw.credit
rec_list_ids = []
if voucher.type == 'sale':
line_total = line_total - (voucher.tax_amount / voucher.payment_rate)
line_total = line_total - self._convert_amount(cr, uid, voucher.tax_amount, voucher.id, context=ctx)
elif voucher.type == 'purchase':
line_total = line_total + (voucher.tax_amount / voucher.payment_rate)
#create one move line per voucher line where amount is not 0.0
line_total = line_total + self._convert_amount(cr, uid, voucher.tax_amount, voucher.id, context=ctx)
# Create one move line per voucher line where amount is not 0.0
line_total, rec_list_ids = self.voucher_move_line_create(cr, uid, voucher.id, line_total, move_id, company_currency, current_currency, context)
#create the writeoff line if needed
# Create the writeoff line if needed
ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, context)
if ml_writeoff:
ml_writeoff_id = move_line_pool.create(cr, uid, ml_writeoff, context)
#We post the voucher.
# We post the voucher.
self.write(cr, uid, [voucher.id], {
'move_id': move_id,
'state': 'posted',
@ -1028,10 +1219,10 @@ class account_voucher(osv.osv):
})
if voucher.journal_id.entry_posted:
move_pool.post(cr, uid, [move_id], context={})
#We automatically reconcile the account move lines.
# We automatically reconcile the account move lines.
for rec_ids in rec_list_ids:
if len(rec_ids) >= 2:
move_line_pool.reconcile_partial(cr, uid, rec_ids, writeoff_acc_id=voucher.exchange_acc_id.id, writeoff_period_id=voucher.period_id.id, writeoff_journal_id=voucher.journal_id.id)
move_line_pool.reconcile_partial(cr, uid, rec_ids, writeoff_acc_id=voucher.writeoff_acc_id.id, writeoff_period_id=voucher.period_id.id, writeoff_journal_id=voucher.journal_id.id)
return True
def copy(self, cr, uid, id, default={}, context=None):
@ -1083,13 +1274,28 @@ class account_voucher_line(osv.osv):
rs_data[line.id] = res
return rs_data
def _currency_id(self, cr, uid, ids, name, args, context=None):
'''
This function returns the currency id of a voucher line. It's either the currency of the
associated move line (if any) or the currency of the voucher or the company currency.
'''
res = {}
for line in self.browse(cr, uid, ids, context=context):
move_line = line.move_line_id
if move_line:
res[line.id] = move_line.currency_id and move_line.currency_id.id or move_line.company_id.currency_id.id
else:
res[line.id] = line.voucher_id.currency_id and line.voucher_id.currency_id.id or line.voucher_id.company_id.currency_id.id
return res
_columns = {
'voucher_id':fields.many2one('account.voucher', 'Voucher', required=1, ondelete='cascade'),
'name':fields.char('Description', size=256),
'account_id':fields.many2one('account.account','Account', required=True),
'partner_id':fields.related('voucher_id', 'partner_id', type='many2one', relation='res.partner', string='Partner'),
'untax_amount':fields.float('Untax Amount'),
'amount':fields.float('Amount', digits_compute=dp.get_precision('Account')),
'amount':fields.float('Allocation', digits_compute=dp.get_precision('Account')),
'reconcile': fields.boolean('Full Reconcile'),
'type':fields.selection([('dr','Debit'),('cr','Credit')], 'Dr/Cr'),
'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'),
'move_line_id': fields.many2one('account.move.line', 'Journal Item'),
@ -1098,11 +1304,24 @@ class account_voucher_line(osv.osv):
'amount_original': fields.function(_compute_balance, multi='dc', type='float', string='Original Amount', store=True),
'amount_unreconciled': fields.function(_compute_balance, multi='dc', type='float', string='Open Balance', store=True),
'company_id': fields.related('voucher_id','company_id', relation='res.company', type='many2one', string='Company', store=True, readonly=True),
'currency_id': fields.function(_currency_id, string='Currency', type='many2one', relation='res.currency', readonly=True),
}
_defaults = {
'name': ''
'name': '',
}
def onchange_reconcile(self, cr, uid, ids, reconcile, amount, amount_unreconciled, context=None):
vals = { 'amount': 0.0}
if reconcile:
vals = { 'amount': amount_unreconciled}
return {'value': vals}
def onchange_amount(self, cr, uid, ids, amount, amount_unreconciled, context=None):
vals = {}
if amount:
vals['reconcile'] = (amount == amount_unreconciled)
return {'value': vals}
def onchange_move_line_id(self, cr, user, ids, move_line_id, context=None):
"""
Returns a dict that contains new values and context
@ -1121,10 +1340,10 @@ class account_voucher_line(osv.osv):
ttype = 'dr'
else:
ttype = 'cr'
account_id = move_line.account_id.id
res.update({
'account_id':account_id,
'type': ttype
'account_id': move_line.account_id.id,
'type': ttype,
'currency_id': move_line.currency_id and move_line.currency_id.id or move_line.company_id.currency_id.id,
})
return {
'value':res,
@ -1261,6 +1480,7 @@ def resolve_o2m_operations(cr, uid, target_osv, operations, fields, context):
result = operation[2]
elif operation[0] == 1:
result = target_osv.read(cr, uid, operation[1], fields, context=context)
if not result: result = {}
result.update(operation[2])
elif operation[0] == 4:
result = target_osv.read(cr, uid, operation[1], fields, context=context)
@ -1268,4 +1488,19 @@ def resolve_o2m_operations(cr, uid, target_osv, operations, fields, context):
results.append(result)
return results
class res_company(osv.osv):
_inherit = "res.company"
_columns = {
'income_currency_exchange_account_id': fields.many2one(
'account.account',
string="Income Currency Rate",
domain="[('type', '=', 'other')]",),
'expense_currency_exchange_account_id': fields.many2one(
'account.account',
string="Expense Currency Rate",
domain="[('type', '=', 'other')]",),
}
res_company()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -11,13 +11,14 @@
header = "False"
menu="True"/> -->
<report id="report_account_voucher_print"
<!-- This report is awfull so it's better to hide it -->
<!-- <report id="report_account_voucher_print"
string="Voucher Print"
model="account.voucher"
name="voucher.print"
rml="account_voucher/report/account_voucher_print.rml"
auto="False"
header = "False"
menu="True"/>
menu="True"/>-->
</data>
</openerp>

View File

@ -259,5 +259,19 @@
</field>
</record>
<!-- res.company form view -->
<record model="ir.ui.view" id="view_company_inherit_currency_xchange_form">
<field name="name">res.company.form.inherit</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="model">res.company</field>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="income_currency_exchange_account_id" colspan="2"/>
<field name="expense_currency_exchange_account_id" colspan="2"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@ -5,7 +5,6 @@
account_id: account.cash
amount: 1000.0
company_id: base.main_company
currency_id: base.EUR
journal_id: account.bank_journal
name: Voucher for Axelor
narration: Basic Pc

View File

@ -1,7 +1,7 @@
-
Demo for Account Voucher
-
!record {model: account.voucher, id: account_voucher_voucheraxelor0}:
!record {model: account.voucher, id: account_voucher_voucheraxelor0again}:
account_id: account.cash
company_id: base.main_company
journal_id: account.bank_journal
@ -19,6 +19,6 @@
-
!python {model: account.voucher}: |
import netsvc, tools, os
(data, format) = netsvc.LocalService('report.voucher.cash_receipt.drcr').create(cr, uid, [ref("account_voucher_voucheraxelor0")], {}, {})
(data, format) = netsvc.LocalService('report.voucher.cash_receipt.drcr').create(cr, uid, [ref("account_voucher_voucheraxelor0again")], {}, {})
if tools.config['test_report_directory']:
file(os.path.join(tools.config['test_report_directory'], 'account_voucher-report.'+format), 'wb+').write(data)

View File

@ -1,6 +1,15 @@
-
In order to check the Account_voucher module with multi-currency in OpenERP,
I create 2 Invoices in USD and make 2 Payments in USD based on the currency rating on that particular date
-
I set the income and expense currency accounts on the main company
-
!python {model: res.company}: |
from datetime import datetime
vals = {
'income_currency_exchange_account_id': ref('account.o_expense'),
'expense_currency_exchange_account_id': ref('account.o_expense')}
self.write(cr, uid, ref('base.main_company'), vals)
-
I create currency USD in OpenERP for January of 1.333333 Rate
-
@ -131,39 +140,41 @@
assert (move_line.debit - move_line.credit == 80), "Invoice move is not correct for debtors account"
-
I create the first voucher of payment
<create with values 240 USD, journal USD, and fill amounts 180 for the invoice of 200$ and 70 for the invoice of 100$>
I set the context that will be used for the encoding of all the vouchers of this file
-
!context
'type': 'receipt'
-
I create the first voucher of payment with values 240 USD, journal USD,
-
!record {model: account.voucher, id: account_voucher_1_case1, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 240.0
company_id: base.main_company
journal_id: bank_journal_USD
name: 'First payment: Case 1 USD/USD'
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-03-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
-
I fill amounts 180 for the invoice of 200$ and 70 for the invoice of 100$>
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_USD'), 240.00, 2, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 240.00,
'company_id': ref('base.main_company'),
'currency_id': ref('base.USD'),
'journal_id': ref('bank_journal_USD'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-%m-%d"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'First payment: Case 1 USD/USD',
}
vals.update(self.onchange_date(cr, uid, [], time.strftime('%Y-03-01'), ref('base.USD'), 240)['value'])
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 200.00:
item['amount'] = 180.00
voucher_id = self.browse(cr, uid, ref('account_voucher_1_case1'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 200.00:
data += [(item.id, 180.0)]
else:
item['amount'] = 70.00
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 70.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 10.0
@ -228,41 +239,35 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 30.0) , "Residual amount is not correct for first Invoice"
-
I create the second voucher of payment
<create with values 45 USD, journal USD, and fill amounts 20 for the invoice of 200$ and 30 for the invoice of 100$>
I create the second voucher of payment with values 45 USD, journal USD,
-
!record {model: account.voucher, id: account_voucher_2_case1}:
account_id: account.cash
amount: 45.0
company_id: base.main_company
journal_id: bank_journal_USD
name: 'Second payment: Case 1'
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-04-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
-
I fill amounts 20 for the invoice of 200$ and 30 for the invoice of 100$
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_USD'), 45.00, 2, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 45.00,
'exchange_acc_id': ref('account.o_expense'),
'company_id': ref('base.main_company'),
'currency_id': ref('base.USD'),
'journal_id': ref('bank_journal_USD'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-%m-%d"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'Second payment: Case 1',
}
vals.update(self.onchange_date(cr, uid, [], time.strftime('%Y-04-01'), ref('base.USD'), 45.0)['value'])
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 20.00:
item['amount'] = 20.00
voucher_id = self.browse(cr, uid, ref('account_voucher_2_case1'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 20.00:
data += [(item.id, 20.0)]
else:
item['amount'] = 30.00
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 30.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 5.0

View File

@ -1,6 +1,15 @@
-
In order to check the Account_voucher module with multi-currency in OpenERP,
I create 2 Invoices in USD and make 2 Payments one in USD and another in EUR, based on the currency rating on that particular date
-
I set the income and expense currency accounts on the main company
-
!python {model: res.company}: |
from datetime import datetime
vals = {
'income_currency_exchange_account_id': ref('account.o_expense'),
'expense_currency_exchange_account_id': ref('account.o_expense')}
self.write(cr, uid, ref('base.main_company'), vals)
-
I create a bank journal with EUR as currency
-
@ -104,38 +113,41 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.debit - move_line.credit == -80), "Invoice move is incorrect for debtors account"
-
I create the first voucher of payment
<create with values 240 EUR, journal EUR, and fills amount 180 for the invoice of 200$ and 70 for the invoice of 100$>
I set the context that will be used for the encoding of all the vouchers of this file
-
!context
'type': 'payment'
-
I create the first voucher of payment with values 240 EUR, journal EUR
-
!record {model: account.voucher, id: account_voucher_1_case2_suppl, view: view_vendor_payment_form}:
account_id: account.cash
amount: 240.0
company_id: base.main_company
journal_id: bank_journal_EUR
name: 'First payment: Case 2 SUPPL USD/EUR',
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-03-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
-
I fill amounts 180 for the invoice of 200$ and 70 for the invoice of 100$
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_EUR'), 240.0, 2, ttype='payment', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 240.0,
'company_id': ref('base.main_company'),
'currency_id': ref('base.EUR'),
'journal_id': ref('bank_journal_EUR'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'payment',
'date': time.strftime("%Y-03-01"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'First payment: Case 2 SUPPL USD/EUR',
}
if not res['value']['line_dr_ids']:
res['value']['line_dr_ids'] = [{'type': 'dr', 'account_id': ref('account.a_pay'),}]
for item in res['value']['line_dr_ids']:
if item['amount_unreconciled'] == 200.00:
item['amount'] = 180.00
voucher_id = self.browse(cr, uid, ref('account_voucher_1_case2_suppl'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 200.00:
data += [(item.id, 180.0)]
else:
item['amount'] = 70.00
vals['line_dr_ids'] = [(0,0,i) for i in res['value']['line_dr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 70.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is -15.0
@ -201,7 +213,7 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 20.0 and move_line.amount_residual == 15) , "Residual amount is not correct for first Invoice"
-
-
I check the residual amuont of Invoice2, should be 30 in residual currency and 24 in amount_residual
-
!python {model: account.invoice}: |
@ -210,40 +222,37 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 30 and move_line.amount_residual == 24) , "Residual amount is not correct for second Invoice"
-
I create the second voucher of payment
<create with values 45 USD, journal USD, and fill amounts 20 for the invoice of 200$ and 30 for the invoice of 100$>
-
I create the second voucher of payment with values 45 USD, journal USD,
-
!record {model: account.voucher, id: account_voucher_2_case2_suppl, view: view_vendor_payment_form}:
account_id: account.cash
amount: 45.0
company_id: base.main_company
journal_id: bank_journal_USD
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-04-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'Second payment: Case 2 SUPPL USD/EUR'
-
I fill amounts 20 for the invoice of 200$ and 30 for the invoice of 100$>
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_EUR'), 45.0, 2, ttype='payment', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 45.0,
'company_id': ref('base.main_company'),
'currency_id': ref('base.USD'),
'journal_id': ref('bank_journal_USD'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'payment',
'date': time.strftime("%Y-%m-%d"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'Second payment: Case 2 SUPPL USD/EUR',
}
vals.update(self.onchange_date(cr, uid, [], time.strftime('%Y-04-01'), ref('base.USD'), 45.0)['value'])
if not res['value']['line_dr_ids']:
res['value']['line_dr_ids'] = [{'type': 'dr', 'account_id': ref('account.a_pay'),}]
for item in res['value']['line_dr_ids']:
if item['amount_unreconciled'] == 20.00:
item['amount'] = 20.00
voucher_id = self.browse(cr, uid, ref('account_voucher_2_case2_suppl'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 20.00:
data += [(item.id, 20.0)]
else:
item['amount'] = 30.00
vals['line_dr_ids'] = [(0,0,i) for i in res['value']['line_dr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 30.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is -5.0

View File

@ -1,6 +1,15 @@
-
In order to check the Account_voucher module with multi-currency in OpenERP,
I create 2 Invoices in USD and make 2 Payments one in USD and another in EUR, based on the currency rating on that particular date
-
I set the income and expense currency accounts on the main company
-
!python {model: res.company}: |
from datetime import datetime
vals = {
'income_currency_exchange_account_id': ref('account.o_expense'),
'expense_currency_exchange_account_id': ref('account.o_expense')}
self.write(cr, uid, ref('base.main_company'), vals)
-
I modify the debtor account in order to make sure there is no currency_id linked
-
@ -136,38 +145,41 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.debit - move_line.credit == 80), "Invoice move is incorrect for debtors account"
-
I create the first voucher of payment
<create with values 200 EUR, journal EUR, and fills amount 130 EUR for the invoice of 200 USD and 70 EUR for the invoice of 100 USD>
I set the context that will be used for the encoding of all the vouchers of this file
-
!context
'type': 'receipt'
-
I create the first voucher of payment with values 200 EUR, journal EUR
-
!record {model: account.voucher, id: account_voucher_1_case2a, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 200.0
company_id: base.main_company
journal_id: bank_journal_EUR
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-03-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'First payment: Case 2 USD/EUR DR EUR'
-
I fill amounts 130 for the invoice of 200$ and 70 for the invoice of 100$
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_EUR'), 240.0, False, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 200.0,
'company_id': ref('base.main_company'),
'currency_id': False,
'journal_id': ref('bank_journal_EUR'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-03-01"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'First payment: Case 2 USD/EUR DR EUR',
}
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 150.00:
item['amount'] = 130.00
voucher_id = self.browse(cr, uid, ref('account_voucher_1_case2a'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 150.00:
data += [(item.id, 130.0)]
else:
item['amount'] = 70.00
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 70.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I confirm the voucher
@ -187,18 +199,6 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', voucher_id.move_id.id)])
for move_line in move_line_obj.browse(cr, uid, move_lines):
assert move_line.state == 'valid', "Voucher move is not valid"
-
I check that my debtor account is correct
-
I check that the debtor account has 2 new lines with 0 in amount_currency columns and their credit columns are 130 and 70
-
!python {model: account.voucher}: |
voucher = self.search(cr, uid, [('name', '=', 'First payment: Case 2 USD/EUR DR EUR'), ('partner_id', '=', ref('base.res_partner_seagate'))])
voucher_id = self.browse(cr, uid, voucher[0])
move_line_obj = self.pool.get('account.move.line')
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', voucher_id.move_id.id)])
for move_line in move_line_obj.browse(cr, uid, move_lines):
assert move_line.amount_currency == 0.00, "A line has the 'amount_currency' column filled"
-
I check the residual amount of Invoice1, should be 55.56 in residual currency and 20 in amount_residual
-
@ -217,41 +217,37 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 22.22 and move_line.amount_residual == 10) , "Residual amount is not correct for second Invoice"
-
I create the second voucher of payment
<create with values 80 USD, journal USD, and fully reconcile the 2 invoices>
-
I create the second voucher of payment with values 80 USD, journal USD
-
!record {model: account.voucher, id: account_voucher_2_case2a, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 80
company_id: base.main_company
journal_id: bank_journal_USD
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-04-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'Second payment: Case 2 SUPPL USD/EUR DR EUR'
-
and I fully reconcile the 2 previous invoices
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_USD'), 80.0, 2, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 80.0,
'company_id': ref('base.main_company'),
'currency_id': ref('base.USD'),
'journal_id': ref('bank_journal_USD'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-%m-%d"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'exchange_acc_id': ref('account.o_expense'),
'comment': 'Write Off',
'name': 'Second payment: Case 2 SUPPL USD/EUR DR EUR',
}
vals.update(self.onchange_date(cr, uid, [], time.strftime('%Y-04-01'), ref('base.USD'), 80.0)['value'])
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 55.56:
item['amount'] = 55.56
voucher_id = self.browse(cr, uid, ref('account_voucher_2_case2a'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 55.56:
data += [(item.id, 55.56)]
else:
item['amount'] = 22.22
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 22.22)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 2.22

View File

@ -1,6 +1,15 @@
-
In order to check the Account_voucher module with multi-currency in OpenERP,
I create 2 Invoices in USD and make 2 Payments one in USD and another in EUR, based on the currency rating on that particular date
-
I set the income and expense currency accounts on the main company
-
!python {model: res.company}: |
from datetime import datetime
vals = {
'income_currency_exchange_account_id': ref('account.o_expense'),
'expense_currency_exchange_account_id': ref('account.o_expense')}
self.write(cr, uid, ref('base.main_company'), vals)
-
I modify the debtor account in order to set the currency_id = USD
-
@ -136,38 +145,41 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.debit - move_line.credit == 80), "Invoice move is incorrect for debtors account"
-
I create the first voucher of payment
<create with values 200 EUR (€), journal EUR, and fills amount 130€ for the invoice of 200$ and 70€ for the invoice of 100$>
I set the context that will be used for the encoding of all the vouchers of this file
-
!context
'type': 'receipt'
-
I create the first voucher of payment with values 200 EUR, journal EUR
-
!record {model: account.voucher, id: account_voucher_1_case2b, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 200.0
company_id: base.main_company
journal_id: bank_journal_EUR
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-03-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'First payment: Case 2 USD/EUR DR USD'
-
I fill amounts 130 for the invoice of 200$ and 70 for the invoice of 100$>
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_EUR'), 200.0, False, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 200.0,
'company_id': ref('base.main_company'),
'currency_id': ref('base.EUR'),
'journal_id': ref('bank_journal_EUR'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-03-01"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'First payment: Case 2 USD/EUR DR USD',
}
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 150.00:
item['amount'] = 130.00
voucher_id = self.browse(cr, uid, ref('account_voucher_1_case2b'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 150.00:
data += [(item.id, 130.0)]
else:
item['amount'] = 70.00
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 70.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I confirm the voucher
@ -211,8 +223,8 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 55.56 and move_line.amount_residual == 20) , "Residual amount is not correct for first Invoice"
- toto
I check the residual amuont of Invoice2, should be 22.22 in residual currency and 10 in amount_residual
-
I check the residual amount of Invoice2, should be 22.22 in residual currency and 10 in amount_residual
-
!python {model: account.invoice}: |
invoice_id = self.browse(cr, uid, ref("account_second_invoice_feb_michal"))
@ -220,41 +232,37 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 22.22 and move_line.amount_residual == 10) , "Residual amount is not correct for second Invoice"
-
I create the second voucher of payment
<create with values 80 USD, journal USD, and fully reconcile the 2 invoices>
-
I create the second voucher of payment with values 80 USD, journal USD
-
!record {model: account.voucher, id: account_voucher_2_case2b, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 80.0
company_id: base.main_company
journal_id: bank_journal_USD
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-04-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'Second payment: Case 2 SUPPL USD/EUR DR USD'
-
and I fully reconcil the 2 previous invoices
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_USD'), 80.0, ref('base.USD'), ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 80.0,
'company_id': ref('base.main_company'),
'currency_id': ref('base.USD'),
'journal_id': ref('bank_journal_USD'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-%m-%d"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'exchange_acc_id': ref('account.o_expense'),
'comment': 'Write Off',
'name': 'Second payment: Case 2 SUPPL USD/EUR DR USD',
}
vals.update(self.onchange_date(cr, uid, [], time.strftime('%Y-04-01'), ref('base.USD'), 80.0)['value'])
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 55.56:
item['amount'] = 55.56
voucher_id = self.browse(cr, uid, ref('account_voucher_2_case2b'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 55.56:
data += [(item.id, 55.56)]
else:
item['amount'] = 22.22
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 22.22)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 2.22
@ -320,8 +328,8 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 0.0 and move_line.amount_residual == 0.0 and invoice_id.state == 'paid') , "Residual amount is not correct for first Invoice"
-
I check the residual amuont of invoice 2, should be 0 in residual currency and 0 in amount_residual and paid
-
I check the residual amount of invoice 2, should be 0 in residual currency and 0 in amount_residual and paid
-
!python {model: account.invoice}: |
invoice_id = self.browse(cr, uid, ref("account_second_invoice_feb_michal"))

View File

@ -99,38 +99,41 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.debit - move_line.credit == 80.00), "Invoice move is incorrect for debtors account"
-
I create the first voucher of payment
<create with values 120 EUR, journal EUR, and fill amounts 100 for the invoice of 150 EUR and 20 for the invoice of 80 EUR>
I set the context that will be used for the encoding of all the vouchers of this file
-
!context
'type': 'receipt'
-
I create the first voucher of payment with values 120 EUR, journal EUR
-
!record {model: account.voucher, id: account_voucher_1_case3, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 120.0
company_id: base.main_company
journal_id: bank_journal_EUR
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-03-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'First payment: Case 3'
-
I fill amounts 100 for the invoice of 150€ and 20 for the invoice of 80€
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_EUR'), 120.00, False, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 120.00,
'company_id': ref('base.main_company'),
'currency_id': ref('base.EUR'),
'journal_id': ref('bank_journal_EUR'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-03-01"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'First payment: Case 3',
}
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 150.00:
item['amount'] = 100.00
voucher_id = self.browse(cr, uid, ref('account_voucher_1_case3'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 150.00:
data += [(item.id, 100.0)]
else:
item['amount'] = 20.00
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
data += [(item.id, 20.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 0.00
@ -181,7 +184,7 @@
move_lines = move_line_obj.search(cr, uid, [('move_id', '=', invoice_id.move_id.id), ('invoice', '=', invoice_id.id), ('account_id', '=', invoice_id.account_id.id)])
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 50.0 and move_line.amount_residual == 50.0) , "Residual amount is not correct for first Invoice"
-
-
I check the residual amuont of Invoice2 is 60
-
!python {model: account.invoice}: |
@ -191,38 +194,36 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.amount_residual_currency == 60.0 and move_line.amount_residual == 60.0) , "Residual amount is not correct for second Invoice"
-
I create the second voucher of payment and check to let open the debtor overpaid amount.
<create with values 120 EUR, journal EUR, and fill amounts 50 for the invoice of 150 EUR and 70 for the invoice of 80 EUR>
I create the second voucher of payment with values 120€, journal EUR, and check to let open the debtor overpaid amount
-
!record {model: account.voucher, id: account_voucher_2_case3, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 120.0
company_id: base.main_company
journal_id: bank_journal_EUR
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-04-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'Second payment: Case 3'
-
I fill amounts 50 for the invoice of 150€ and 70 for the invoice of 80€
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_EUR'), 120.00, False, ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 120.00,
'company_id': ref('base.main_company'),
'currency_id': ref('base.EUR'),
'journal_id': ref('bank_journal_EUR'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-04-01"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'comment': 'Write Off',
'name': 'Second payment: Case 3',
}
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 50.00:
item['amount'] = 50.00
elif item['amount_unreconciled'] == 60.00:
item['amount'] = 70.00
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
voucher_id = self.browse(cr, uid, ref('account_voucher_2_case3'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 50.00:
data += [(item.id, 50.0)]
elif item.amount_unreconciled == 60.00:
data += [(item.id, 70.00)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 0.00

View File

@ -1,6 +1,15 @@
-
In order to check the Account_voucher module with multi-currency in OpenERP,
I create an invoice in CAD and make its Payment in CHF based on the currency rating on that particular date.
-
I set the income and expense currency accounts on the main company
-
!python {model: res.company}: |
from datetime import datetime
vals = {
'income_currency_exchange_account_id': ref('account.o_expense'),
'expense_currency_exchange_account_id': ref('account.o_expense')}
self.write(cr, uid, ref('base.main_company'), vals)
-
I create currency CAD in OpenERP for January of 1.338800 Rate
-
@ -89,38 +98,40 @@
move_line = move_line_obj.browse(cr, uid, move_lines[0])
assert (move_line.debit - move_line.credit == 149.39), "Invoice move is incorrect for debtors account"
-
I create the first voucher of payment
<create with values 200 CHF, journal CHF, and completly pat the invoice of 200 CAD>
I set the context that will be used for the encoding of all the vouchers of this file
-
!context
'type': 'receipt'
-
I create the first voucher of payment with values 200 CHF, journal CHF
-
!record {model: account.voucher, id: account_voucher_1_case4, view: view_vendor_receipt_form}:
account_id: account.cash
amount: 200
company_id: base.main_company
journal_id: bank_journal_CHF
partner_id: base.res_partner_seagate
period_id: account.period_3
date: !eval time.strftime("%Y-03-01")
payment_option: 'with_writeoff'
writeoff_acc_id: account.a_expense
comment: 'Write Off'
name: 'First payment: Case 4'
-
I completly pay the invoice of 200 CAD
-
!python {model: account.voucher}: |
import netsvc, time
vals = {}
res = self.onchange_partner_id(cr, uid, [], ref("base.res_partner_seagate"), ref('bank_journal_CHF'), 200.00, ref('base.CHF'), ttype='receipt', date=False)
vals = {
'account_id': ref('account.cash'),
'amount': 200.00,
'company_id': ref('base.main_company'),
'currency_id': ref('base.CHF'),
'journal_id': ref('bank_journal_CHF'),
'partner_id': ref('base.res_partner_seagate'),
'period_id': ref('account.period_3'),
'type': 'receipt',
'date': time.strftime("%Y-%m-%d"),
'payment_option': 'with_writeoff',
'writeoff_acc_id': ref('account.a_expense'),
'exchange_acc_id': ref('account.o_expense'),
'comment': 'Write Off',
'name': 'First payment: Case 4',
}
vals.update(self.onchange_date(cr, uid, [], time.strftime('%Y-03-01'), ref('base.CHF'), 200.0)['value'])
if not res['value']['line_cr_ids']:
res['value']['line_cr_ids'] = [{'type': 'cr', 'account_id': ref('account.a_recv'),}]
for item in res['value']['line_cr_ids']:
if item['amount_unreconciled'] == 186.74:
item['amount'] = 186.74
vals['line_cr_ids'] = [(0,0,i) for i in res['value']['line_cr_ids']]
id = self.create(cr, uid, vals)
voucher_id = self.browse(cr, uid, id)
voucher_id = self.browse(cr, uid, ref('account_voucher_1_case4'))
data = []
for item in voucher_id.line_cr_ids:
if item.amount_unreconciled == 186.74:
data += [(item.id, 186.74)]
else:
data += [(item.id, 0.0)]
for line_id, amount in data:
self.pool.get('account.voucher.line').write(cr, uid, [line_id], {'amount': amount})
assert (voucher_id.state=='draft'), "Voucher is not in draft state"
-
I check that writeoff amount computed is 13.26
@ -151,7 +162,7 @@
-
I check that my debtor account is correct
-
I check that the debtor account has 1 new line with -186.74 as amount_currency columns and 149.39 of credit and currency is CHF.
I check that the debtor account has 1 new line with -298.78 as amount_currency columns and 149.39 of credit and currency is CAD.
-
I check that my currency rate difference is correct. 0 in debit with no amount_currency
-
@ -165,7 +176,7 @@
for move_line in move_line_obj.browse(cr, uid, move_lines):
if move_line.amount_currency == 200:
assert move_line.debit == 160.00, "Bank account has wrong entry."
elif move_line.amount_currency == -186.74:
elif move_line.amount_currency == -298.78:
assert move_line.credit == 149.39, "Debtor account has wrong entry."
elif move_line.debit == 0.00 and move_line.credit == 0.00:
assert move_line.amount_currency == 0.00, "Incorrect Currency Difference."

View File

@ -5,7 +5,6 @@
account_id: account.a_recv
amount: 30000.0
company_id: base.main_company
currency_id: base.EUR
journal_id: account.sales_journal
line_cr_ids:
- account_id: account.a_sale

View File

@ -75,13 +75,13 @@
<form string="Bill Payment">
<group col="6" colspan="4">
<field name="partner_id" required="1" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'invoice_currency':currency_id}" string="Supplier"/>
<field name="amount" on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, context)"/>
<field name="amount" on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)"/>
<field name="journal_id"
domain="[('type','in',['bank', 'cash'])]"
widget="selection" select="1"
on_change="onchange_journal(journal_id, line_dr_ids, False, partner_id, date, amount, type, context)"
on_change="onchange_journal(journal_id, line_dr_ids, False, partner_id, date, amount, type, company_id, context)"
string="Payment Method"/>
<field name="date" select="1" on_change="onchange_date(date, currency_id, amount, context)"/>
<field name="date" select="1" on_change="onchange_date(date, currency_id, payment_rate_currency_id, amount, company_id, context)"/>
<field name="reference" select="1" string="Payment Ref"/>
<field name="name" colspan="2"/>
<field name="account_id"
@ -92,7 +92,7 @@
</group>
<notebook colspan="4">
<page string="Payment Information">
<field name="line_dr_ids" attrs="{'invisible': [('type', '=', 'receipt')]}" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, context)">
<field name="line_dr_ids" attrs="{'invisible': [('type', '=', 'receipt')]}" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<tree string="Open Supplier Journal Entries" editable="bottom" colors="gray:amount==0">
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
@ -102,29 +102,35 @@
<field name="date_original" readonly="1"/>
<field name="date_due" readonly="1"/>
<field name="amount_original" readonly="1"/>
<field name="amount_unreconciled" sum="Open Balance" readonly="1"/>
<field name="amount" sum="Payment"/>
<field name="amount_unreconciled" readonly="1"/>
<field name="amount" sum="Total Allocation"/>
</tree>
</field>
<field name="line_cr_ids" colspan="4" nolabel="1" attrs="{'invisible': [('type', '=', 'payment')]}" default_get="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, context)">
<field name="line_cr_ids" colspan="4" nolabel="1" attrs="{'invisible': [('type', '=', 'payment')]}" default_get="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<tree string="Open Customer Journal Entries" editable="bottom" colors="gray:amount==0">
<field name="move_line_id"/>
<field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/>
<field name="date_original"/>
<field name="amount_original"/>
<field name="amount" sum="Payment"/>
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
domain="[('account_id.type','=','payable'), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]"
/>
<field name="account_id" groups="base.group_extended" domain="[('type','=','payable')]"/>
<field name="date_original" readonly="1"/>
<field name="date_due" readonly="1"/>
<field name="amount_original" readonly="1"/>
<field name="amount_unreconciled" readonly="1"/>
<field name="amount" sum="Total Allocation"/>
</tree>
</field>
<group col="2" colspan="3">
<separator string="Internal Notes" colspan="2"/>
<field name="narration" colspan="2" nolabel="1"/>
</group>
<group col="2" colspan="1">
<separator string="Other Information" colspan="2"/>
<field name="currency_id"/>
<field name="payment_rate" required="1" on_change="onchange_rate(payment_rate, amount, context)" groups='base.group_extended'/>
<field name="paid_amount_in_company_currency" groups='base.group_extended'/>
<field name="number"/>
<group col="4" colspan="1">
<separator string="Other Information" colspan="4"/>
<field name="currency_id" colspan="4"/>
<field name="payment_rate" required="1" on_change="onchange_rate(payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context)" groups='base.group_extended' colspan="3"/>
<field name="payment_rate_currency_id" groups='base.group_extended' colspan="1" nolabel="1" on_change="onchange_payment_rate_currency(currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context)"/>
<field name="paid_amount_in_company_currency" groups='base.group_extended' colspan="4" invisible="1"/>
<field name="number" colspan="4"/>
</group>
</page>
</notebook>
@ -140,14 +146,14 @@
<form string="Bill Payment">
<group col="6" colspan="4">
<field name="partner_id" domain="[('supplier','=',True)]" required="1" invisible="context.get('line_type', False)" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" context="{'invoice_currency':currency_id}" string="Supplier"/>
<field name="amount" invisible="context.get('line_type', False)" on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, context)"/>
<field name="amount" invisible="context.get('line_type', False)" on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)"/>
<field name="journal_id"
domain="[('type','in',['bank', 'cash'])]"
invisible="context.get('line_type', False)"
widget="selection" select="1"
on_change="onchange_journal(journal_id, line_dr_ids, False, partner_id, date, amount, type, context)"
on_change="onchange_journal(journal_id, line_dr_ids, False, partner_id, date, amount, type, company_id, context)"
string="Payment Method"/>
<field name="date" select="1" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, amount, context)"/>
<field name="date" select="1" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, payment_rate_currency_id, amount, company_id, context)"/>
<field name="reference" select="1" invisible="context.get('line_type', False)" string="Payment Ref"/>
<field name="name" colspan="2" invisible="context.get('line_type', False)"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
@ -156,6 +162,7 @@
invisible="True"/>
<field name="pre_line" invisible="1"/>
<field name="type" invisible="True"/>
<field name="currency_id" invisible="1" colspan="4"/>
</group>
<notebook colspan="4">
<page string="Payment Information">
@ -170,17 +177,25 @@
<field name="date_original" readonly="1"/>
<field name="date_due" readonly="1"/>
<field name="amount_original" readonly="1"/>
<field name="amount_unreconciled" sum="Open Balance" readonly="1"/>
<field name="amount" sum="Payment"/>
<field name="amount_unreconciled" readonly="1"/>
<field name="reconcile" on_change="onchange_reconcile(reconcile, amount, amount_unreconciled, context)"/>
<field name="amount" sum="Total Allocation" on_change="onchange_amount(amount, amount_unreconciled, context)"/>
</tree>
</field>
<field name="line_cr_ids" colspan="4" nolabel="1" attrs="{'invisible': [('pre_line','=',False)]}" default_get="{'journal_id':journal_id, 'partner_id':partner_id}">
<tree string="Credits" editable="bottom" colors="gray:amount==0">
<field name="move_line_id"/>
<field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/>
<field name="date_original"/>
<field name="amount_original"/>
<field name="amount" sum="Payment"/>
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
domain="[('account_id.type','=','payable'), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]"
required="1"
/>
<field name="account_id" groups="base.group_no_one" domain="[('type','=','payable')]"/>
<field name="date_original" readonly="1"/>
<field name="date_due" readonly="1"/>
<field name="amount_original" readonly="1"/>
<field name="amount_unreconciled" readonly="1"/>
<field name="reconcile" on_change="onchange_reconcile(reconcile, amount, amount_unreconciled, context)"/>
<field name="amount" sum="Total Allocation" on_change="onchange_amount(amount, amount_unreconciled, context)"/>
</tree>
</field>
<group col="2" colspan="3">
@ -188,18 +203,16 @@
<field name="narration" colspan="2" nolabel="1"/>
</group>
<group col="2" colspan="1">
<group col="2" colspan="1" attrs="{'invisible':[('currency_id','=',False)]}">
<separator string="Currency Options" colspan="2"/>
<field name="exchange_acc_id"
domain="[('type','=','other')]"/>
<field name="payment_rate" required="1" on_change="onchange_rate(payment_rate, amount, context)" groups='base.group_extended'/>
<field name="paid_amount_in_company_currency" groups='base.group_extended'/>
<group col="4" colspan="1" attrs="{'invisible':[('currency_id','=',False),('is_multi_currency','=',False)]}">
<separator string="Currency Options" colspan="4"/>
<field name="payment_rate" required="1" on_change="onchange_rate(payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context)" groups='base.group_extended' colspan="3"/>
<field name="payment_rate_currency_id" groups='base.group_extended' colspan="1" nolabel="1" on_change="onchange_payment_rate_currency(currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context)"/>
<field name="paid_amount_in_company_currency" groups='base.group_extended' colspan="4" invisible="1"/>
</group>
<group col="2" colspan="1">
<separator string="Payment Options" colspan="2"/>
<field name="writeoff_amount"/>
<field name="payment_option" required="1"/>
<field name="writeoff_amount"
attrs="{'invisible':[('payment_option','!=','with_writeoff')]}"/>
<field name="writeoff_acc_id"
attrs="{'invisible':[('payment_option','!=','with_writeoff')], 'required':[('payment_option','=','with_writeoff')]}"
domain="[('type','=','other')]"/>
@ -208,11 +221,6 @@
<field name="analytic_id"
groups="analytic.group_analytic_accounting"/>
</group>
<group col="4" colspan="2">
<separator string="Other Information" colspan="4"/>
<field name="number" colspan="4"/>
<field name="currency_id" invisible="1" colspan="4"/>
</group>
</group>
</page>
<page string="Journal Items" groups="base.group_extended" attrs="{'invisible': [('state','!=','posted')]}">
@ -220,6 +228,7 @@
<field name="period_id"/>
<field name="audit"/>
</group>
<field name="number" colspan="4"/>
<field name="move_ids" colspan="4" nolabel="1" readonly="1">
<tree string="Journal Items">
<field name="move_id"/>
@ -242,7 +251,7 @@
<group col="10" colspan="4">
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
<button name="cancel_voucher" string="Cancel" states="draft,proforma" icon="gtk-cancel" invisible="context.get('line_type', False)"/>
<button name="cancel_voucher" string="Unreconcile" type="object" states="posted" icon="terp-stock_effects-object-colorize" invisible="context.get('line_type', False)" confirm="Are you sure to unreconcile this record ?"/>
<button name="cancel_voucher" string="Unreconcile" type="object" states="posted" icon="terp-stock_effects-object-colorize" invisible="context.get('line_type', False)" confirm="Are you sure to unreconcile and cancel this record ?"/>
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft" icon="terp-stock_effects-object-colorize" invisible="context.get('line_type', False)"/>
<button name="proforma_voucher" string="Validate" states="draft" icon="gtk-go-forward" invisible="context.get('line_type', False)"/>
</group>
@ -289,14 +298,14 @@
<field name="amount"
invisible="context.get('line_type', False)"
string="Paid Amount"
on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, context)"/>
on_change="onchange_amount(amount, payment_rate, partner_id, journal_id, currency_id, type, date, payment_rate_currency_id, company_id, context)"/>
<field name="journal_id"
domain="[('type','in',['bank', 'cash'])]"
invisible="context.get('line_type', False)"
widget="selection" select="1"
on_change="onchange_journal(journal_id, line_cr_ids, False, partner_id, date, amount, type, context)"
on_change="onchange_journal(journal_id, line_cr_ids, False, partner_id, date, amount, type, company_id, context)"
string="Payment Method"/>
<field name="date" select="1" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, amount, context)"/>
<field name="date" select="1" invisible="context.get('line_type', False)" on_change="onchange_date(date, currency_id, payment_rate_currency_id, amount, company_id, context)"/>
<field name="reference" select="1" invisible="context.get('line_type', False)" string="Payment Ref"/>
<field name="name" colspan="2" invisible="context.get('line_type', False)"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
@ -308,7 +317,7 @@
</group>
<notebook colspan="4">
<page string="Payment Information">
<field name="line_cr_ids" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, context)">
<field name="line_cr_ids" default_get="{'journal_id':journal_id, 'type':type, 'partner_id':partner_id}" colspan="4" nolabel="1" height="140" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<tree string="Invoices and outstanding transactions" editable="bottom" colors="gray:amount==0">
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
@ -319,17 +328,25 @@
<field name="date_original" readonly="1"/>
<field name="date_due" readonly="1"/>
<field name="amount_original" readonly="1"/>
<field name="amount_unreconciled" sum="Open Balance" readonly="1"/>
<field name="amount" sum="Payment"/>
<field name="amount_unreconciled" readonly="1"/>
<field name="reconcile" on_change="onchange_reconcile(reconcile, amount, amount_unreconciled, context)"/>
<field name="amount" sum="Total Allocation" on_change="onchange_amount(amount, amount_unreconciled, context)"/>
</tree>
</field>
<field name="line_dr_ids" colspan="4" nolabel="1" attrs="{'invisible': [('pre_line','=',False)]}" default_get="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, context)">
<field name="line_dr_ids" colspan="4" nolabel="1" attrs="{'invisible': [('pre_line','=',False)]}" default_get="{'journal_id':journal_id, 'partner_id':partner_id}" on_change="onchange_line_ids(line_dr_ids, line_cr_ids, amount, currency_id, context)">
<tree string="Credits" editable="bottom" colors="gray:amount==0">
<field name="move_line_id"/>
<field name="account_id" groups="base.group_extended" domain="[('type','=','receivable')]"/>
<field name="date_original"/>
<field name="amount_original"/>
<field name="amount" sum="Payment"/>
<field name="move_line_id" context="{'journal_id':parent.journal_id, 'partner_id':parent.partner_id}"
on_change="onchange_move_line_id(move_line_id)"
domain="[('account_id.type','in',('receivable','payable')), ('reconcile_id','=', False), ('partner_id','=',parent.partner_id)]"
required="1"
/>
<field name="account_id" groups="base.group_no_one" domain="[('type','=','receivable')]"/>
<field name="date_original" readonly="1"/>
<field name="date_due" readonly="1"/>
<field name="amount_original" readonly="1"/>
<field name="amount_unreconciled" readonly="1"/>
<field name="reconcile" on_change="onchange_reconcile(reconcile, amount, amount_unreconciled, context)"/>
<field name="amount" sum="Total Allocation" on_change="onchange_amount(amount, amount_unreconciled, context)"/>
</tree>
</field>
<group col="2" colspan="3">
@ -337,18 +354,16 @@
<field name="narration" colspan="2" nolabel="1"/>
</group>
<group col="2" colspan="1">
<group col="2" colspan="1" attrs="{'invisible':[('currency_id','=',False)]}">
<separator string="Currency Options" colspan="2"/>
<field name="exchange_acc_id"
domain="[('type','=','other')]"/>
<field name="payment_rate" required="1" on_change="onchange_rate(payment_rate, amount, context)" groups='base.group_extended'/>
<field name="paid_amount_in_company_currency" groups='base.group_extended'/>
<group col="4" colspan="1" attrs="{'invisible':[('currency_id','=',False),('is_multi_currency','=',False)]}">
<separator string="Currency Options" colspan="4"/>
<field name="payment_rate" required="1" on_change="onchange_rate(payment_rate, amount, currency_id, payment_rate_currency_id, company_id, context)" groups='base.group_extended' colspan="3"/>
<field name="payment_rate_currency_id" groups='base.group_extended' colspan="1" nolabel="1" on_change="onchange_payment_rate_currency(currency_id, payment_rate, payment_rate_currency_id, date, amount, company_id, context)"/>
<field name="paid_amount_in_company_currency" groups='base.group_extended' colspan="4" invisible="1"/>
</group>
<group col="2" colspan="1">
<separator string="Payment Options" colspan="2"/>
<field name="writeoff_amount"/>
<field name="payment_option" required="1"/>
<field name="writeoff_amount"
attrs="{'invisible':[('payment_option','!=','with_writeoff')]}"/>
<field name="writeoff_acc_id"
attrs="{'invisible':[('payment_option','!=','with_writeoff')], 'required':[('payment_option','=','with_writeoff')]}"
domain="[('type','=','other')]"/>
@ -357,10 +372,6 @@
<field name="analytic_id"
groups="analytic.group_analytic_accounting"/>
</group>
<group col="4" colspan="2">
<separator string="Other Information" colspan="4"/>
<field name="number" colspan="4"/>
</group>
</group>
</page>
<page string="Journal Items" groups="base.group_extended" attrs="{'invisible': [('state','!=','posted')]}">
@ -368,6 +379,7 @@
<field name="period_id"/>
<field name="audit"/>
</group>
<field name="number" colspan="4"/>
<field name="move_ids" colspan="4" nolabel="1" readonly="1">
<tree string="Journal Items">
<field name="move_id"/>
@ -390,7 +402,7 @@
<group col="10" colspan="4">
<field name="state" widget="statusbar" statusbar_visible="draft,posted" statusbar_colors='{"proforma":"blue"}'/>
<button name="cancel_voucher" string="Cancel" states="draft,proforma" icon="gtk-cancel" invisible="context.get('line_type', False)"/>
<button name="cancel_voucher" string="Unreconcile" type="object" states="posted" invisible="context.get('line_type', False)" icon="terp-stock_effects-object-colorize" confirm="Are you sure to unreconcile this record ?"/>
<button name="cancel_voucher" string="Unreconcile" type="object" states="posted" invisible="context.get('line_type', False)" icon="terp-stock_effects-object-colorize" confirm="Are you sure to unreconcile and cancel this record ?"/>
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft" icon="terp-stock_effects-object-colorize" invisible="context.get('line_type', False)"/>
<button name="proforma_voucher" string="Validate" states="draft" icon="gtk-go-forward" invisible="context.get('line_type', False)"/>
</group>

View File

@ -83,8 +83,8 @@
<form string="Sales Receipt">
<group col="6" colspan="4">
<field name="partner_id" required="1" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)" string="Customer"/>
<field name="date" on_change="onchange_date(date, currency_id, amount, context)"/>
<field name="journal_id" domain="[('type','in',['sale','sale_refund'])]" widget="selection" on_change="onchange_journal(journal_id, line_cr_ids, tax_id, partner_id, date, amount, type, context)"/>
<field name="date" on_change="onchange_date(date, currency_id, currency_id, amount, company_id, context)"/>
<field name="journal_id" domain="[('type','in',['sale','sale_refund'])]" widget="selection" on_change="onchange_journal(journal_id, line_cr_ids, tax_id, partner_id, date, amount, type, company_id, context)"/>
<field name="number"/>
<field name="name" colspan="2"/>
<field name="company_id" select="1" widget="selection" groups="base.group_multi_company"/>
@ -210,8 +210,8 @@
<form string="Supplier Voucher">
<group col="6" colspan="4">
<field name="partner_id" domain="[('supplier','=',True)]" required="1" string="Supplier" on_change="onchange_partner_id(partner_id, journal_id, amount, currency_id, type, date, context)"/>
<field name="date" string="Bill Date" select="1" on_change="onchange_date(date, currency_id, amount, context)"/>
<field name="journal_id" domain="[('type','in',['purchase','purchase_refund'])]" widget="selection" select="1" on_change="onchange_journal(journal_id, line_dr_ids, tax_id, partner_id, date, amount, type, context)"/>
<field name="date" string="Bill Date" select="1" on_change="onchange_date(date, currency_id, currency_id, amount, company_id, context)"/>
<field name="journal_id" domain="[('type','in',['purchase','purchase_refund'])]" widget="selection" select="1" on_change="onchange_journal(journal_id, line_dr_ids, tax_id, partner_id, date, amount, type, company_id, context)"/>
<field name="number"/>
<field name="name" colspan="2"/>
<field name="reference" select="1"/>

View File

@ -24,7 +24,7 @@
"version": "1.1",
"author" : "OpenERP SA",
"website" : "http://www.openerp.com",
"category" : "Hidden",
"category": 'Accounting & Finance',
"depends" : ["base", "decimal_precision"],
"description": """
Module for defining analytic accounting object.

View File

@ -161,7 +161,7 @@ class account_analytic_account(osv.osv):
'debit': fields.function(_debit_credit_bal_qtty, type='float', string='Debit', multi='debit_credit_bal_qtty', digits_compute=dp.get_precision('Account')),
'credit': fields.function(_debit_credit_bal_qtty, type='float', string='Credit', multi='debit_credit_bal_qtty', digits_compute=dp.get_precision('Account')),
'quantity': fields.function(_debit_credit_bal_qtty, type='float', string='Quantity', multi='debit_credit_bal_qtty'),
'quantity_max': fields.float('Maximum Quantity', help='Sets the higher limit of quantity of hours.'),
'quantity_max': fields.float('Maximum Time', help='Sets the higher limit of quantity of hours.'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'contact_id': fields.many2one('res.partner.address', 'Contact'),
'user_id': fields.many2one('res.users', 'Account Manager'),
@ -242,6 +242,13 @@ class account_analytic_account(osv.osv):
res['value']['partner_id'] = partner
return res
def onchange_partner_id(self, cr, uid, ids, partner, context=None):
partner_obj = self.pool.get('res.partner')
if not partner:
return {'value':{'contact_id': False}}
address = partner_obj.address_get(cr, uid, [partner], ['contact'])
return {'value':{'contact_id': address['contact']}}
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
if not args:
args=[]

View File

@ -20,9 +20,9 @@
##############################################################################
{
'name': 'Analytic Journal Billing Rate, Define the default invoicing rate for a specific journal',
'name': 'Billing Rates on Contracts',
'version': '1.0',
'category': 'Hidden',
'category': 'Sales Management',
'description': """
This module allows you to define what is the default invoicing rate for a specific journal on a given account.
==============================================================================================================

View File

@ -21,9 +21,9 @@
{
'name': 'Human Resources',
'name': 'Jobs on Contracts',
'version': '1.0',
'category': 'Hidden',
'category': 'Sales Management',
'description': """
This module allows you to define what is the default function of a specific user on a given account.
====================================================================================================

View File

@ -24,7 +24,7 @@
{
'name': 'Database Anonymization',
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'complexity': "easy",
'description': """
This module allows you to anonymize a database.

View File

@ -3,5 +3,3 @@
"access_ir_model_fields_anonymization_user","ir_model_fields_anonymization user","model_ir_model_fields_anonymization",,1,0,0,0
"access_ir_model_fields_anonymization_history_group_system","ir_model_fields_anonymization_history group_user","model_ir_model_fields_anonymization_history","base.group_system",1,1,1,1
"access_ir_model_fields_anonymization_history_user","ir_model_fields_anonymization_history user","model_ir_model_fields_anonymization_history",,1,0,0,0
"access_ir_model_fields_anonymize_wizard_group_system","ir_model_fields_anonymize_wizard group_user","model_ir_model_fields_anonymize_wizard","base.group_system",1,1,1,1
"access_ir_model_fields_anonymize_wizard_user","ir_model_fields_anonymize_wizard user","model_ir_model_fields_anonymize_wizard",,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 access_ir_model_fields_anonymization_user ir_model_fields_anonymization user model_ir_model_fields_anonymization 1 0 0 0
4 access_ir_model_fields_anonymization_history_group_system ir_model_fields_anonymization_history group_user model_ir_model_fields_anonymization_history base.group_system 1 1 1 1
5 access_ir_model_fields_anonymization_history_user ir_model_fields_anonymization_history user model_ir_model_fields_anonymization_history 1 0 0 0
access_ir_model_fields_anonymize_wizard_group_system ir_model_fields_anonymize_wizard group_user model_ir_model_fields_anonymize_wizard base.group_system 1 1 1 1
access_ir_model_fields_anonymize_wizard_user ir_model_fields_anonymize_wizard user model_ir_model_fields_anonymize_wizard 1 0 0 0

View File

@ -21,7 +21,7 @@
{
'name': 'Association profile',
'name': 'Associations Management',
'version': '0.1',
'category': 'Specific Industry Applications',
'complexity': "normal",
@ -37,6 +37,7 @@ It installs the profile for associations to manage events, registrations, member
'demo_xml': [],
'installable': True,
'active': False,
'core': True,
'certificate': '0078696047261',
'images': ['images/association1.jpeg'],
}

View File

@ -6,7 +6,6 @@
id="base.menu_association"
icon="terp-calendar"
sequence="9"
groups="base.group_extended"
web_icon="images/association.png"
web_icon_hover="images/association-hover.png"/>
<menuitem name="Configuration" id="base.menu_event_config" parent="base.menu_association" sequence="30" groups="base.group_extended"/>

View File

@ -68,6 +68,7 @@ The dashboard for auction includes:
],
'installable': True,
'auction': True,
'active': False,
'certificate': '0039333102717',
'images': ['images/auction1.jpeg','images/auction2.jpeg','images/auction3.jpeg'],

View File

@ -99,9 +99,7 @@
</td>
<td>
<para style="Addressee">[[ o['partner'] and o['partner'].name or False]]</para>
<para style="Addressee">[[o['partner'] and o['partner'].address[0].street or False]]</para>
<para style="Addressee">[[o['partner'] and o['partner'].address[0].zip or False]][[o['partner'] and o['partner'].address[0].city or False]]</para>
<para style="Addressee">[[o['partner'] and o['partner'].address[0].country_id.name or False]]</para>
<para style="Addressee">[[o['partner'] and o['partner'].address and display_address(o['partner'].address[0]) ]]</para>
</td>
</tr>
</blockTable>

View File

@ -84,9 +84,7 @@
</para>
<para style="P5">[[o.bord_vnd_id.partner_id.title]]</para>
<para style="P5">[[o.bord_vnd_id.partner_id.name]]</para>
<para style="P5">[[o.bord_vnd_id.partner_id.address[0].street]]</para>
<para style="P5">[[o.bord_vnd_id.partner_id.address[0].zip]],[[o.bord_vnd_id.partner_id.address[0].city]]</para>
<para style="P5">[[o.bord_vnd_id.partner_id.address[0].country_id.name]]</para>
<para style="P5">[[o.bord_vnd_id.partner_id.address and display_address(o.bord_vnd_id.partner_id.address[0]) ]] </para>
<para style="P6">
<font color="white"> </font>
</para>

View File

@ -74,9 +74,7 @@
</td>
<td>
<para style="Addressee">[[ o['partner'] and o['partner'].name or False]]</para>
<para style="Addressee">[[o['partner'] and o['partner'].address[0].street or False]]</para>
<para style="Addressee">[[o['partner'] and o['partner'].address[0].zip or False]][[o['partner'] and o['partner'].address[0].city or False]]</para>
<para style="P11">[[o['partner'] and o['partner'].address[0].country_id.name or False]]</para>
<para style="Addressee">[[ o['partner'] and o['partner'].address and display_address(o['partner'].address[0]) </para>
<para style="P4">
<font color="white"> </font>
</para>

View File

@ -23,7 +23,7 @@
{
'name': 'Audit Trail',
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'description': """
This module lets administrator track every user operation on all the objects of the system.
===========================================================================================

View File

@ -21,9 +21,9 @@
{
'name': 'OpenID',
'name': 'OpenID Authentification',
'version': '2.0',
'category': 'Hidden',
'category': 'Tools',
'description': """Allow users to login through OpenID.""",
'author': 'OpenERP s.a.',
'maintainer': 'OpenERP s.a.',

View File

@ -22,7 +22,7 @@
{
'name': 'Action Rule',
'version': '1.0',
'category': 'Hidden',
'category': 'Sales Management',
'description': """
This module allows to implement action rules for any object.
============================================================

View File

@ -34,7 +34,7 @@ It supports:
- Recurring events
- Invitations to people""",
"author" : "OpenERP SA",
'category': 'Hidden',
'category': 'Tools',
'website': 'http://www.openerp.com',
"init_xml" : [
'base_calendar_data.xml'

View File

@ -23,7 +23,7 @@
{
'name': 'Base Contact',
'version': '1.0',
'category': 'Hidden',
'category': 'Sales Management',
'complexity': "expert",
'description': """
This module allows you to manage your contacts entirely.

View File

@ -7,104 +7,104 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-01-11 11:14+0000\n"
"PO-Revision-Date: 2009-02-03 06:25+0000\n"
"Last-Translator: <>\n"
"PO-Revision-Date: 2011-12-03 15:19+0000\n"
"Last-Translator: kifcaliph <kifcaliph@hotmail.com>\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: 2011-11-05 05:04+0000\n"
"X-Generator: Launchpad (build 14231)\n"
"X-Launchpad-Export-Date: 2011-12-04 04:43+0000\n"
"X-Generator: Launchpad (build 14418)\n"
#. module: base_contact
#: field:res.partner.contact,title:0
msgid "Title"
msgstr ""
msgstr "اللقب"
#. module: base_contact
#: view:res.partner.address:0
msgid "# of Contacts"
msgstr ""
msgstr "عدد جهات الاتصال"
#. module: base_contact
#: field:res.partner.job,fax:0
msgid "Fax"
msgstr ""
msgstr "فاكس"
#. module: base_contact
#: view:base.contact.installer:0
msgid "title"
msgstr ""
msgstr "الاسم"
#. module: base_contact
#: help:res.partner.job,date_start:0
msgid "Start date of job(Joining Date)"
msgstr ""
msgstr "تاريخ الالتحاق بالوظيفة"
#. module: base_contact
#: view:base.contact.installer:0
msgid "Select the Option for Addresses Migration"
msgstr ""
msgstr "حدد الخيار لنقل العناوين"
#. module: base_contact
#: help:res.partner.job,function:0
msgid "Function of this contact with this partner"
msgstr ""
msgstr "مهمة جهة الاتصال هذه عند هذا الشريك"
#. module: base_contact
#: help:res.partner.job,state:0
msgid "Status of Address"
msgstr ""
msgstr "حالة العنوان"
#. module: base_contact
#: help:res.partner.job,name:0
msgid ""
"You may enter Address first,Partner will be linked "
"automatically if any."
msgstr ""
msgstr "يمكنك إدخال العنوان أولاً، وسيتمّ ربط الشريك تلقائياً إن وُجِد."
#. module: base_contact
#: help:res.partner.job,fax:0
msgid "Job FAX no."
msgstr ""
msgstr "فاكس العمل"
#. module: base_contact
#: field:res.partner.contact,mobile:0
msgid "Mobile"
msgstr ""
msgstr "الجوال"
#. module: base_contact
#: view:res.partner.contact:0
#: field:res.partner.contact,comment:0
msgid "Notes"
msgstr ""
msgstr "ملاحظات"
#. module: base_contact
#: model:process.node,note:base_contact.process_node_contacts0
msgid "People you work with."
msgstr ""
msgstr "أشخاص تعمل معهم."
#. module: base_contact
#: model:process.transition,note:base_contact.process_transition_functiontoaddress0
msgid "Define functions and address."
msgstr ""
msgstr "تعريف المهام والعنوان"
#. module: base_contact
#: help:res.partner.job,date_stop:0
msgid "Last date of job"
msgstr ""
msgstr "تاريخ ترك الوظيفة"
#. module: base_contact
#: view:base.contact.installer:0
#: field:base.contact.installer,migrate:0
msgid "Migrate"
msgstr ""
msgstr "نقل"
#. module: base_contact
#: view:res.partner.contact:0
#: field:res.partner.job,name:0
msgid "Partner"
msgstr ""
msgstr "الشريك"
#. module: base_contact
#: model:process.node,note:base_contact.process_node_function0
@ -114,12 +114,12 @@ msgstr ""
#. module: base_contact
#: model:process.node,name:base_contact.process_node_partners0
msgid "Partners"
msgstr ""
msgstr "الشركاء"
#. module: base_contact
#: field:res.partner.job,state:0
msgid "State"
msgstr ""
msgstr "المحافظة"
#. module: base_contact
#: help:res.partner.contact,active:0
@ -151,27 +151,42 @@ msgid ""
"an other object.\n"
" "
msgstr ""
"\n"
" تمكنك هذه الوحدة البرمجية من إدارة جهات الاتصال بشكل كامل.\n"
" فهي تسمح لك بـتعرف:\n"
" * جهات اتصال غير ذات صلة بشريك،\n"
" * جهات اتصال ذات عناوين عمل متعددة (ربما لارتباطها بشركاء مختلفين)،\n"
" * جهات اتصال ذات مهام مختلفة لكل عنوان من عناوين وظائفها\n"
"\n"
" كذلك تضيف هذه الوحدة البرمجية عناصر جديدة إلى القائمة تحت\n"
" الشركاء / جهات الاتصال\n"
" الشركاء / المهام\n"
"\n"
" تنبه إلى أن هذه الوحدة البرمجية تقوم بتحويل العناوين الموجودة مسبقاً إلى "
"\"عناوين\" و \"جهات اتصال\"، مما يعني أن بعض حقول العناوين سيتم حذفها (مثل "
"اسم جهة الاتصال) لأنه من المفترض أن يتم تعريفها في كائن آخر.\n"
" "
#. module: base_contact
#: model:ir.module.module,shortdesc:base_contact.module_meta_information
#: model:process.process,name:base_contact.process_process_basecontactprocess0
msgid "Base Contact"
msgstr ""
msgstr "جهة الاتصال الأساسية"
#. module: base_contact
#: field:res.partner.job,date_stop:0
msgid "Date Stop"
msgstr ""
msgstr "تاريخ التوقف"
#. module: base_contact
#: model:ir.actions.act_window,name:base_contact.action_res_partner_job
msgid "Contact's Jobs"
msgstr ""
msgstr "الوظائف"
#. module: base_contact
#: view:res.partner:0
msgid "Categories"
msgstr ""
msgstr "الفئات"
#. module: base_contact
#: help:res.partner.job,sequence_partner:0
@ -179,70 +194,72 @@ msgid ""
"Order of importance of this job title in the list of job "
"title of the linked partner"
msgstr ""
"ترتيب المسمى الوظيفي هذا حسب الأهمية بين المسميات الوظيغية المستخدمة لدى "
"الشريك"
#. module: base_contact
#: field:res.partner.job,extension:0
msgid "Extension"
msgstr ""
msgstr "الامتداد"
#. module: base_contact
#: help:res.partner.job,extension:0
msgid "Internal/External extension phone number"
msgstr ""
msgstr "امتداد رقم الهاتف الداخلي/الخارجي"
#. module: base_contact
#: help:res.partner.job,phone:0
msgid "Job Phone no."
msgstr ""
msgstr "هاتف العمل"
#. module: base_contact
#: view:res.partner.contact:0
#: field:res.partner.contact,job_ids:0
msgid "Functions and Addresses"
msgstr ""
msgstr "المهام والعناوين"
#. module: base_contact
#: model:ir.model,name:base_contact.model_res_partner_contact
#: field:res.partner.job,contact_id:0
msgid "Contact"
msgstr ""
msgstr "جهة الاتصال"
#. module: base_contact
#: help:res.partner.job,email:0
msgid "Job E-Mail"
msgstr ""
msgstr "البريد الإلكتروني للعمل"
#. module: base_contact
#: field:res.partner.job,sequence_partner:0
msgid "Partner Seq."
msgstr ""
msgstr "رقم الشريك"
#. module: base_contact
#: model:process.transition,name:base_contact.process_transition_functiontoaddress0
msgid "Function to address"
msgstr ""
msgstr "مهمة إلى عنوان"
#. module: base_contact
#: field:base.contact.installer,progress:0
msgid "Configuration Progress"
msgstr ""
msgstr "سير الإعدادات"
#. module: base_contact
#: field:res.partner.contact,name:0
msgid "Last Name"
msgstr ""
msgstr "اسم العائلة"
#. module: base_contact
#: view:res.partner:0
#: view:res.partner.contact:0
msgid "Communication"
msgstr ""
msgstr "التواصل"
#. module: base_contact
#: field:base.contact.installer,config_logo:0
#: field:res.partner.contact,photo:0
msgid "Image"
msgstr ""
msgstr "صورة"
#. module: base_contact
#: selection:res.partner.job,state:0
@ -252,7 +269,7 @@ msgstr ""
#. module: base_contact
#: model:ir.model,name:base_contact.model_res_partner_address
msgid "Partner Addresses"
msgstr ""
msgstr "عناوين الشريك"
#. module: base_contact
#: view:base.contact.installer:0
@ -262,12 +279,12 @@ msgstr ""
#. module: base_contact
#: field:res.partner.job,sequence_contact:0
msgid "Contact Seq."
msgstr ""
msgstr "رقم جهة الاتصال"
#. module: base_contact
#: view:res.partner.address:0
msgid "Search Contact"
msgstr ""
msgstr "بحث جهة الإتصال"
#. module: base_contact
#: model:ir.actions.act_window,name:base_contact.action_partner_contact_form
@ -277,7 +294,7 @@ msgstr ""
#: view:res.partner:0
#: field:res.partner.address,job_ids:0
msgid "Contacts"
msgstr ""
msgstr "جهات الاتصال"
#. module: base_contact
#: view:base.contact.installer:0
@ -289,58 +306,58 @@ msgstr ""
#. module: base_contact
#: model:process.node,note:base_contact.process_node_addresses0
msgid "Working and private addresses."
msgstr ""
msgstr "عناوين العمل والعناوين الخاصة"
#. module: base_contact
#: help:res.partner.job,address_id:0
msgid "Address which is linked to the Partner"
msgstr ""
msgstr "العنوان المرتبط بالشريك"
#. module: base_contact
#: field:res.partner.job,function:0
msgid "Partner Function"
msgstr ""
msgstr "مهمة الشريك"
#. module: base_contact
#: help:res.partner.job,other:0
msgid "Additional phone field"
msgstr ""
msgstr "حقل هاتف إضافي"
#. module: base_contact
#: field:res.partner.contact,website:0
msgid "Website"
msgstr ""
msgstr "الموقع الإلكتروني"
#. module: base_contact
#: view:base.contact.installer:0
msgid "Otherwise these details will not be visible from address/contact."
msgstr ""
msgstr "وإلا فلن تظهر هذه التفاصيل في العنوان/جهة الاتصال."
#. module: base_contact
#: view:base.contact.installer:0
msgid "Configure"
msgstr ""
msgstr "ضبط الإعدادات"
#. module: base_contact
#: field:res.partner.contact,email:0
#: field:res.partner.job,email:0
msgid "E-Mail"
msgstr ""
msgstr "البريد الإلكتروني"
#. module: base_contact
#: model:ir.model,name:base_contact.model_base_contact_installer
msgid "base.contact.installer"
msgstr ""
msgstr "base.contact.installer"
#. module: base_contact
#: view:res.partner.job:0
msgid "Contact Functions"
msgstr ""
msgstr "مهام جهة الاتصال"
#. module: base_contact
#: field:res.partner.job,phone:0
msgid "Phone"
msgstr ""
msgstr "هاتف"
#. module: base_contact
#: view:base.contact.installer:0
@ -350,164 +367,164 @@ msgstr ""
#. module: base_contact
#: field:res.partner.contact,active:0
msgid "Active"
msgstr ""
msgstr "نشِط"
#. module: base_contact
#: field:res.partner.contact,function:0
msgid "Main Function"
msgstr ""
msgstr "المهمة الرئيسية"
#. module: base_contact
#: model:process.transition,note:base_contact.process_transition_partnertoaddress0
msgid "Define partners and their addresses."
msgstr ""
msgstr "تعريف الشركاء وعناوينهم"
#. module: base_contact
#: view:res.partner.contact:0
msgid "Seq."
msgstr ""
msgstr "رقم"
#. module: base_contact
#: field:res.partner.contact,lang_id:0
msgid "Language"
msgstr ""
msgstr "اللغة"
#. module: base_contact
#: view:res.partner.contact:0
msgid "Extra Information"
msgstr ""
msgstr "معلومات إضافية"
#. module: base_contact
#: model:process.node,note:base_contact.process_node_partners0
msgid "Companies you work with."
msgstr ""
msgstr "الشركات التي تتعامل معها."
#. module: base_contact
#: view:res.partner.contact:0
msgid "Partner Contact"
msgstr ""
msgstr "جهة الاتصال بالشريك"
#. module: base_contact
#: view:res.partner.contact:0
msgid "General"
msgstr ""
msgstr "عام"
#. module: base_contact
#: view:res.partner.contact:0
msgid "Photo"
msgstr ""
msgstr "صورة"
#. module: base_contact
#: field:res.partner.contact,birthdate:0
msgid "Birth Date"
msgstr ""
msgstr "تاريخ الميلاد"
#. module: base_contact
#: help:base.contact.installer,migrate:0
msgid "If you select this, all addresses will be migrated."
msgstr ""
msgstr "إذا اخترت هذا الخيار، سيتم نقل جميع العناوين."
#. module: base_contact
#: selection:res.partner.job,state:0
msgid "Current"
msgstr ""
msgstr "الحالي"
#. module: base_contact
#: field:res.partner.contact,first_name:0
msgid "First Name"
msgstr ""
msgstr "الاسم الأول"
#. module: base_contact
#: model:ir.model,name:base_contact.model_res_partner_job
msgid "Contact Partner Function"
msgstr ""
msgstr "مهمة الشريك"
#. module: base_contact
#: field:res.partner.job,other:0
msgid "Other"
msgstr ""
msgstr "غير ذلك"
#. module: base_contact
#: model:process.node,name:base_contact.process_node_function0
msgid "Function"
msgstr ""
msgstr "المهمة"
#. module: base_contact
#: field:res.partner.address,job_id:0
#: field:res.partner.contact,job_id:0
msgid "Main Job"
msgstr ""
msgstr "الوظيفة الرئيسية"
#. module: base_contact
#: model:process.transition,note:base_contact.process_transition_contacttofunction0
msgid "Defines contacts and functions."
msgstr ""
msgstr "تعريف جهات الاتصال والمهام."
#. module: base_contact
#: model:process.transition,name:base_contact.process_transition_contacttofunction0
msgid "Contact to function"
msgstr ""
msgstr "جهة اتصال إلى مهمة"
#. module: base_contact
#: view:res.partner:0
#: field:res.partner.job,address_id:0
msgid "Address"
msgstr ""
msgstr "العنوان"
#. module: base_contact
#: field:res.partner.contact,country_id:0
msgid "Nationality"
msgstr ""
msgstr "الجنسية"
#. module: base_contact
#: model:ir.actions.act_window,name:base_contact.act_res_partner_jobs
msgid "Open Jobs"
msgstr ""
msgstr "الوظائف المفتوحة"
#. module: base_contact
#: field:base.contact.installer,name:0
msgid "Name"
msgstr ""
msgstr "الاسم"
#. module: base_contact
#: view:base.contact.installer:0
msgid "You can migrate Partner's current addresses to the contact."
msgstr ""
msgstr "يمكنك نقل العناوين الحالية للشريك إلى جهة الاتصال"
#. module: base_contact
#: field:res.partner.contact,partner_id:0
msgid "Main Employer"
msgstr ""
msgstr "صاحب العمل الرئيسي"
#. module: base_contact
#: model:ir.actions.act_window,name:base_contact.action_base_contact_installer
msgid "Address Migration"
msgstr ""
msgstr "نقل العنوان"
#. module: base_contact
#: view:res.partner:0
msgid "Postal Address"
msgstr ""
msgstr "العنوان البريدي"
#. module: base_contact
#: model:process.node,name:base_contact.process_node_addresses0
#: view:res.partner:0
msgid "Addresses"
msgstr ""
msgstr "العناوين"
#. module: base_contact
#: model:process.transition,name:base_contact.process_transition_partnertoaddress0
msgid "Partner to address"
msgstr ""
msgstr "شريك إلى عنوان"
#. module: base_contact
#: field:res.partner.job,date_start:0
msgid "Date Start"
msgstr ""
msgstr "تاريخ البدء"
#. module: base_contact
#: help:res.partner.job,sequence_contact:0
msgid ""
"Order of importance of this address in the list of "
"addresses of the linked contact"
msgstr ""
msgstr "ترتيب هذا العنوان حسب الأهمية بين عناوين جهة الاتصال"

View File

@ -19,12 +19,12 @@
#
##############################################################################
{
"name" : "Base - Password Encryption",
"name" : "DB Password Encryption",
"version" : "1.1",
"author" : ['OpenERP SA', "FS3"],
"maintainer" : "OpenERP SA",
"website" : "http://www.openerp.com",
"category" : "Hidden",
"category" : "Tools",
'complexity': "easy",
"description": """
Replaces cleartext passwords in the database with a secure hash

View File

@ -19,9 +19,9 @@
#
##############################################################################
{
'name': 'Create IBAN bank accounts',
'name': 'IBAN Bank Accounts',
'version': '1.0',
'category': 'Hidden',
"category": 'Accounting & Finance',
'complexity': "easy",
'description': """
This module installs the base for IBAN (International Bank Account Number) bank accounts and checks for its validity.

View File

@ -20,9 +20,9 @@
##############################################################################
{
'name': 'Module Technical Guide in Restructured Text ',
'name': 'Generate Docs of Modules',
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'description': """
This module generates the Technical Guides of selected modules in Restructured Text format (RST).
=================================================================================================

View File

@ -21,9 +21,9 @@
{
'name': 'Base module quality - To check the quality of other modules' ,
'name': 'Analyse Module Quality' ,
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'description': """
The aim of this module is to check the quality of other modules.
================================================================

View File

@ -23,7 +23,7 @@
{
'name': 'Module Record',
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'description': """
This module allows you to create a new module without any development.
======================================================================

View File

@ -2,3 +2,4 @@
"access_base_report_creator_report","base_report_creator.report","model_base_report_creator_report","base.group_system",1,1,1,1
"access_base_report_creator_report_fields","base_report_creator.report.fields","model_base_report_creator_report_fields","base.group_system",1,1,1,1
"access_base_report_creator_report_filter","base_report_creator.report.filter","model_base_report_creator_report_filter","base.group_system",1,1,1,1
"access_base_report_creator_report_result","base_report_creator.report.result","model_base_report_creator_report_result","base.group_system",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_base_report_creator_report base_report_creator.report model_base_report_creator_report base.group_system 1 1 1 1
3 access_base_report_creator_report_fields base_report_creator.report.fields model_base_report_creator_report_fields base.group_system 1 1 1 1
4 access_base_report_creator_report_filter base_report_creator.report.filter model_base_report_creator_report_filter base.group_system 1 1 1 1
5 access_base_report_creator_report_result base_report_creator.report.result model_base_report_creator_report_result base.group_system 1 1 1 1

View File

@ -21,9 +21,9 @@
{
'name': 'Base Setup',
'name': 'Initial Setup Tools',
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'complexity': "easy",
'description': """
This module helps to configure the system at the installation of a new database.

View File

@ -28,290 +28,6 @@ from osv import fields, osv
from tools.translate import _
from lxml import etree
#Application and feature chooser, this could be done by introspecting ir.modules
DEFAULT_MODULES = {
'Customer Relationship Management' : ['crm',],
'Sales Management' : ['sale',],
'Project Management' : ['project',],
'Knowledge Management' : ['document',],
'Warehouse Management' : ['stock',],
'Manufacturing' : ['mrp'],
'Accounting & Finance' : ['account'],
'Purchase Management' : ['purchase'],
'Human Resources' : ['hr',],
'Point of Sale' : ['point_of_sale',],
'Marketing' : ['marketing',],
}
class base_setup_installer(osv.osv_memory):
_name = 'base.setup.installer'
_inherit = 'res.config.installer'
_columns = {
'selection' : fields.text('Selection'),
}
def fields_get(self, cr, uid, fields=None, context=None):
if context is None:
context = {}
if fields is None:
fields = {}
fields = {}
category_proxy = self.pool.get('ir.module.category')
domain = [('parent_id', '=', False),
('name', '!=', 'Uncategorized'),
('visible', '=', True)]
category_ids = category_proxy.search(cr, uid, domain, context=context)
for category in category_proxy.browse(cr, uid, category_ids, context=context):
category_name = 'category_%d' % (category.id,)
fields[category_name] = {
'type' : 'boolean',
'string' : category.name,
'name' : category_name,
'help' : category.description,
}
module_proxy = self.pool.get('ir.module.module')
module_ids = module_proxy.search(cr, uid, [], context=context)
for module in module_proxy.browse(cr, uid, module_ids, context=context):
module_name = 'module_%d' % (module.id,)
module_is_installed = module.state == 'installed'
fields[module_name] = {
'type' : 'boolean',
'string' : module.shortdesc,
'name' : module_name,
'help' : module.description,
}
return fields
def default_get(self, cr, uid, fields=None, context=None):
if context is None:
context = {}
if fields is None:
fields = {}
result = {}
if 'dont_compute_virtual_attributes' not in context:
module_proxy = self.pool.get('ir.module.module')
module_ids = module_proxy.search(cr, uid, [], context=context)
for module in module_proxy.browse(cr, uid, module_ids, context=context):
result['module_%d' % (module.id,)] = module.state == 'installed'
cat_proxy = self.pool.get('ir.module.category')
cat_ids = cat_proxy.search(cr, uid, [], context=context)
for cat in cat_proxy.browse(cr, uid, cat_ids, context=context):
m = DEFAULT_MODULES.get(cat.name,[])
r = module_proxy.search(cr, uid, [('state','=','installed'),('name','in',m)])
result['category_%d' % (cat.id,)] = bool(r) and (len(r) == len(m))
return result
def fields_view_get(self, cr, uid, view_id=None, view_type='from', context=None, toolbar=False, submenu=False):
def in_extended_view_group(cr, uid, context=None):
try:
model, group_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_extended')
except ValueError:
return False
return group_id in self.pool.get('res.users').read(cr, uid, uid, ['groups_id'], context=context)['groups_id']
result = super(base_setup_installer, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
module_category_proxy = self.pool.get('ir.module.category')
domain = [('parent_id', '=', False),
('name', '!=', 'Uncategorized'),
('visible', '=', True)]
module_category_ids = module_category_proxy.search(cr, uid, domain, context=context, order='sequence asc')
arch = ['<form string="%s">' % _('Automatic Base Setup')]
arch.append('<separator string="%s" colspan="4" />' % _('Install Applications'))
module_proxy = self.pool.get('ir.module.module')
extended_view = in_extended_view_group(cr, uid, context=context)
for module_category in module_category_proxy.browse(cr, uid, module_category_ids, context=context):
domain = [('category_id', '=', module_category.id)]
if not extended_view:
domain.append(('complexity', '!=', 'expert'))
modules = module_proxy.browse(cr, uid, module_proxy.search(cr, uid, domain, context=context), context=context)
if not modules:
continue
m = DEFAULT_MODULES.get(module_category.name, [])
r = module_proxy.search(cr, uid, [('state', '=', 'installed'),('name', 'in', m)], context=context)
readonly = bool(r)
attributes = {
'name' : 'category_%d' % (module_category.id,),
'on_change' : 'on_change_%s_%d(category_%d)' % ('category', module_category.id, module_category.id,),
}
if readonly:
attributes['modifiers'] = simplejson.dumps({'readonly' : True})
arch.append("""<field %s />""" % (" ".join(["%s='%s'" % (key, value,)
for key, value in attributes.iteritems()]),))
# Compute the modules to show
for module_category in module_category_proxy.browse(cr, uid, module_category_ids, context=context):
domain = [('category_id', '=', module_category.id)]
if not extended_view:
domain.append(('complexity', '!=', 'expert'))
default_modules = DEFAULT_MODULES.get(module_category.name, False)
if default_modules:
domain.append(('name', 'not in', default_modules))
modules = module_proxy.browse(cr, uid, module_proxy.search(cr, uid, domain, context=context), context=context)
if not modules:
continue
modifiers = {
'invisible' : [('category_%d' % (module_category.id), '=', False)],
}
module_modifiers = dict(modifiers)
arch.append("""<separator string="%s Features" colspan="4" modifiers='%s'/>""" % (
cgi.escape(module_category.name),
simplejson.dumps(modifiers))
)
for module in modules:
#module_modifiers['readonly'] = module.state == 'installed'
arch.append("""<field name="module_%d" modifiers='%s' />""" % (
module.id,
simplejson.dumps(module_modifiers))
)
arch.append(
'<separator colspan="4" />'
'<group colspan="4" col="2">'
'<button special="cancel" string="Cancel" icon="gtk-cancel" />'
'<button string="Install Modules" type="object" name="apply_cb" icon="gtk-apply" />'
'</group>'
)
arch.append('</form>')
result['arch'] = ''.join(arch)
return result
def __getattr__(self, name):
if name.startswith('on_change_category_'):
def proxy(cr, uid, ids, value, context=None):
item = 'category_%s' % name[len('on_change_category_'):]
return self._on_change_selection(cr, uid, ids, item, value, context=context)
return proxy
return getattr(super(base_setup_installer, self), name)
def _on_change_selection(self, cr, uid, ids, item, value, context=None):
if not isinstance(item, basestring) or not value:
return {}
if item.startswith('category_') or item.startswith('module_'):
object_name, identifier = item.split('_')
else:
return {}
values = {
}
#if object_name == 'category':
# module_ids = self.pool.get('ir.module.module').search(cr, uid, [('category_id', '=', int(identifier))], context=context)
# for module_id in module_ids:
# values['module_%d' % module_id] = 1
return {'value': values}
def create(self, cr, uid, values, context=None):
to_install = {'categories' : [], 'modules' : []}
for key, value in values.iteritems():
if value == 1 and (key.startswith('module_') or key.startswith('category_')):
kind, identifier = key.split('_')
if kind == 'category':
to_install['categories'].append(long(identifier))
if kind == 'module':
to_install['modules'].append(long(identifier))
values = {
'selection' : simplejson.dumps(to_install),
}
context.update(dont_compute_virtual_attributes=True)
return super(base_setup_installer, self).create(cr, uid, values, context=context)
def apply_cb(self, cr, uid, ids, context=None):
category_proxy = self.pool.get('ir.module.category')
for installer in self.browse(cr, uid, ids, context=context):
to_install = simplejson.loads(installer.selection)
proxy = self.pool.get('ir.module.module')
module_ids = proxy.search(cr, uid, [('id', 'in', to_install['modules'])], context=context)
modules = set(record['name']
for record in proxy.read(cr, uid, module_ids, ['name'], context=context))
category_ids = category_proxy.search(cr, uid, [('id', 'in', to_install['categories'])], context=context)
selected_categories = set(record['name']
for record in category_proxy.read(cr, uid, category_ids, ['name'], context=context))
# FIXME: Use a workaround, but can do better
for category_name, default_modules in DEFAULT_MODULES.iteritems():
if category_name in selected_categories:
modules.update(default_modules)
# Special Cases:
# * project_mrp: the dependencies are sale, project, procurement, mrp_jit
if 'sale' in modules and 'project' in modules:
modules.add('project_mrp')
need_update = False
module_ids = proxy.search(cr, uid, [('name', 'in', list(modules))], context=context)
if module_ids:
proxy.state_update(cr, uid, module_ids, 'to install', ['uninstalled'], context=context)
need_update = True
category_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'module_category_hidden_link')
while True and category_id:
cr.execute("select id, name from ir_module_module m where category_id = %s \
and (select count(d.id) from ir_module_module_dependency d \
where d.module_id = m.id) = (select count(d.id) from \
ir_module_module_dependency d inner join ir_module_module m2 on d.name = m2.name \
where d.module_id=m.id and m2.state in %s ) and state = %s",
(category_id[1], ('installed', 'to install', 'to upgrade', ), 'uninstalled',))
inner_modules = [name for _, name in cr.fetchall()]
module_ids = proxy.search(cr, uid, [('name', 'in', inner_modules)], context=context)
if not module_ids:
break
modules.update(inner_modules)
proxy.state_update(cr, uid, module_ids, 'to install', ['uninstalled'], context=context)
need_update = True
domain = [('name', 'in', list(modules)),
('state', '=', 'installed')]
for module in proxy.browse(cr, uid, proxy.search(cr, uid, domain, context=context), context):
cr.execute("update ir_actions_todo set state='open' \
from ir_model_data as data where data.res_id = ir_actions_todo.id \
and ir_actions_todo.type='special'\
and data.model = 'ir.actions.todo' and data.module=%s", (module.name, ))
if need_update:
cr.commit()
self.pool = pooler.restart_pool(cr.dbname, update_module=True)[1]
return self.pool.get('res.config').next(cr, uid, [], context=context)
#Migrate data from another application Conf wiz
class migrade_application_installer_modules(osv.osv_memory):

View File

@ -1,36 +1,6 @@
<openerp>
<data>
<record model="ir.actions.act_window" id="action_base_setup_installer_beta">
<field name="name">Install Applications</field>
<field name="res_model">base.setup.installer</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="base_setup_installer_todo" model="ir.actions.todo">
<field name="action_id" ref="action_base_setup_installer_beta" />
<field name="category_id" ref="base.category_administration_config"/>
<field name="sequence">2</field>
</record>
<record id="action_start_configurator" model="ir.actions.server">
<field name="name">Start Configuration</field>
<field name="model_id" ref="base.model_ir_actions_todo"/>
<field name="state">code</field>
<field name="code" eval="'# obj is a browse_record and will provide stupid ids to method\n' 'action = pool.get(\'ir.actions.todo\').action_launch(cr, uid, ' + str([ref('base_setup_installer_todo')]) + ', context=context)'"/>
</record>
<menuitem name="Add More Features" action="action_start_configurator" id="menu_view_base_module_configuration" parent="base.menu_config" type="server" icon="STOCK_EXECUTE" sequence="1"/>
<record id="ir_ui_view_sc_configuration" model="ir.ui.view_sc">
<field name="name">Add More Features</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="menu_view_base_module_configuration" />
</record>
<!-- Import or create customers configartion view -->
<record id="action_import_create_installer" model="ir.actions.act_window">
<field name="name">Create or Import Customers</field>
@ -162,6 +132,7 @@
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="context">{'res_id': user.company_id.id}</field>
<field name="help">Fill in your company data (address, logo, bank accounts) so that it's printed on your reports. You can click on the button 'Preview Header' in order to check the header/footer of PDF documents.</field>
</record>
<record id="base_setup_company_todo" model="ir.actions.todo">
<field name="action_id" ref="action_base_setup_company"/>

View File

@ -20,10 +20,10 @@
##############################################################################
{
"name":"Server Object Synchronization",
"name":"Multi-DB Synchronization",
"version":"0.1",
"author":"OpenERP SA",
"category":"Hidden",
"category":"Tools",
"description": """
Synchronization with all objects.
=================================

View File

@ -4,7 +4,7 @@
"author": "OpenERP SA",
"version": "1.0",
"depends": ["base"],
"category" : "Hidden",
"category" : "Tools",
'complexity': "easy",
'description': """
Common base for tools modules.

View File

@ -22,7 +22,7 @@
{
'name': 'VAT Number Validation',
'version': '1.0',
'category': 'Hidden',
"category": 'Accounting & Finance',
'complexity': "easy",
'description': """
VAT validation for Partners' VAT numbers

View File

@ -20,9 +20,9 @@
##############################################################################
{
'name': 'Dashboard Creator',
'name': 'Dashboards',
'version': '1.0',
'category': 'Hidden',
'category': 'Tools',
'complexity': "normal",
'description': """
Lets the user create a custom dashboard.

View File

@ -49,7 +49,7 @@ To access OpenERP Calendar using WebCal to remote site use the URL like:
DATABASE_NAME: Name of database on which OpenERP Calendar is created
CALENDAR_NAME: Name of calendar to access
""",
'category': 'Hidden',
'category': 'Tools',
"author" : "OpenERP SA",
'website': 'http://www.openerp.com',
"init_xml" : ["caldav_data.xml"],

View File

@ -21,7 +21,7 @@
"name" : "Claim from Delivery",
"version" : "1.0",
"author" : "OpenERP SA",
"category" : "Hidden",
'category': 'Sales Management',
"depends" : ["base", "crm_claim", "stock"],
"init_xml" : [],
"demo_xml" : [],

View File

@ -21,7 +21,7 @@
{
'name': 'Customer & Supplier Relationship Management',
'name': 'Customer Relationship Management',
'version': '1.0',
'category': 'Customer Relationship Management',
'complexity': "easy",
@ -61,7 +61,8 @@ Creates a dashboard for CRM that includes:
'mail',
'base_calendar',
'resource',
'board'
'board',
'fetchmail'
],
'init_xml': [
'crm_data.xml',
@ -118,20 +119,17 @@ Creates a dashboard for CRM that includes:
'crm_phonecall_demo.xml',
],
'test': [
'test/test_crm_lead.yml',
'test/test_crm_meeting.yml',
'test/test_crm_opportunity.yml',
'test/test_crm_phonecall.yml',
'test/test_crm_recurrent_meeting.yml',
'test/test_crm_stage_changes.yml',
'test/test_crm_recurrent_meeting_case2.yml',
'test/test_crm_lead_case2.yml',
'test/test_crm_opportunity_case2.yml',
'test/test_crm_phonecall_case2.yml',
'test/test_crm_partner2opportunity.yml',
'test/test_crm_segmentation.yml',
'test/process/communication_with_customer.yml',
'test/process/lead2opportunity2win.yml',
'test/process/merge_opportunity.yml',
'test/process/cancel_lead.yml',
'test/process/segmentation.yml',
'test/ui/crm_demo.yml',
'test/ui/duplicate_lead.yml',
'test/ui/delete_lead.yml'
],
'installable': True,
'core': True,
'active': False,
'certificate': '0079056041421',
'images': ['images/sale_crm_crm_dashboard.png', 'images/crm_dashboard.jpeg','images/leads.jpeg','images/meetings.jpeg','images/opportunities.jpeg','images/outbound_calls.jpeg','images/stages.jpeg'],

View File

@ -468,10 +468,12 @@ class crm_case(crm_base):
self._action(cr, uid, cases, state)
return True
#DEAD Code
def remind_partner(self, cr, uid, ids, context=None, attach=False):
return self.remind_user(cr, uid, ids, context, attach,
destination=False)
#DEAD Code
def remind_user(self, cr, uid, ids, context=None, attach=False, destination=True):
mail_message = self.pool.get('mail.message')
for case in self.browse(cr, uid, ids, context=context):

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<data>
<record id="base.user_demo" model="res.users">
<field name="groups_id" eval="[(4,ref('base.group_sale_salesman'))]"/>
</record>
@ -12,5 +12,17 @@
<field name="res_id" ref="crm.menu_crm_case_categ_meet"/>
</record>
<record model="crm.case.section" id="section_sales_marketing_department">
<field name="name">Sales Marketing Department</field>
<field name="code">Sales Marketing</field>
<field name="parent_id" ref="crm.section_sales_department"></field>
</record>
<record model="crm.segmentation" id="crm_segmentation0">
<field name="name">OpenERP partners</field>
<field name="exclusif">True</field>
<field name="categ_id" ref="base.res_partner_category_2"/>
</record>
</data>
</openerp>

View File

@ -27,7 +27,7 @@ from tools.translate import _
from crm import crm_case
import binascii
import tools
from mail.mail_message import to_email
CRM_LEAD_PENDING_STATES = (
crm.AVAILABLE_STATES[2][0], # Cancelled
@ -352,36 +352,380 @@ class crm_lead(crm_case, osv.osv):
"""
return self.set_priority(cr, uid, ids, '3')
def convert_opportunity(self, cr, uid, ids, context=None):
""" Precomputation for converting lead to opportunity
def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
# prepare opportunity data into dictionary for merging
opportunities = self.browse(cr, uid, ids, context=context)
def _get_first_not_null(attr):
if hasattr(oldest, attr):
return getattr(oldest, attr)
for opportunity in opportunities:
if hasattr(opportunity, attr):
return getattr(opportunity, attr)
return False
def _get_first_not_null_id(attr):
res = _get_first_not_null(attr)
return res and res.id or False
def _concat_all(attr):
return ', '.join(filter(lambda x: x, [getattr(opportunity, attr) or '' for opportunity in opportunities if hasattr(opportunity, attr)]))
data = {}
for field_name in fields:
field_info = self._all_columns.get(field_name)
if field_info is None:
continue
field = field_info.column
if field._type in ('many2many', 'one2many'):
continue
elif field._type == 'many2one':
data[field_name] = _get_first_not_null_id(field_name) # !!
elif field._type == 'text':
data[field_name] = _concat_all(field_name) #not lost
else:
data[field_name] = _get_first_not_null(field_name) #not lost
return data
def _merge_find_oldest(self, cr, uid, ids, context=None):
if context is None:
context = {}
#TOCHECK: where pass 'convert' in context ?
if context.get('convert'):
ids = list(set(ids) - set(context.get('lead_ids', False)) )
#search opportunities order by create date
opportunity_ids = self.search(cr, uid, [('id', 'in', ids)], order='create_date' , context=context)
oldest_id = opportunity_ids[0]
return self.browse(cr, uid, oldest_id, context=context)
def _mail_body_text(self, cr, uid, lead, fields, title=False, context=None):
body = []
if title:
body.append("%s\n" % (title))
for field_name in fields:
field_info = self._all_columns.get(field_name)
if field_info is None:
continue
field = field_info.column
value = None
if field._type == 'selection':
if hasattr(field.selection, '__call__'):
key = field.selection(self, cr, uid, context=context)
else:
key = field.selection
value = dict(key).get(lead[field_name], lead[field_name])
elif field._type == 'many2one':
if lead[field_name]:
value = lead[field_name].name_get()[0][1]
else:
value = lead[field_name]
body.append("%s: %s" % (field.string, value or ''))
return "\n".join(body + ['---'])
def _merge_notification(self, cr, uid, opportunity_id, opportunities, context=None):
#TOFIX: mail template should be used instead of fix body, subject text
details = []
merge_message = _('Merged opportunities')
subject = [merge_message]
fields = ['name', 'partner_id', 'stage_id', 'section_id', 'user_id', 'categ_id', 'channel_id', 'company_id', 'contact_name',
'email_from', 'phone', 'fax', 'mobile', 'state_id', 'description', 'probability', 'planned_revenue',
'country_id', 'city', 'street', 'street2', 'zip']
for opportunity in opportunities:
subject.append(opportunity.name)
title = "%s : %s" % (merge_message, opportunity.name)
details.append(self._mail_body_text(cr, uid, opportunity, fields, title=title, context=context))
subject = subject[0] + ", ".join(subject[1:])
details = "\n\n".join(details)
return self.message_append(cr, uid, [opportunity_id], subject, body_text=details, context=context)
def _merge_opportunity_history(self, cr, uid, opportunity_id, opportunities, context=None):
message = self.pool.get('mail.message')
for opportunity in opportunities:
for history in opportunity.message_ids:
message.write(cr, uid, history.id, {
'res_id': opportunity_id,
'subject' : _("From %s : %s") % (opportunity.name, history.subject)
}, context=context)
return True
def _merge_opportunity_attachments(self, cr, uid, opportunity_id, opportunities, context=None):
attachment = self.pool.get('ir.attachment')
# return attachments of opportunity
def _get_attachments(opportunity_id):
attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', opportunity_id)], context=context)
return attachment.browse(cr, uid, attachment_ids, context=context)
count = 1
first_attachments = _get_attachments(opportunity_id)
for opportunity in opportunities:
attachments = _get_attachments(opportunity.id)
for first in first_attachments:
for attachment in attachments:
if attachment.name == first.name:
values = dict(
name = "%s (%s)" % (attachment.name, count,),
res_id = opportunity_id,
)
attachment.write(values)
count+=1
return True
def merge_opportunity(self, cr, uid, ids, context=None):
"""
To merge opportunities
:param ids: list of opportunities ids to merge
"""
if context is None: context = {}
#TOCHECK: where pass lead_ids in context?
lead_ids = context and context.get('lead_ids', []) or []
if len(ids) <= 1:
raise osv.except_osv(_('Warning !'),_('Please select more than one opportunities.'))
ctx_opportunities = self.browse(cr, uid, lead_ids, context=context)
opportunities = self.browse(cr, uid, ids, context=context)
opportunities_list = list(set(opportunities) - set(ctx_opportunities))
oldest = self._merge_find_oldest(cr, uid, ids, context=context)
if ctx_opportunities :
first_opportunity = ctx_opportunities[0]
tail_opportunities = opportunities_list
else:
first_opportunity = opportunities_list[0]
tail_opportunities = opportunities_list[1:]
fields = ['partner_id', 'title', 'name', 'categ_id', 'channel_id', 'city', 'company_id', 'contact_name', 'country_id',
'partner_address_id', 'type_id', 'user_id', 'section_id', 'state_id', 'description', 'email', 'fax', 'mobile',
'partner_name', 'phone', 'probability', 'planned_revenue', 'street', 'street2', 'zip', 'create_date', 'date_action_last',
'date_action_next', 'email_from', 'email_cc', 'partner_name']
data = self._merge_data(cr, uid, ids, oldest, fields, context=context)
# merge data into first opportunity
self.write(cr, uid, [first_opportunity.id], data, context=context)
#copy message and attachements into the first opportunity
self._merge_opportunity_history(cr, uid, first_opportunity.id, tail_opportunities, context=context)
self._merge_opportunity_attachments(cr, uid, first_opportunity.id, tail_opportunities, context=context)
#Notification about loss of information
self._merge_notification(cr, uid, first_opportunity, opportunities, context=context)
#delete tail opportunities
self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context)
#open first opportunity
self.case_open(cr, uid, [first_opportunity.id])
return first_opportunity.id
def _convert_opportunity_data(self, cr, uid, lead, customer, section_id=False, context=None):
crm_stage = self.pool.get('crm.case.stage')
contact_id = False
if customer:
contact_id = self.pool.get('res.partner').address_get(cr, uid, [customer.id])['default']
if not section_id:
section_id = lead.section_id and lead.section_id.id or False
if section_id:
stage_ids = crm_stage.search(cr, uid, [('sequence','>=',1), ('section_ids','=', section_id)])
else:
stage_ids = crm_stage.search(cr, uid, [('sequence','>=',1)])
stage_id = stage_ids and stage_ids[0] or False
return {
'planned_revenue': lead.planned_revenue,
'probability': lead.probability,
'name': lead.name,
'partner_id': customer and customer.id or False,
'user_id': (lead.user_id and lead.user_id.id),
'type': 'opportunity',
'stage_id': stage_id or False,
'date_action': time.strftime('%Y-%m-%d %H:%M:%S'),
'partner_address_id': contact_id
}
def _convert_opportunity_notification(self, cr, uid, lead, context=None):
success_message = _("Lead '%s' has been converted to an opportunity.") % lead.name
self.message_append(cr, uid, [lead.id], success_message, body_text=success_message, context=context)
self.log(cr, uid, lead.id, success_message)
self._send_mail_to_salesman(cr, uid, lead, context=context)
return True
def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None):
partner = self.pool.get('res.partner')
mail_message = self.pool.get('mail.message')
customer = False
if partner_id:
customer = partner.browse(cr, uid, partner_id, context=context)
for lead in self.browse(cr, uid, ids, context=context):
if lead.state in ('done', 'cancel'):
continue
if user_ids or section_id:
self.allocate_salesman(cr, uid, [lead.id], user_ids, section_id, context=context)
vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
self.write(cr, uid, [lead.id], vals, context=context)
self._convert_opportunity_notification(cr, uid, lead, context=context)
#TOCHECK: why need to change partner details in all messages of lead ?
if lead.partner_id:
msg_ids = [ x.id for x in lead.message_ids]
mail_message.write(cr, uid, msg_ids, {
'partner_id': lead.partner_id.id
}, context=context)
return True
def _lead_create_partner(self, cr, uid, lead, context=None):
partner = self.pool.get('res.partner')
partner_id = partner.create(cr, uid, {
'name': lead.partner_name or lead.contact_name or lead.name,
'user_id': lead.user_id.id,
'comment': lead.description,
'section_id': lead.section_id.id or False,
'address': []
})
return partner_id
def _lead_set_partner(self, cr, uid, lead, partner_id, context=None):
res = False
res_partner = self.pool.get('res.partner')
if partner_id:
res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id.id or False})
contact_id = res_partner.address_get(cr, uid, [partner_id])['default']
res = lead.write({'partner_id' : partner_id, 'partner_address_id': contact_id}, context=context)
return res
def _lead_create_partner_address(self, cr, uid, lead, partner_id, context=None):
address = self.pool.get('res.partner.address')
return address.create(cr, uid, {
'partner_id': partner_id,
'name': lead.contact_name,
'phone': lead.phone,
'mobile': lead.mobile,
'email': lead.email_from and to_email(lead.email_from)[0],
'fax': lead.fax,
'title': lead.title and lead.title.id or False,
'function': lead.function,
'street': lead.street,
'street2': lead.street2,
'zip': lead.zip,
'city': lead.city,
'country_id': lead.country_id and lead.country_id.id or False,
'state_id': lead.state_id and lead.state_id.id or False,
})
def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
"""
This function convert partner based on action.
if action is 'create', create new partner with contact and assign lead to new partner_id.
otherwise assign lead to specified partner_id
"""
if context is None:
context = {}
context.update({'active_ids': ids})
partner_ids = {}
for lead in self.browse(cr, uid, ids, context=context):
if action == 'create':
if not partner_id:
partner_id = self._lead_create_partner(cr, uid, lead, context=context)
self._lead_create_partner_address(cr, uid, lead, partner_id, context=context)
self._lead_set_partner(cr, uid, lead, partner_id, context=context)
partner_ids[lead.id] = partner_id
return partner_ids
data_obj = self.pool.get('ir.model.data')
value = {}
def _send_mail_to_salesman(self, cr, uid, lead, context=None):
"""
Send mail to salesman with updated Lead details.
@ lead: browse record of 'crm.lead' object.
"""
#TOFIX: mail template should be used here instead of fix subject, body text.
message = self.pool.get('mail.message')
email_to = lead.user_id and lead.user_id.user_email
if not email_to:
return False
email_from = lead.section_id and lead.section_id.user_id and lead.section_id.user_id.user_email or email_to
partner = lead.partner_id and lead.partner_id.name or lead.partner_name
subject = "lead %s converted into opportunity" % lead.name
body = "Info \n Id : %s \n Subject: %s \n Partner: %s \n Description : %s " % (lead.id, lead.name, lead.partner_id.name, lead.description)
return message.schedule_with_attach(cr, uid, email_from, [email_to], subject, body)
for case in self.browse(cr, uid, ids, context=context):
context.update({'active_id': case.id})
data_id = data_obj._get_id(cr, uid, 'crm', 'view_crm_lead2opportunity_partner')
view_id1 = False
if data_id:
view_id1 = data_obj.browse(cr, uid, data_id, context=context).res_id
value = {
'name': _('Create Partner'),
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'crm.lead2opportunity.partner',
'view_id': False,
'context': context,
'views': [(view_id1, 'form')],
'type': 'ir.actions.act_window',
'target': 'new',
'nodestroy': True
def allocate_salesman(self, cr, uid, ids, user_ids, team_id=False, context=None):
index = 0
for lead_id in ids:
value = {}
if team_id:
value['section_id'] = team_id
if index < len(user_ids):
value['user_id'] = user_ids[index]
index += 1
if value:
self.write(cr, uid, [lead_id], value, context=context)
return True
def schedule_phonecall(self, cr, uid, ids, schedule_time, call_summary, desc, phone, contact_name, user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
"""
action :('schedule','Schedule a call'), ('log','Log a call')
"""
phonecall = self.pool.get('crm.phonecall')
model_data = self.pool.get('ir.model.data')
phonecall_dict = {}
if not categ_id:
res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
if res_id:
categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
for lead in self.browse(cr, uid, ids, context=context):
if not section_id:
section_id = lead.section_id and lead.section_id.id or False
if not user_id:
user_id = lead.user_id and lead.user_id.id or False
vals = {
'name' : call_summary,
'opportunity_id' : lead.id,
'user_id' : user_id or False,
'categ_id' : categ_id or False,
'description' : desc or '',
'date' : schedule_time,
'section_id' : section_id or False,
'partner_id': lead.partner_id and lead.partner_id.id or False,
'partner_address_id': lead.partner_address_id and lead.partner_address_id.id or False,
'partner_phone' : phone or lead.phone or (lead.partner_address_id and lead.partner_address_id.phone or False),
'partner_mobile' : lead.partner_address_id and lead.partner_address_id.mobile or False,
'priority': lead.priority,
}
return value
new_id = phonecall.create(cr, uid, vals, context=context)
phonecall.case_open(cr, uid, [new_id])
if action == 'log':
phonecall.case_close(cr, uid, [new_id])
phonecall_dict[lead.id] = new_id
return phonecall_dict
def redirect_opportunity_view(self, cr, uid, opportunity_id, context=None):
models_data = self.pool.get('ir.model.data')
# Get Opportunity views
form_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
tree_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_oppor')
return {
'name': _('Opportunity'),
'view_type': 'form',
'view_mode': 'tree, form',
'res_model': 'crm.lead',
'domain': [('type', '=', 'opportunity')],
'res_id': int(opportunity_id),
'view_id': False,
'views': [(form_view and form_view[1] or False, 'form'),
(tree_view and tree_view[1] or False, 'tree'),
(False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window',
}
def message_new(self, cr, uid, msg, custom_values=None, context=None):
"""Automatically calls when new email message arrives"""
@ -447,17 +791,10 @@ class crm_lead(crm_case, osv.osv):
data_obj = self.pool.get('ir.model.data')
for opp in self.browse(cr, uid, ids, context=context):
# Get meeting views
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
res = data_obj.read(cr, uid, result, ['res_id'])
id1 = data_obj._get_id(cr, uid, 'crm', 'crm_case_calendar_view_meet')
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_meet')
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_meet')
if id1:
id1 = data_obj.browse(cr, uid, id1, context=context).res_id
if id2:
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
if id3:
id3 = data_obj.browse(cr, uid, id3, context=context).res_id
tree_view = data_obj.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_meet')
form_view = data_obj.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_meet')
calander_view = data_obj.get_object_reference(cr, uid, 'crm', 'crm_case_calendar_view_meet')
search_view = data_obj.get_object_reference(cr, uid, 'crm', 'view_crm_case_meetings_filter')
context.update({
'default_opportunity_id': opp.id,
'default_partner_id': opp.partner_id and opp.partner_id.id or False,
@ -474,9 +811,9 @@ class crm_lead(crm_case, osv.osv):
'view_mode': 'calendar,form,tree',
'res_model': 'crm.meeting',
'view_id': False,
'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
'views': [(calander_view and calander_view[1] or False, 'calendar'), (form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree')],
'type': 'ir.actions.act_window',
'search_view_id': res['res_id'],
'search_view_id': search_view and search_view[1] or False,
'nodestroy': True
}
return value

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<data>
<!-- Demo Leads -->
<record id="crm_case_itisatelesalescampaign0" model="crm.lead">
<field name="type_id" ref="crm.type_lead1"/>
@ -9,8 +9,8 @@
<field name="user_id" ref="base.user_root"/>
<field eval="'The Oil Company'" name="partner_name"/>
<field eval="'draft'" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="'Luc Latour'" name="contact_name"/>
<field name="section_id" ref="crm.section_sales_marketing_department"/>
<field eval="'Luc Latour'" name="contact_name"/>
<field name="title" ref="base.res_partner_title_sir"/>
<field eval="'Training Manager'" name="function"/>
<field eval="'Paris'" name="city"/>
@ -92,7 +92,7 @@
<field eval="'Bruxelles'" name="city"/>
<field name="country_id" ref="base.be"/>
<field eval="'draft'" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field name="section_id" ref="crm.section_sales_marketing_department"/>
<field eval="'(333) 715-1450'" name="mobile"/>
<field eval="1" name="active"/>
<field name="categ_id" ref="crm.categ_oppor1"/>

View File

@ -60,16 +60,23 @@
<record model="ir.actions.act_window" id="crm_case_category_act_oppor11">
<field name="name">Opportunities</field>
<field name="res_model">crm.lead</field>
<field name="view_mode">tree,form,graph,calendar,kanban</field>
<field name="view_mode">kanban,tree,form,graph,calendar</field>
<field name="domain">[('type','=','opportunity')]</field>
<field name="context">{'search_default_user_id':uid,'search_default_new':1, 'search_default_open':1, 'search_default_section_id':section_id, 'stage_type': 'opportunity', 'default_type': 'opportunity'}</field>
<field name="view_id" ref="crm_case_tree_view_oppor"/>
<field name="view_id" eval="False"/>
<field name="search_view_id" ref="crm.view_crm_case_opportunities_filter"/>
<field name="help">With opportunities you can manage and keep track of your sales pipeline by creating specific customer- or prospect-related sales documents to follow up potential sales. Information such as expected revenue, opportunity stage, expected closing date, communication history and much more can be stored. Opportunities can be connected to the email gateway: new emails may create opportunities, each of them automatically gets the history of the conversation with the customer.
You and your team(s) will be able to plan meetings and phone calls from opportunities, convert them into quotations, manage related documents, track all customer related activities, and much more.</field>
</record>
<record model="ir.actions.act_window.view" id="action_crm_tag_kanban_view_oppor11">
<field name="sequence" eval="0"/>
<field name="view_mode">kanban</field>
<field name="view_id" ref="crm_case_kanban_view_leads"/>
<field name="act_window_id" ref="crm_case_category_act_oppor11"/>
</record>
<record model="ir.actions.act_window.view" id="action_crm_tag_tree_view_oppor11">
<field name="sequence" eval="1"/>
<field name="view_mode">tree</field>

View File

@ -59,10 +59,11 @@
widget="selection"
domain="[('object_id.model','=','crm.lead')]"/>
<button
name="convert_opportunity"
name="%(crm.action_crm_lead2opportunity_partner)d"
string="Convert to Opportunity"
help="Convert to Opportunity" icon="gtk-go-forward"
type="object"/>
type="action"
/>
<newline />
<field name="user_id" />
<field name="section_id" widget="selection" />
@ -142,6 +143,29 @@
type="object" icon="gtk-convert" />
</group>
</page>
<page string="Communication &amp; History" groups="base.group_extended">
<group colspan="4">
<field colspan="4" name="email_cc" widget="char" size="512"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="tree" readonly="1">
<tree string="History">
<field name="display_text" string="History Information"/>
<field name="email_from" invisible="1"/>
<button
string="Reply" attrs="{'invisible': [('email_from', '=', False)]}"
name="%(mail.action_email_compose_message_wizard)d"
context="{'mail.compose.message.mode':'reply', 'message_id':active_id}"
icon="terp-mail-replied" type="action" />
</tree>
</field>
<button string="Add Internal Note"
name="%(crm.action_crm_add_note)d"
context="{'model': 'crm.lead' }"
icon="terp-document-new" type="action" />
<button string="Send New Email"
name="%(mail.action_email_compose_message_wizard)d"
icon="terp-mail-message-new" type="action"/>
</page>
<page string="Extra Info" groups="base.group_extended">
<group colspan="2" col="2">
<separator string="Categorization" colspan="2" col="2"/>
@ -170,58 +194,6 @@
<field name="day_close"/>
</group>
</page>
<page string="Communication &amp; History" groups="base.group_extended">
<group colspan="4">
<field colspan="4" name="email_cc" widget="char" size="512"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="tree,form" readonly="1">
<tree string="History">
<field name="display_text" string="History Information"/>
<field name="email_from" invisible="1"/>
<button
string="Reply" attrs="{'invisible': [('email_from', '=', False)]}"
name="%(mail.action_email_compose_message_wizard)d"
context="{'mail.compose.message.mode':'reply', 'message_id':active_id}"
icon="terp-mail-replied" type="action" />
</tree>
<form string="History">
<group col="4" colspan="4">
<group col="2" colspan="2" attrs="{'invisible': [('email_from', '=', False)]}">
<field name="email_from"/>
<field name="email_to" size="512"/>
</group>
<group col="2" colspan="2">
<field name="date"/>
<field name="email_cc" size="512" attrs="{'invisible': [('email_from', '=', False)]}"/>
</group>
<field name="subject" colspan="4" widget="char" attrs="{'invisible': [('email_from', '=', False)]}" size="512"/>
<field name="display_text" colspan="4" attrs="{'invisible': [('email_from', '!=', False)]}"/>
</group>
<notebook colspan="4">
<page string="Details" attrs="{'invisible': [('email_from', '=', False)]}">
<field name="body_text" colspan="4" nolabel="1"/>
<group attrs="{'invisible': [('email_from', '=', False)]}">
<button colspan="4" string="Reply"
name="%(mail.action_email_compose_message_wizard)d"
context="{'mail.compose.message.mode':'reply'}"
icon="terp-mail-replied" type="action"/>
</group>
</page>
<page string="Attachments" attrs="{'invisible': [('email_from', '=', False)]}">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
</form>
</field>
<button string="Add Internal Note"
name="%(crm.action_crm_add_note)d"
context="{'model': 'crm.lead' }"
icon="terp-document-new" type="action" />
<button string="Send New Email"
name="%(mail.action_email_compose_message_wizard)d"
icon="terp-mail-message-new" type="action"/>
</page>
</notebook>
</form>
</field>
@ -325,7 +297,7 @@
<a t-if="record.priority.raw_value == 1" icon="star-on" type="object" name="set_normal_priority"/>
<a t-if="record.priority.raw_value != 1" icon="star-off" type="object" name="set_high_priority" style="opacity:0.6; filter:alpha(opacity=60);"/>
</td>
<td align="left" valign="middle" class="oe_kanban_title3" tooltip="lead_details">
<td align="left" valign="middle" class="oe_kanban_title" tooltip="lead_details">
<field name="partner_id"/>
<t t-if="record.planned_revenue.raw_value">
- <t t-esc="Math.round(record.planned_revenue.value)"/>
@ -459,7 +431,7 @@
<field name="name">Opportunities</field>
<field name="model">crm.lead</field>
<field name="type">form</field>
<field name="priority">10</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<form string="Opportunities">
<group colspan="4" col="7">
@ -577,7 +549,7 @@
<group colspan="4">
<field colspan="4" name="email_cc" widget="char" size="512"/>
</group>
<field name="message_ids" colspan="4" nolabel="1" mode="tree,form" readonly="1">
<field name="message_ids" colspan="4" nolabel="1" mode="tree" readonly="1">
<tree string="History">
<field name="display_text" string="History Information"/>
<field name="email_from" invisible="1"/>
@ -587,34 +559,6 @@
context="{'mail.compose.message.mode':'reply', 'message_id':active_id}"
icon="terp-mail-replied" type="action" />
</tree>
<form string="History">
<group col="4" colspan="4">
<group col="2" colspan="2" attrs="{'invisible': [('email_from', '=', False)]}">
<field name="email_from"/>
<field name="email_to" size="512"/>
</group>
<group col="2" colspan="2">
<field name="date"/>
<field name="email_cc" size="512" attrs="{'invisible': [('email_from', '=', False)]}"/>
</group>
<field name="subject" colspan="4" widget="char" attrs="{'invisible': [('email_from', '=', False)]}" size="512"/>
<field name="display_text" colspan="4" attrs="{'invisible': [('email_from', '!=', False)]}"/>
</group>
<notebook colspan="4">
<page string="Details" attrs="{'invisible': [('email_from', '=', False)]}">
<field name="body_text" colspan="4" nolabel="1"/>
<group attrs="{'invisible': [('email_from', '=', False)]}">
<button colspan="4" string="Reply"
name="%(mail.action_email_compose_message_wizard)d"
context="{'mail.compose.message.mode':'reply'}"
icon="terp-mail-replied" type="action"/>
</group>
</page>
<page string="Attachments" attrs="{'invisible': [('email_from', '=', False)]}">
<field name="attachment_ids" colspan="4" readonly="1" nolabel="1"/>
</page>
</notebook>
</form>
</field>
<button string="Add Internal Note"
name="%(crm.action_crm_add_note)d"
@ -705,6 +649,7 @@
domain="[('state','=','pending')]"/>
<separator orientation="vertical"/>
<field name="name" string="Opportunity / Customer" filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
<field name="partner_id" string="Customer / Email" filter_domain="['|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]"/>
<field name="user_id">
<filter icon="terp-personal-"
domain="[('user_id','=', False)]"

View File

@ -102,11 +102,6 @@ class crm_phonecall(crm_base, osv.osv):
def case_close(self, cr, uid, ids, *args):
"""Overrides close for crm_case for setting close date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of case Ids
@param *args: Tuple Value for additional Params
"""
res = True
for phone in self.browse(cr, uid, ids):
@ -121,11 +116,6 @@ class crm_phonecall(crm_base, osv.osv):
def case_reset(self, cr, uid, ids, *args):
"""Resets case as Todo
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of case Ids
@param *args: Tuple Value for additional Params
"""
res = super(crm_phonecall, self).case_reset(cr, uid, ids, args, 'crm.phonecall')
self.write(cr, uid, ids, {'duration': 0.0})
@ -134,25 +124,147 @@ class crm_phonecall(crm_base, osv.osv):
def case_open(self, cr, uid, ids, *args):
"""Overrides cancel for crm_case for setting Open Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of case's Ids
@param *args: Give Tuple Value
"""
res = super(crm_phonecall, self).case_open(cr, uid, ids, *args)
self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
return res
def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
"""
action :('schedule','Schedule a call'), ('log','Log a call')
"""
model_data = self.pool.get('ir.model.data')
phonecall_dict = {}
if not categ_id:
res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
if res_id:
categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
for call in self.browse(cr, uid, ids, context=context):
if not section_id:
section_id = call.section_id and call.section_id.id or False
if not user_id:
user_id = call.user_id and call.user_id.id or False
vals = {
'name' : call_summary,
'user_id' : user_id or False,
'categ_id' : categ_id or False,
'description' : call.description or False,
'date' : schedule_time,
'section_id' : section_id or False,
'partner_id': call.partner_id and call.partner_id.id or False,
'partner_address_id': call.partner_address_id and call.partner_address_id.id or False,
'partner_phone' : call.partner_phone,
'partner_mobile' : call.partner_mobile,
'priority': call.priority,
}
new_id = self.create(cr, uid, vals, context=context)
self.case_open(cr, uid, [new_id])
if action == 'log':
self.case_close(cr, uid, [new_id])
phonecall_dict[call.id] = new_id
return phonecall_dict
def _call_create_partner(self, cr, uid, phonecall, context=None):
partner = self.pool.get('res.partner')
partner_id = partner.create(cr, uid, {
'name': phonecall.name,
'user_id': phonecall.user_id.id,
'comment': phonecall.description,
'address': []
})
return partner_id
def _call_set_partner(self, cr, uid, ids, partner_id, context=None):
return self.write(cr, uid, ids, {'partner_id' : partner_id}, context=context)
def _call_create_partner_address(self, cr, uid, phonecall, partner_id, context=None):
address = self.pool.get('res.partner.address')
return address.create(cr, uid, {
'partner_id': partner_id,
'name': phonecall.name,
'phone': phonecall.partner_phone,
})
def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
"""
This function convert partner based on action.
if action is 'create', create new partner with contact and assign lead to new partner_id.
otherwise assign lead to specified partner_id
"""
if context is None:
context = {}
partner_ids = {}
for call in self.browse(cr, uid, ids, context=context):
if action == 'create':
if not partner_id:
partner_id = self._call_create_partner(cr, uid, call, context=context)
self._call_create_partner_address(cr, uid, call, partner_id, context=context)
self._call_set_partner(cr, uid, [call.id], partner_id, context=context)
partner_ids[call.id] = partner_id
return partner_ids
def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
model_data = self.pool.get('ir.model.data')
# Select the view
tree_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_tree_view')
form_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_form_view')
search_view = model_data.get_object_reference(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
value = {
'name': _('Phone Call'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'crm.phonecall',
'res_id' : int(phonecall_id),
'views': [(form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree'), (False, 'calendar')],
'type': 'ir.actions.act_window',
'search_view_id': search_view and search_view[1] or False,
}
return value
def convert_opportunity(self, cr, uid, ids, opportunity_summary=False, partner_id=False, planned_revenue=0.0, probability=0.0, context=None):
partner = self.pool.get('res.partner')
address = self.pool.get('res.partner.address')
opportunity = self.pool.get('crm.lead')
opportunity_dict = {}
default_contact = False
for call in self.browse(cr, uid, ids, context=context):
if not partner_id:
partner_id = call.partner_id and call.partner_id.id or False
if partner_id:
address_id = partner.address_get(cr, uid, [partner_id])['default']
if address_id:
default_contact = address.browse(cr, uid, address_id, context=context)
opportunity_id = opportunity.create(cr, uid, {
'name': opportunity_summary or call.name,
'planned_revenue': planned_revenue,
'probability': probability,
'partner_id': partner_id or False,
'partner_address_id': default_contact and default_contact.id,
'phone': default_contact and default_contact.phone,
'mobile': default_contact and default_contact.mobile,
'section_id': call.section_id and call.section_id.id or False,
'description': call.description or False,
'priority': call.priority,
'type': 'opportunity',
'phone': call.partner_phone or False,
})
vals = {
'partner_id': partner_id,
'opportunity_id' : opportunity_id,
}
self.write(cr, uid, [call.id], vals)
self.case_close(cr, uid, [call.id])
opportunity.case_open(cr, uid, [opportunity_id])
opportunity_dict[call.id] = opportunity_id
return opportunity_dict
def action_make_meeting(self, cr, uid, ids, context=None):
"""
This opens Meeting's calendar view to schedule meeting on current Phonecall
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of Phonecall to Meeting IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for created Meeting view
"""
value = {}

View File

@ -83,9 +83,6 @@
<field eval="2.08" name="duration"/>
</record>
<record id="crm_case_phone06" model="crm.phonecall">
<field name="partner_address_id" ref="base.res_partner_address_1"/>
<field eval="1" name="active"/>
<field name="partner_id" ref="base.res_partner_9"/>
<field eval="&quot;3&quot;" name="priority"/>
<field name="user_id" ref="base.user_root"/>
<field eval="&quot;Bad time&quot;" name="name"/>

View File

@ -33,6 +33,44 @@ class res_partner(osv.osv):
'phonecall_ids': fields.one2many('crm.phonecall', 'partner_id',\
'Phonecalls'),
}
def redirect_partner_form(self, cr, uid, partner_id, context=None):
search_view = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'view_res_partner_filter')
value = {
'domain': "[]",
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'res.partner',
'res_id': int(partner_id),
'view_id': False,
'context': context,
'type': 'ir.actions.act_window',
'search_view_id': search_view and search_view[1] or False
}
return value
def make_opportunity(self, cr, uid, ids, opportunity_summary, planned_revenue=0.0, probability=0.0, partner_id=None, context=None):
categ = self.pool.get('crm.case.categ')
address = self.address_get(cr, uid, ids)
categ_ids = categ.search(cr, uid, [('object_id.model','=','crm.lead')])
lead = self.pool.get('crm.lead')
opportunity_ids = {}
for partner in self.browse(cr, uid, ids, context=context):
address = self.address_get(cr, uid, [partner.id])['default']
if not partner_id:
partner_id = partner.id
opportunity_id = lead.create(cr, uid, {
'name' : opportunity_summary,
'planned_revenue' : planned_revenue,
'probability' : probability,
'partner_id' : partner_id,
'partner_address_id' : address,
'categ_id' : categ_ids and categ_ids[0] or '',
'state' :'draft',
'type': 'opportunity'
})
opportunity_ids[partner_id] = opportunity_id
return opportunity_ids
res_partner()

View File

@ -0,0 +1,30 @@
Return-Path: <info@customer.com>
X-Original-To: info@customer.com
Delivered-To: sales@my.com
Received: by mail.my.com (Postfix, from userid xxx)
id 822ECBFB67; Mon, 24 Oct 2011 07:36:51 +0200 (CEST)
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.my.com
X-Spam-Level:
X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED autolearn=ham
version=3.3.1
Received: from [192.168.1.146]
(Authenticated sender: info@mail.customer.com)
by mail.customer.com (Postfix) with ESMTPSA id 07A30BFAB4
for <sales@my.com>; Mon, 24 Oct 2011 07:36:50 +0200 (CEST)
Message-ID: <4EA4F95D.904@customer.com>
Date: Mon, 24 Oct 2011 11:06:29 +0530
From: Mr. John Right <info@customer.com>
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Lightning/1.0b2 Thunderbird/3.1.8
MIME-Version: 1.0
To: sales@my.com
Subject: Fournir votre devis avec le meilleur prix.
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit
Bonjour l'équipe de vente,
Je veux acheter vos produits et services.
S'il vous plaît fournir votre cotation avec le meilleur prix.
Merci

View File

@ -0,0 +1,53 @@
-
I cancel unqualified lead.
-
!python {model: crm.lead}: |
self.case_cancel(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
-
I check cancelled lead.
-
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in cancel state}:
- state == "cancel"
-
I reset cancelled lead into unqualified lead.
-
!python {model: crm.lead}: |
self.case_reset(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
-
I check unqualified lead after reset.
-
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in draft state}:
- state == "draft"
-
I put unqualified lead into pending.
-
!python {model: crm.lead}: |
self.case_pending(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
-
I check status of pending lead.
-
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in pending state}:
- state == "pending"
-
I Escalate the Lead to Parent Team.
-
!python {model: crm.lead}: |
self.case_escalate(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
-
I check lead escalate to Parent Team.
-
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Escalate lead to parent team}:
- section_id.name == "Sales Department"
-
I mark as lost the opportunity.
-
!python {model: crm.lead}: |
self.case_mark_lost(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
-
I check opportunity after lost.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref('crm_case_itisatelesalescampaign0'))
assert lead.state == 'done', "lead is not done state"
assert lead.stage_id.id == ref('crm.stage_lead6'), 'Stage is not changed!'
assert lead.probability == 0.0, 'Probability is wrong!'

View File

@ -0,0 +1,56 @@
-
Customer interested in our product. so He send request by email to get more details.
-
Mail script will be fetched him request from mail server. so I process that mail after read EML file
-
!python {model: mail.thread}: |
import addons
request_file = open(addons.get_module_resource('crm','test', 'customer_request.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.lead', request_message)
-
After getting the mail, I check details of new lead of that customer.
-
!python {model: crm.lead}: |
lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
assert lead_ids and len(lead_ids), "Lead is not created after getting request"
lead = self.browse(cr, uid, lead_ids[0], context=context)
assert not lead.partner_id, "Customer should be a new"
assert lead.name == "Fournir votre devis avec le meilleur prix.", "Subject does not match"
-
I reply him request with welcome message.
-
!python {model: mail.compose.message}: |
lead_ids = self.pool.get('crm.lead').search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
context.update({'active_model': 'crm.lead','active_id': lead_ids[0]})
id = self.create(cr, uid, {'body_text': "Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci", 'email_from': 'sales@mycompany.com'}, context=context)
try:
self.send_mail(cr, uid, [id], context=context)
except:
pass
-
Now, I convert him into customer and put into regular customer list.
-
!python {model: crm.lead}: |
lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
self.convert_partner(cr, uid, lead_ids, context=context)
-
Now, I search customer in regular customer list.
-
!python {model: crm.lead}: |
partner_ids = self.message_partner_by_email(cr, uid, 'Mr. John Right <info@customer.com>')
assert partner_ids.get('partner_id'), "Customer is not found in regular customer list."
-
I convert one phonecall request as a customer and put into regular customer list.
-
!python {model: crm.phonecall}: |
self.convert_partner(cr, uid, [ref('crm.crm_case_phone06')], context=context)
-
I check converted phonecall to partner.
-
!python {model: res.partner}: |
partner_id = self.search(cr, uid, [('phonecall_ids', '=', ref('crm.crm_case_phone06'))])
assert partner_id, "Customer is not found in regular customer list."
data = self.browse(cr, uid, partner_id, context=context)[0]
assert data.user_id.id == ref("base.user_root"), "User not assign properly"
assert data.name == "Bad time", "User not assign properly"

View File

@ -0,0 +1,90 @@
-
In order to test convert customer lead into opportunity,
-
I open customer lead.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref("crm_case_qrecorp0")])
-
I check lead state is "Open".
-
!assert {model: crm.lead, id: crm.crm_case_qrecorp0, string: Lead in open state}:
- state == "open"
-
I convert lead into opportunity for exiting customer.
-
!python {model: crm.lead}: |
self.convert_opportunity(cr, uid ,[ref("crm_case_qrecorp0")], ref("base.res_partner_agrolait"))
-
I check details of converted opportunity.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref('crm_case_qrecorp0'))
assert lead.type == 'opportunity', 'Lead is not converted to opportunity!'
assert lead.partner_id.id == ref("base.res_partner_agrolait"), 'Partner missmatch!'
assert lead.stage_id.id == ref("stage_lead1"), 'Stage of opportunity is incorrect!'
-
Now I begin communication and schedule a phone call with the customer.
-
!python {model: crm.opportunity2phonecall}: |
import time
context.update({'active_model': 'crm.lead', 'active_ids': [ref('crm_case_qrecorp0')]})
call_id = self.create(cr, uid, {'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'name': "Bonjour M. Jean, Comment êtes-vous? J'ai obtenu votre demande. peut-on parler au sujet de ce pour quelques minutes?"}, context=context)
self.action_schedule(cr, uid, [call_id], context=context)
-
I check that phonecall is scheduled for that opportunity.
-
!python {model: crm.phonecall}: |
ids = self.search(cr, uid, [('opportunity_id', '=', ref('crm_case_qrecorp0'))])
assert len(ids), 'phonecall is not scheduled'
-
Now I schedule Meeting with Customer.
-
!python {model: crm.lead}: |
self.action_makeMeeting(cr, uid, [ref('crm_case_qrecorp0')])
-
After communicated with customer, I put some notes with Contract details.
-
!python {model: crm.add.note}: |
context.update({'active_model': 'crm.lead', 'active_id': ref('crm_case_qrecorp0')})
note_id = self.create(cr, uid, {'body': "ces détails envoyés par le client sur le FAX pour la qualité"})
self.action_add(cr, uid, [note_id], context=context)
-
Finally, I won this opportunity, so I close this opportunity.
-
!python {model: crm.lead}: |
self.case_mark_won(cr, uid, [ref("crm_case_qrecorp0")])
-
I check details of the opportunity After won the opportunity.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref('crm_case_qrecorp0'))
assert lead.state == 'done', 'Opportunity is not in done state!'
assert lead.stage_id.name == 'Won', ' Stage of Opportunity is not win!'
assert lead.probability == 100.0, 'probability revenue should not be 100.0!'
-
I convert mass lead into opportunity customer.
-
!python {model: crm.lead2opportunity.partner.mass}: |
context.update({'active_model': 'crm.lead', 'active_ids': [ref("crm_case_employee0"), ref("crm_case_electonicgoodsdealer0")], 'active_id': ref("crm_case_qrecorp0")})
id = self.create(cr, uid, {'user_ids': [ref('base.user_root')], 'section_id': ref('crm.section_sales_department')}, context=context)
self.mass_convert(cr, uid, [id], context=context)
-
Now I check First lead converted on opportunity.
-
!python {model: crm.lead}: |
opp = self.browse(cr, uid, ref('crm_case_employee0'))
assert opp.name == "Need Info about Onsite Intervention", "Opportunity name not correct"
assert opp.type == 'opportunity', 'Lead is not converted to opportunity!'
assert opp.partner_id.name == "Agrolait", 'Partner missmatch!'
assert opp.stage_id.id == ref("stage_lead1"), 'Stage of probability is incorrect!'
-
Then check for Second lead converted on opportunity.
-
!python {model: crm.lead}: |
opp = self.browse(cr, uid, ref('crm_case_electonicgoodsdealer0'))
assert opp.name == "Interest in Your New Product", "Opportunity name not correct"
assert opp.type == 'opportunity', 'Lead is not converted to opportunity!'
assert opp.stage_id.id == ref("stage_lead1"), 'Stage of probability is incorrect!'

View File

@ -0,0 +1,51 @@
-
I make direct opportunity for Customer.
-
!python {model: crm.partner2opportunity}: |
context.update({'active_model': 'res.partner', 'active_ids': [ref("base.res_partner_9")]})
res_id = self.create(cr, uid, {'name': "enquête pour l'achat de services"}, context=context)
self.make_opportunity(cr, uid, [res_id], context=context)
-
I make another opportunity from phonecall for same customer.
-
!python {model: crm.phonecall2opportunity}: |
context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_case_phone06")]})
res_id = self.create(cr, uid, {'name': "Quoi de prix de votre autre service?", 'partner_id': ref("base.res_partner_9")}, context=context)
self.make_opportunity(cr, uid, [res_id], context=context)
-
Now I merge all opportunities of customer.
-
!python {model: crm.lead}: |
opportunity_ids = self.search(cr, uid, [('partner_id','=', ref("base.res_partner_9"))])
self.merge_opportunity(cr, uid, opportunity_ids, context=context)
-
I check for merged opportunities for customer.
-
!python {model: crm.lead}: |
merge_id = self.search(cr, uid, [('partner_id','=', ref("base.res_partner_9"))])
assert merge_id, 'Fail to create Merge opportunity'
merge_data = self.browse(cr, uid, merge_id)[0]
assert merge_data.type == 'opportunity', 'Merged opportunity type not change!'
assert merge_data.partner_id.id == ref("base.res_partner_9"), 'Partner missmatch!'
-
Now I schedule another phonecall to customer after merged.
-
!python {model: crm.phonecall2phonecall}: |
context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_case_phone06")]})
res_id = self.create(cr, uid, {'name': "vos chances sont fusionnés en un seul"}, context=context)
self.action_schedule(cr, uid, [res_id], context=context)
-
I schedule Meeting on this phonecall.
-
!python {model: crm.phonecall}: |
self.action_make_meeting(cr, uid, [ref("crm.crm_case_phone06")])
-
I setting Phone call to Held (Done).
-
!python {model: crm.phonecall}: |
self.case_close(cr, uid, [ref("crm.crm_case_phone06")])
-
I check that the phone call is in 'Held' state.
-
!assert {model: crm.phonecall, id: crm.crm_case_phone06, string: Phone call Helded}:
- state == "done"

View File

@ -0,0 +1,16 @@
-
In order to test segmentation process which create specific partner categories criteria,
-
I start the process.
-
!python {model: crm.segmentation}: |
self.process_start(cr, uid, [ref("crm_segmentation0")],context)
#Todo: Need to check after segmentation started
-
I create rule Segmentation line record for partner .
-
!python {model: crm.segmentation.line}: |
id = self.create(cr, uid, {'name': "OpenERP partners",'expr_value': 25})
self.test(cr, uid, [id],partner_id=0)
#Todo: Need to test segmantation line record

View File

@ -1,154 +0,0 @@
-
In order to test the CRM in OpenERP, I will do a customer qualification
process that starts with a fist contact with a customer (a lead), which will
be converted to a business opportunity and a partner.
-
I create a two new users "user_crm" and I assign the group "salesman".
-
!record {model: res.users, id: res_users_usercrm0}:
company_id: base.main_company
context_lang: en_US
context_section_id: crm.section_sales_department
groups_id:
- base.group_sale_salesman
login: user_crm
name: user_crm
password: user_crm
- |
I start by creating a new lead "New Customer" and I provide an address to this
new customer, as well as an email "info@mycustomer.com".
-
!record {model: crm.lead, id: crm_lead_newcustomer0}:
email_from: info@mycustomer.com
name: New Customer
partner_name: Capegemini
partner_id: base.res_partner_9
phone: (855) 924-4364
mobile: (333) 715-1450
section_id: crm.section_sales_department
referred: False
- |
I check that the lead is in 'draft' state.
-
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in Draft}:
- state == "draft"
-
I open lead by click on "Open" button.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref("crm_lead_newcustomer0")])
fields={
'day_open': 0.0,
'day_close': 0.0
}
self._compute_day(cr, uid, [ref("crm_lead_newcustomer0")], fields, context)
- |
I check that lead is now in 'open' state.
-
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in open state}:
- state == "open"
-
I search id for case object.
-
!python {model: crm.case.categ}: |
self._find_object_id(cr, uid, context)
- |
As the lead seems to be a real business opportunity, I will convert it to a
partner
and a business opportunity by clicking on the "Convert" button.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref('crm_lead_newcustomer0'))
action = self.convert_opportunity(cr, uid, [ref("crm_lead_newcustomer0")], {'active_ids': [ref("crm_lead_newcustomer0")]})
assert action['res_model'] == 'crm.lead2opportunity.partner'
-
|
I select "create a new partner" option.
-
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner_create_0}:
action: 'create'
name: 'convert'
-
Then, Click on "Create Opportunity" button.
-
!python {model: crm.lead2opportunity.partner}: |
self.action_apply(cr, uid, [ref("crm_lead2opportunity_partner_create_0")], {'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
-
|
I select "Link to an existing partner" option.
-
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner_create_1}:
action: 'exist'
-
Then, Click on "Create Opportunity" button.
-
!python {model: crm.lead2opportunity.partner}: |
self.action_apply(cr, uid, [ref("crm_lead2opportunity_partner_create_1")], {'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
-
|
I select "Do not link to a partner" option.
-
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner_create_2}:
action: 'nothing'
-
Then, Click on "Create Opportunity" button.
-
!python {model: crm.lead2opportunity.partner}: |
self.action_apply(cr, uid, [ref("crm_lead2opportunity_partner_create_2")], {'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
- |
In order to check the opportunity is created or not, I check type.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref("crm_lead_newcustomer0"))
assert lead.type == 'opportunity'
-
I create mass report of lead to opprtunity partner.
-
!record {model: crm.lead2opportunity.partner.mass, id: crm_lead2opportunity_partner_mass0}:
user_ids:
- base.user_root
section_id: crm.section_sales_department
-
Then, execute that mass wizard.
-
!python {model: crm.lead2opportunity.partner.mass}: |
self.mass_convert(cr, uid, [ref("crm_lead2opportunity_partner_mass0")],{'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
-
I close lead by click on "close" button.
-
!python {model: crm.lead}: |
self.case_close(cr, uid, [ref("crm_lead_newcustomer0")])
- |
I check that lead is now in 'done' state.
-
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in done state}:
- state == "done"
-
I cancel lead by click on "cancel" button.
-
!python {model: crm.lead}: |
self.case_cancel(cr, uid, [ref("crm_lead_newcustomer0")])
- |
I check that lead is now in 'cancel' state.
-
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in cancel state}:
- state == "cancel"
#-
# |
# yaml is also not working with smtp server and send new email.
- |
I configure with smtp server.
- |
And I communicate with lead through send New mail to Lead using its email address from the user who is logged in.
- |
I check that communication history generated when send email to lead.
- |
Then, I add a cc which receive copy of future communication between partner and users by mail.
- |
I Reply to last Email to lead with some document attached.and check that communication history generated or not.

View File

@ -1,151 +0,0 @@
-
In order to do complete test the CRM in OpenERP,
I will create new full configured record and carry test on it.
- |
I Start by creating "Test Sales Team" with No Unlink.
I create a crm.case.section record.
-
!record {model: crm.case.section, id: crm_case_section_demosalesteam}:
code: DEMO
complete_name: Test Sales Team
name: Test Sales Team
allow_unlink: False
member_ids:
- base.user_admin
stage_ids:
- crm.stage_lead1
- crm.stage_lead2
- crm.stage_lead3
- crm.stage_lead4
- crm.stage_lead5
- crm.stage_lead6
working_hours: 0.0
resource_calendar_id: resource.timesheet_group1
parent_id: crm.section_sales_department
-
I assign segmentation.
-
!record {model: res.users, id: res_users_usercrm0}:
context_section_id: crm_case_section_demosalesteam
- |
I create a new lead "Test Customer" and I provide an address to this
demo customer and email "info@democustomer.com" and Also "Test Sales Team".
-
!record {model: crm.lead, id: crm_lead_democustomer}:
email_from: info@democustomer.com
name: Test Customer
partner_name: NotSoTinySARL
phone: (+32).81.81.37.00
mobile: (+32).81.81.37.00
section_id: crm_case_section_demosalesteam
referred: False
type: lead
-
I check that the lead is in 'draft' state.
-
!assert {model: crm.lead, id: crm_lead_democustomer, string: Lead in Draft}:
- state == "draft"
-
I create categories.
-
!record {model: crm.case.categ, id: crm_case_categ0}:
name: crm_case_section_demosalesteam
section_id: crm_case_section_demosalesteam
-
I assigning contact detail to the Lead "Test Customer" without address.
-
!python {model: crm.lead}: |
self.onchange_partner_address_id(cr, uid, ref("crm_lead_democustomer"), None, email=False)
-
I assigning contact detail to the Lead "Test Customer" with address.
-
!python {model: crm.lead}: |
self.onchange_partner_address_id(cr, uid, ref("crm_lead_democustomer"), ref("base.res_partner_address_notsotinysarl0"), email=False)
-
I selecting email "Opt-out" option for the "Test Customer" Lead.
-
!python {model: crm.lead}: |
self.on_change_optout(cr, uid, ref("crm_lead_democustomer"), True)
-
I change the Opt-out to Opt-in to show email receive preference.
-
!python {model: crm.lead}: |
self.on_change_optin(cr, uid, ref("crm_lead_democustomer"), True)
-
I open lead by click on "Open" button.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref("crm_lead_democustomer")])
-
I check that lead "Test Customer" is now in 'open' state.
-
!assert {model: crm.lead, id: crm_lead_democustomer, string: Lead in open state}:
- state == "open"
-
I reset the lead "Test Customer".
-
!python {model: crm.lead}: |
self.case_reset(cr, uid, [ref("crm_lead_democustomer")])
-
I again opening lead by click on "Open" button.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref("crm_lead_democustomer")])
-
I setting stage "New" for the lead "Test Customer".
-
!python {model: crm.lead}: |
self.stage_next(cr, uid, [ref("crm_lead_democustomer")], context={'stage_type': 'lead'})
-
I try to Unlink the Lead "Test Customer" demo Lead.
-
!python {model: crm.lead}: |
try:
self.unlink(cr, uid, [ref("crm_lead_democustomer")])
except:
pass
-
I setting Lead "Test Customer" to Pending State.
-
!python {model: crm.lead}: |
self.case_pending(cr, uid, [ref("crm_lead_democustomer")])
-
I check that lead "Test Customer" is now in 'Pending' state.
-
!assert {model: crm.lead, id: crm_lead_democustomer, string: Lead in Pending state}:
- state == "pending"
-
I Escalate the Lead "Test Customer" Parent "Sales Team".
-
!python {model: crm.lead}: |
self.case_escalate(cr, uid, [ref("crm_lead_democustomer")])
-
I add Internal Note Saying Escalated Reason.
-
!record {model: crm.add.note, id: crm_add_note_0}:
body: Sales Lead Has Been Escalated Due to Some Technical reason to the parent 'Sales
Team'
state: unchanged
-
I click a note button to attach the record.
-
!python {model: crm.add.note}: |
context['active_model'] = "crm.lead"
context['active_ids'] = [ref("crm_lead_democustomer")]
self.action_add(cr, uid, [ref("crm_add_note_0")], context=context)
-
I Copying this lead "Test Customer" to New Lead.
-
!python {model: crm.lead}: |
self.copy(cr, uid, ref("crm_lead_democustomer"))
-
I checking the Lead Copied or Not.
-
!python {model: crm.lead}: |
sid = self.search(cr, uid, [('name', '=', 'Test Customer'),('state', '=', 'draft')])
if not sid:
raise AssertionError("Lead is not copied Successfully")

View File

@ -1,97 +0,0 @@
- |
I will test Meetings which may be customer meeting or phonecall meeting or
internal Meeting.
- |
I start by creating a new Meeting.
-
!record {model: crm.meeting, id: crm_meeting_regardingpresentation0}:
categ_id: crm.categ_meet2
date: !eval time.strftime('%Y-%m-%d 16:04:00')
date_deadline: !eval "(datetime.now() + timedelta(1)).strftime('%Y-%m-%d 00:04:00')"
duration: 8.0
email_from: info@balmerinc.be
location: Ahmedabad
name: Regarding Presentation
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
rrule_type: weekly
section_id: crm.section_sales_department
- |
I check that the Meetings is in 'UnConfirmed' state.
-
!assert {model: crm.meeting, id: crm_meeting_regardingpresentation0}:
- state == "draft"
- |
I can set reminder on meeting if I put reminder "40 minutes before" .
- |
For that, I first create alarm.
-
!record {model: res.alarm, id: res_alarm_minituesbefore0}:
name: 40 minutes before
trigger_duration: 40
trigger_interval: minutes
trigger_occurs: before
trigger_related: start
- |
I will assign this reminder.
- !python {model: crm.meeting}: |
self.write(cr, uid, [ref('crm_meeting_regardingpresentation0')], {'alarm_id': ref("res_alarm_minituesbefore0")})
- |
In order to check recurrence on meetings I will set Recurrency to Custom
and I set the fields so that the meeting will occur weekly on Monday and Friday 10 times.
-
!python {model: crm.meeting}: |
self.write(cr, uid, [ref("crm_meeting_regardingpresentation0")], {'fr': 1, 'mo': 1, 'th': 1, 'tu': 1, 'we':1, 'count':10, 'interval': 1, 'rrule_type': 'weekly', 'recurrency' : True})
- |
I can see from the calendar view that the meeting is scheduled on Monday and Friday
for 10 times.
-
!python {model: crm.meeting}: |
self.fields_view_get(cr, uid, False, 'calendar', context)
- |
I will search for one of the recurrent event and count the number of meeting.
-
!python {model: crm.meeting}: |
import time
from datetime import datetime, date, timedelta
ids = self.search(cr, uid, [('date', '>=', time.strftime('%Y-%m-%d 00:00:00')), ('date', '<=', (datetime.now()+timedelta(31)).strftime('%Y-%m-%d 00:00:00')), ('name', '=', 'Regarding Presentation')], context={'virtual_id': True})
assert len(ids) == 10
- |
If I want to edit meetings information for all occurrence I click on "Edit All" button.
-
!python {model: crm.meeting}: |
self.write(cr, uid, [ref('crm_meeting_regardingpresentation0')], {'edit_all':'True'},context)
- |
I can see that new meeting form is opened with same value.
I change some data for meeting and save it.
I can see from meeting's calendar view that all meeting occurrences are changed accordingly.
-
!record {model: crm.meeting, id: crm.crm_meeting_regardingpresentation0}:
alarm_id: base_calendar.alarm9
rrule_type: weekly
- |
In order to invite people for this meetings, I click on "Invite People" button
I can invite internal user.
-
!record {model: base_calendar.invite.attendee, id: base_calendar_invite_attendee_0}:
type: internal
send_mail: False
partner_id: base.res_partner_9
user_ids:
- base.user_demo
-
I click on "Invite" button of "Invite attendee" wizard.
-
!python {model: base_calendar.invite.attendee}: |
self.do_invite(cr, uid, [ref('base_calendar_invite_attendee_0')], {'active_id': ref('crm_meeting_regardingpresentation0'), 'model' : 'crm.meeting', 'attendee_field':'attendee_ids'})
- |
After direct/indirect confirmation for meetings I can confirm meeting.
-
!python {model: crm.meeting}: |
self.case_open(cr, uid, [ref('crm_meeting_regardingpresentation0')])

View File

@ -1,113 +0,0 @@
- |
I start by creating a new Opportunity. And I select partner for opportunity.
I can see that after selecting partner his contact and email is automatically filled.
-
!record {model: crm.lead, id: crm_opportunity_abcfuelcounits0}:
email_from: info@balmerinc.be
name: 'ABC FUEL CO 829264 - 10002 units'
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
probability: 1.0
stage_id: crm.stage_lead1
categ_id: crm.categ_oppor2
section_id: crm.section_sales_department
- |
I check that the opportunity is in 'New' state.
-
!assert {model: crm.lead, id: crm_opportunity_abcfuelcounits0}:
- state == "draft"
- |
I check that phonecall record is created for that opportunity.
-
!python {model: crm.phonecall}: |
phone_obj = self.pool.get('crm.phonecall')
- |
I schedule Meeting on this current opportunity by clicking on "schedule
Meeting".
-
!python {model: crm.lead}: |
self.action_makeMeeting(cr, uid, [ref("crm_opportunity_abcfuelcounits0")])
- |
I can see that Meeting's calendar view is shown.
then I click on the date on which I want to schedule meeting.
I fill proper data for that meeting and save it.
-
!record {model: crm.meeting, id: crm_meeting_abcfuelcounits0}:
date: !eval time.strftime('%Y-%m-%d 00:00:00')
date_deadline: !eval time.strftime('%Y-%m-%d 08:00:00')
duration: 8.0
email_from: info@balmerinc.be
name: 'ABC FUEL CO 829264 - 10002 units'
opportunity_id: 'crm_opportunity_abcfuelcounits0'
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
section_id: crm.section_sales_department
state: open
- |
In order to schedule a phonecall to the partner
I click on "schedule call" button and select planned date for the call.
-
!record {model: crm.opportunity2phonecall, id: crm_opportunity2phonecall_abcfuelcounits0}:
date: !eval "(datetime.now() + timedelta(1)).strftime('%Y-%m-%d 11:15:00')"
name: 'ABC FUEL CO 829264 - 10002 units'
section_id: crm.section_sales_department
user_id: base.user_demo
categ_id: crm.categ_phone1
- |
schedule phonecall by opportunity2phoncall wizard.
-
!python {model: crm.opportunity2phonecall}: |
self.action_apply(cr, uid, [ref('crm_opportunity2phonecall_abcfuelcounits0')], {'active_ids': [ref("crm_opportunity_abcfuelcounits0")]})
- |
I check that phonecall record is created for that opportunity.
-
!python {model: crm.phonecall}: |
phone_obj = self.pool.get('crm.phonecall')
ids = phone_obj.search(cr, uid, [('name', '=', 'ABC FUEL CO 829264 - 10002 units')])
assert len(ids)
- |
I can see phonecall record after click on "Schedule call" wizard.
-
!record {model: crm.phonecall, id: crm_phonecall_abcfuelcounits0}:
date: !eval "(datetime.now() + timedelta(1)).strftime('%Y-%m-%d 11:15:00')"
duration: 3.0
name: 'ABC FUEL CO 829264 - 10002 units'
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
section_id: crm.section_sales_department
- |
I Merge the opportunities.
-
for that create two opportunities first opportunity 'Test FUEL CO'.
-
!record {model: crm.lead, id: crm_opportunity_1}:
email_from: info@balmerinc.be
name: 'Test FUEL CO 829264 - 10002 units'
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
probability: 1.0
stage_id: crm.stage_lead1
categ_id: crm.categ_oppor2
section_id: crm.section_sales_department
-
I create the opportunity 'FUEL CO'.
-
!record {model: crm.lead, id: crm_opportunity_2}:
email_from: info@balmerinc.be
name: 'FUEL CO 829264 - 10002 units'
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
probability: 1.0
stage_id: crm.stage_lead1
categ_id: crm.categ_oppor2
section_id: crm.section_sales_department
- |
I Merge two Opportunities.
-
!python {model: crm.merge.opportunity}: |
op_list = [ref('crm_opportunity_1'),ref('crm_opportunity_2')]
op_ids=self.pool.get('crm.lead').browse(cr,uid,op_list)
lead_ids = [ref('crm_lead_newcustomer0')]
self.merge(cr, uid, op_ids, {'lead_ids': lead_ids})

View File

@ -1,45 +0,0 @@
- |
I start by creating a new Opportunity. And I select partner for opportunity.
I can see that after selecting partner his contact and email is automatically filled.
-
!record {model: crm.lead, id: crm_opportunity_demotestopportunity}:
email_from: info@balmerinc.be
name: 'Demo Test Opportunity'
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
probability: 1.0
categ_id: crm.categ_oppor2
section_id: crm.section_sales_department
type: opportunity
-
I check that the opportunity is in 'New' state.
-
!assert {model: crm.lead, id: crm_opportunity_demotestopportunity, string: Opportunity in Draft}:
- state == "draft"
-
I open opportunity by click on "Open" button.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref("crm_opportunity_demotestopportunity")])
-
I change partner of the opportunity.
-
!python {model: crm.lead}: |
self.onchange_partner_id(cr, uid, [ref("crm_opportunity_demotestopportunity")], ref("base.res_partner_agrolait"))
-
I change Contact Detail of the opportunity.
-
!python {model: crm.lead}: |
self.onchange_partner_address_id(cr, uid,[ref("crm_opportunity_demotestopportunity")], ref("base.res_partner_address_8invoice"))
-
I change Opportunity to Won State.
-
!python {model: crm.lead}: |
self.case_mark_won(cr, uid, [ref("crm_opportunity_demotestopportunity")])
-
I check that the opportunity is in 'Done' state.
-
!assert {model: crm.lead, id: crm_opportunity_demotestopportunity, string: Opportunity is Won}:
- state == "done"

View File

@ -1,25 +0,0 @@
- |
I start by creating a new opportunity from partner.
-
!record {model: crm.partner2opportunity, id: crm_partner2opportunity_id_0}:
name: test
planned_revenue: 0.0
partner_id: base.res_partner_9
probability: 0.0
-
I click on "Create Opportunity" button of this wizard.
-
!python {model: crm.partner2opportunity}: |
fields = {
'name': 'test',
'planned_revenue': '0.0',
'partner_id': ref('base.res_partner_9'),
'probability': '0.0'
}
self.default_get(cr, uid, fields, {"active_ids": [ref("crm_partner2opportunity_id_0")]})
- |
In order to check the opportunity is created or not, I check type.
-
!python {model: crm.partner2opportunity}: |
opportunity = self.make_opportunity(cr, uid, [ref("crm_partner2opportunity_id_0")], {"active_ids": [ref("crm_partner2opportunity_id_0")]})
assert True

View File

@ -1,116 +0,0 @@
- |
I start by creating a new phonecall.
-
!record {model: crm.phonecall, id: crm_phonecall_interviewcall0}:
date: !eval time.strftime('%Y-%m-%d 08:00:00')
name: Interview call
duration: 2.0
section_id: crm.section_sales_department
-
I select partner by click on "Create a Partner" button.
-
!record {model: crm.phonecall2partner, id: crm_phonecall2partner_1}:
action: exist
partner_id: base.res_partner_9
-
I click on "Continue" button of this wizard and make partner.
-
!python {model: crm.phonecall2partner}: |
self._select_partner(cr, uid,{"active_ids": [ref("crm_phonecall_interviewcall0")]})
self.open_create_partner(cr, uid, [ref("crm_phonecall2partner_1")], {"active_ids": [ref("crm_phonecall_interviewcall0")]})
self.make_partner(cr, uid, [ref("crm_phonecall2partner_1")], {"active_ids": [ref("crm_phonecall_interviewcall0")]})
- |
As the success of phonecall seems to be a real business opportunity, I will convert
it to opportunity by clicking on the "Convert to Opportunity" button.
-
!record {model: crm.phonecall2opportunity, id: crm_phonecall2opportunity_interviewcall0}:
name: Interview call
partner_id: base.res_partner_9
planned_revenue: 0.0
probability: 0.0
- |
I can see that a business opportunity is now assigned to this phonecall
-
!assert {model: crm.phonecall, id: crm_phonecall_interviewcall0}:
- opportunity_id != False
-
I click on "Convert" button of this wizard.
-
!python {model: crm.phonecall2opportunity}: |
self.action_apply(cr, uid, [ref("crm_phonecall2opportunity_interviewcall0")], {"active_id": ref("crm_phonecall_interviewcall0")})
- |
And I check that the phonecall and the newly created business opportunity is linked
to same partner.
-
!python {model: crm.phonecall}: |
obj_phonecall = self.browse(cr, uid, ref('crm_phonecall_interviewcall0'))
ids = self.pool.get('crm.lead').search(cr, uid, [('name', '=', obj_phonecall.opportunity_id.name)])
obj_opp = self.pool.get('crm.lead').browse(cr, uid, ids)[0]
assert obj_phonecall.partner_id == obj_opp.partner_id
- |
I schedule Meeting on this current phonecall by clicking on "schedule
Meeting".
-
!python {model: crm.phonecall}: |
self.action_make_meeting(cr, uid, [ref('crm_phonecall_interviewcall0')])
- |
I can see that Meeting's calendar view is shown.
then I click on the date on which I want schedule meeting.
I fill proper data for that meeting and save it.
-
!record {model: crm.meeting, id: crm_meeting_interviewcall0}:
alarm_id: base_calendar.alarm3
date: !eval "'%s-%s-%s 09:00:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
date_deadline: !eval "'%s-%s-%s 17:00:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
duration: 8.0
email_from: info@balmerinc.be
name: Interview call
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
phonecall_id: 'crm_phonecall_interviewcall0'
state: open
- |
In order to schedule other phonecall to the partner
I click on "schedule other call" button. and plan for other call
I can see that it will open other phonecall view with some data same as current
phonecall.
-
!record {model: crm.phonecall2phonecall, id: crm_phonecall2phonecall_interviewcall0}:
date: !eval "'%s-%s-%s 19:49:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
name: Interview call
section_id: crm.section_sales_department
user_id: base.user_root
action: schedule
categ_id: crm.categ_phone1
-
I click on "schedule other call" button. and plan for other call.
-
!record {model: crm.phonecall2phonecall, id: crm_phonecall2phonecall_interviewcall1}:
date: !eval "'%s-%s-%s 19:49:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
name: Interview call
section_id: crm.section_sales_department
user_id: base.user_root
action: log
categ_id: crm.categ_phone1
- |
I click on "Schedule" button of this wizard.
-
!python {model: crm.phonecall2phonecall}: |
fields = {
'name': 'Interview call',
'section_id': ref('crm.section_sales_department'),
'user_id': ref('base.user_root'),
'categ_id': ref('crm.categ_phone1')
}
self.default_get(cr, uid, fields,{'active_id': ref('crm_phonecall_interviewcall0')})
self.action_apply(cr, uid, [ref('crm_phonecall2phonecall_interviewcall0')], {'active_id': ref('crm_phonecall_interviewcall0')})
- |
I click on "Schedule" button of this wizard with log option.
-
!python {model: crm.phonecall2phonecall}: |
self.action_apply(cr, uid, [ref('crm_phonecall2phonecall_interviewcall1')], {'active_id': ref('crm_phonecall_interviewcall0')})

Some files were not shown because too many files have changed in this diff Show More