[MERGE] merged with main trunk

bzr revid: qdp-launchpad@openerp.com-20111205150819-tuzcw6v25wp2aq9r
This commit is contained in:
Quentin (OpenERP) 2011-12-05 16:08:19 +01:00
commit bd724f43b4
213 changed files with 4635 additions and 4389 deletions

View File

@ -142,7 +142,6 @@ module named account_voucher.
'test/account_change_currency.yml',
'test/chart_of_account.yml',
'test/account_period_close.yml',
'test/account_fiscalyear_close_state.yml',
'test/account_use_model.yml',
'test/account_validate_account_move.yml',
'test/account_fiscalyear_close.yml',
@ -150,6 +149,7 @@ module named account_voucher.
'test/account_cash_statement.yml',
'test/test_edi_invoice.yml',
'test/account_report.yml',
'test/account_fiscalyear_close_state.yml', #last test, as it will definitively close the demo fiscalyear
],
'installable': True,
'active': False,

View File

@ -881,7 +881,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,

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'),

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,11 +8,10 @@
<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"/>
@ -57,11 +56,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 +83,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 +192,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>

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

@ -1,31 +1,8 @@
-
In order to check the Close a Fiscal Year wizard in OpenERP I first create a Fiscalyear
-
!record {model: account.fiscalyear, id: account_fiscalyear_fiscalyear0}:
code: !eval "'FY%s'% (datetime.now().year+1)"
company_id: base.main_company
date_start: !eval "'%s-01-01' %(datetime.now().year+1)"
date_stop: !eval "'%s-12-31' %(datetime.now().year+1)"
name: !eval "'Fiscal Year %s' %(datetime.now().year+1)"
-
I create monthly Periods for this fiscalyear
-
!python {model: account.fiscalyear}: |
self.create_period(cr, uid, [ref("account_fiscalyear_fiscalyear0")], {"lang":
'en_US', "active_model": "ir.ui.menu", "active_ids": [ref("account.menu_action_account_fiscalyear_form")],
"tz": False, "active_id": ref("account.menu_action_account_fiscalyear_form"),
})
-
I check that the fiscalyear state is "Draft"
-
!assert {model: account.fiscalyear, id: account_fiscalyear_fiscalyear0, string: Fiscal Year is in Draft state}:
- state == 'draft'
-
I run the Close a Fiscalyear wizard to close this fiscalyear
I run the Close a Fiscalyear wizard to close the demo fiscalyear
-
!record {model: account.fiscalyear.close.state, id: account_fiscalyear_close_state_0}:
fy_id: account_fiscalyear_fiscalyear0
fy_id: data_fiscalyear
-
I clicked on Close States Button to close fiscalyear
@ -37,9 +14,6 @@
-
I check that the fiscalyear state is now "Done"
-
!assert {model: account.fiscalyear, id: account_fiscalyear_fiscalyear0, string: Fiscal Year is in Done state}:
!assert {model: account.fiscalyear, id: data_fiscalyear, string: Fiscal Year is in Done state}:
- state == 'done'

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

@ -8,31 +8,31 @@ 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-07-12 12:04+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"PO-Revision-Date: 2011-11-29 08:00+0000\n"
"Last-Translator: Ferdinand @ Camptocamp <Unknown>\n"
"Language-Team: German <de@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-11-05 05:57+0000\n"
"X-Generator: Launchpad (build 14231)\n"
"X-Launchpad-Export-Date: 2011-11-30 05:27+0000\n"
"X-Generator: Launchpad (build 14404)\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 ""
msgstr "Anlage (Entwurf)"
#. module: account_asset
#: field:account.asset.property,method_end:0
#: field:account.asset.property.history,method_end:0
msgid "Ending date"
msgstr ""
msgstr "Ende Datum"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation board"
msgstr ""
msgstr "Abschreibungs-Tableau"
#. module: account_asset
#: view:account.asset.asset:0
@ -45,61 +45,61 @@ msgstr ""
#: 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 ""
msgstr "Anlagegüter"
#. module: account_asset
#: constraint:ir.actions.act_window:0
msgid "Invalid model name in the action definition."
msgstr ""
msgstr "Ungültiger Modellname in der Aktionsdefinition."
#. module: account_asset
#: selection:account.asset.property,method:0
msgid "Linear"
msgstr ""
msgstr "Linear"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Change duration"
msgstr ""
msgstr "Verändere Lebensdauer"
#. module: account_asset
#: field:account.asset.asset,child_ids:0
msgid "Child assets"
msgstr ""
msgstr "untergeordnete Anlagengüter"
#. module: account_asset
#: field:account.asset.board,value_asset:0
msgid "Asset Value"
msgstr ""
msgstr "Anlagenwert"
#. module: account_asset
#: wizard_field:account.asset.modify,init,name:0
msgid "Reason"
msgstr ""
msgstr "Begründung"
#. 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 ""
msgstr "Buchungen"
#. module: account_asset
#: wizard_view:account.asset.compute,asset_compute:0
msgid "Generated entries"
msgstr ""
msgstr "erzeugte Buchungen"
#. 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 ""
msgstr "Anzahl der Intervalle"
#. module: account_asset
#: wizard_button:account.asset.compute,asset_compute,asset_open:0
msgid "Open entries"
msgstr ""
msgstr "offene Buchungen"
#. module: account_asset
#: view:account.asset.asset:0
@ -108,102 +108,102 @@ msgstr ""
#: model:ir.ui.menu,name:account_asset.menu_finance_Assets
#: model:ir.ui.menu,name:account_asset.menu_finance_config_Assets
msgid "Assets"
msgstr ""
msgstr "Anlagegüter"
#. module: account_asset
#: selection:account.asset.property,method:0
msgid "Progressive"
msgstr ""
msgstr "Progressiv"
#. 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 ""
msgstr "Anlagegüter (Entwurf)"
#. 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 ""
msgstr "Bemerkungen"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Change history"
msgstr ""
msgstr "Bearbeitungshistorie"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation entries"
msgstr ""
msgstr "Abschreibungsbuchungen"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Methods"
msgstr ""
msgstr "Methoden"
#. module: account_asset
#: wizard_view:account.asset.modify,init:0
msgid "Asset properties to modify"
msgstr ""
msgstr "zu verändernde Anlagenmerkmale"
#. module: account_asset
#: field:account.asset.asset,partner_id:0
msgid "Partner"
msgstr ""
msgstr "Partner"
#. 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 ""
msgstr "Perioden pro Intervall"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation duration"
msgstr ""
msgstr "Abschreibungsdauer"
#. module: account_asset
#: field:account.asset.property,account_analytic_id:0
msgid "Analytic account"
msgstr ""
msgstr "Analytisches Konto"
#. module: account_asset
#: field:account.asset.property,state:0
msgid "State"
msgstr ""
msgstr "Status"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation methods"
msgstr ""
msgstr "Abschreibungsmethode"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Other information"
msgstr ""
msgstr "Andere Informationen"
#. module: account_asset
#: field:account.asset.board,value_asset_cumul:0
msgid "Cumul. value"
msgstr ""
msgstr "kummulierter Betrag"
#. module: account_asset
#: view:account.asset.property:0
msgid "Assets methods"
msgstr ""
msgstr "Anlagen Methoden"
#. module: account_asset
#: constraint:ir.ui.view:0
msgid "Invalid XML for View Architecture!"
msgstr ""
msgstr "Fehlerhafter XML-Code für diese Ansicht!"
#. module: account_asset
#: model:ir.model,name:account_asset.model_account_asset_property
msgid "Asset property"
msgstr ""
msgstr "Anlagenmerkmale"
#. module: account_asset
#: wizard_view:account.asset.compute,asset_compute:0
@ -212,30 +212,30 @@ msgstr ""
#: 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 ""
msgstr "Berechne Anlagen"
#. 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 ""
msgstr "Verändere Anlagegut"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Confirm asset"
msgstr ""
msgstr "Anlagegut bestätigen"
#. module: account_asset
#: view:account.asset.property.history:0
#: model:ir.model,name:account_asset.model_account_asset_property_history
msgid "Asset history"
msgstr ""
msgstr "Anlagenhistorie"
#. module: account_asset
#: field:account.asset.property,date:0
msgid "Date created"
msgstr ""
msgstr "Erstellungsdatum"
#. module: account_asset
#: model:ir.module.module,description:account_asset.module_meta_information
@ -252,211 +252,213 @@ msgstr ""
#: field:account.asset.board,value_gross:0
#: field:account.asset.property,value_total:0
msgid "Gross value"
msgstr ""
msgstr "Anschaffungswert"
#. module: account_asset
#: selection:account.asset.property,method_time:0
msgid "Ending period"
msgstr ""
msgstr "Periodenende"
#. module: account_asset
#: field:account.asset.board,name:0
msgid "Asset name"
msgstr ""
msgstr "Anlagenname"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Accounts information"
msgstr ""
msgstr "Konto Information"
#. 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 ""
msgstr "Notiz"
#. module: account_asset
#: selection:account.asset.asset,state:0
#: selection:account.asset.property,state:0
msgid "Draft"
msgstr ""
msgstr "Entwurf"
#. module: account_asset
#: field:account.asset.property,type:0
msgid "Depr. method type"
msgstr ""
msgstr "Abschreibungsmethode"
#. module: account_asset
#: field:account.asset.property,account_asset_id:0
msgid "Asset account"
msgstr ""
msgstr "Anlagenkonto"
#. module: account_asset
#: field:account.asset.property.history,asset_property_id:0
msgid "Method"
msgstr ""
msgstr "Methode"
#. module: account_asset
#: selection:account.asset.asset,state:0
msgid "Normal"
msgstr ""
msgstr "Normal"
#. module: account_asset
#: field:account.asset.property,method_progress_factor:0
msgid "Progressif factor"
msgstr ""
msgstr "Progressionsfaktor"
#. module: account_asset
#: field:account.asset.asset,localisation:0
msgid "Localisation"
msgstr ""
msgstr "Lokalisation"
#. module: account_asset
#: field:account.asset.property,method:0
msgid "Computation method"
msgstr ""
msgstr "Berechnungsmethode"
#. module: account_asset
#: field:account.asset.property,method_time:0
msgid "Time method"
msgstr ""
msgstr "Zeitmethode"
#. module: account_asset
#: field:account.asset.asset,active:0
msgid "Active"
msgstr ""
msgstr "Aktiv"
#. module: account_asset
#: field:account.asset.property.history,user_id:0
msgid "User"
msgstr ""
msgstr "Benutzer"
#. module: account_asset
#: field:account.asset.asset,property_ids:0
msgid "Asset method name"
msgstr ""
msgstr "Anlagenmethoden Bezeichnung"
#. module: account_asset
#: field:account.asset.asset,date:0
#: field:account.asset.property.history,date:0
msgid "Date"
msgstr ""
msgstr "Datum"
#. module: account_asset
#: field:account.asset.board,value_net:0
msgid "Net value"
msgstr ""
msgstr "Netto Wert"
#. module: account_asset
#: wizard_view:account.asset.close,init:0
#: model:ir.actions.wizard,name:account_asset.wizard_asset_close
msgid "Close asset"
msgstr ""
msgstr "Anlagegut schliessen"
#. module: account_asset
#: field:account.asset.property,history_ids:0
msgid "History"
msgstr ""
msgstr "Verlauf"
#. module: account_asset
#: field:account.asset.property,account_actif_id:0
msgid "Depreciation account"
msgstr ""
msgstr "AfA-Konto"
#. module: account_asset
#: field:account.asset.asset,period_id:0
#: wizard_field:account.asset.compute,init,period_id:0
msgid "Period"
msgstr ""
msgstr "Periode"
#. 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 ""
msgstr "Anlagenkategorie"
#. 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 ""
msgstr "Abbrechen"
#. 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 ""
msgstr "Schließen"
#. module: account_asset
#: selection:account.asset.property,state:0
msgid "Open"
msgstr ""
msgstr "Öffnen"
#. module: account_asset
#: constraint:ir.model:0
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
"Der Objektname muss mit \"x_\" beginnen und darf keine Sonderzeichen "
"beinhalten!"
#. module: account_asset
#: model:ir.module.module,shortdesc:account_asset.module_meta_information
msgid "Asset management"
msgstr ""
msgstr "Anlagenbuchhaltung"
#. 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 ""
msgstr "Anlagenspiegel"
#. module: account_asset
#: field:account.asset.asset,state:0
msgid "Global state"
msgstr ""
msgstr "Globaler Status"
#. module: account_asset
#: selection:account.asset.property,method_time:0
msgid "Delay"
msgstr ""
msgstr "Verzögerung"
#. module: account_asset
#: wizard_view:account.asset.close,init:0
msgid "General information"
msgstr ""
msgstr "Allgemeine Informationen"
#. module: account_asset
#: field:account.asset.property,journal_analytic_id:0
msgid "Analytic journal"
msgstr ""
msgstr "analytisches Journal"
#. module: account_asset
#: field:account.asset.property,name:0
msgid "Method name"
msgstr ""
msgstr "Methodenname"
#. module: account_asset
#: field:account.asset.property,journal_id:0
msgid "Journal"
msgstr ""
msgstr "Journal"
#. module: account_asset
#: field:account.asset.property.history,name:0
msgid "History name"
msgstr ""
msgstr "Verlauf Bezeichnung"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Close method"
msgstr ""
msgstr "Abschlussmethode"
#. module: account_asset
#: field:account.asset.property,entry_asset_ids:0
msgid "Asset Entries"
msgstr ""
msgstr "Anlagen"
#. module: account_asset
#: field:account.asset.asset,category_id:0
@ -464,66 +466,66 @@ msgstr ""
#: field:account.asset.category,name:0
#: model:ir.model,name:account_asset.model_account_asset_category
msgid "Asset category"
msgstr ""
msgstr "Analgenkategorie"
#. module: account_asset
#: view:account.asset.asset:0
msgid "Depreciation"
msgstr ""
msgstr "Abschreibung"
#. module: account_asset
#: field:account.asset.asset,code:0
#: field:account.asset.category,code:0
msgid "Asset code"
msgstr ""
msgstr "Kurzbezeichnung"
#. module: account_asset
#: field:account.asset.asset,value_total:0
msgid "Total value"
msgstr ""
msgstr "Gesamt Wert"
#. module: account_asset
#: selection:account.asset.asset,state:0
msgid "View"
msgstr ""
msgstr "Ansicht"
#. module: account_asset
#: view:account.asset.asset:0
msgid "General info"
msgstr ""
msgstr "Allgemeine Informationen"
#. module: account_asset
#: field:account.asset.asset,sequence:0
msgid "Sequence"
msgstr ""
msgstr "Sequenz"
#. module: account_asset
#: field:account.asset.property,value_residual:0
msgid "Residual value"
msgstr ""
msgstr "Buchwert"
#. module: account_asset
#: wizard_button:account.asset.close,init,asset_close:0
msgid "End of asset"
msgstr ""
msgstr "Ende des Anlagegutes"
#. module: account_asset
#: selection:account.asset.property,type:0
msgid "Direct"
msgstr ""
msgstr "Direkt"
#. module: account_asset
#: selection:account.asset.property,type:0
msgid "Indirect"
msgstr ""
msgstr "Indirekt"
#. module: account_asset
#: field:account.asset.asset,parent_id:0
msgid "Parent asset"
msgstr ""
msgstr "übergeordnetes Anlagegut"
#. 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 ""
msgstr "Anlangenhierarchie"

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

@ -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>

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

@ -958,6 +958,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

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

@ -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

@ -146,7 +146,11 @@
<field eval="&quot;&quot;&quot;Grand-Rosière&quot;&quot;&quot;" name="city"/>
<field eval="&quot;&quot;&quot;+32.81.73.35.01&quot;&quot;&quot;" name="fax"/>
<field eval="&quot;&quot;&quot;1367&quot;&quot;&quot;" name="zip"/>
<field name="country_id" ref="base.be"/>
<!-- The partner associated with the main company should not have a country specified in the demo data,
as it may conflicts with the accounting installing chart wizard. This wizard will indeed try to
install the localization module accordingly to this variable automatically. Thus, in demo data,
everyone would have the belgian chart of account by default, what should be avoided. -->
<!-- <field name="country_id" ref="base.be"/> -->
<field eval="&quot;&quot;&quot;+32.81.81.37.00&quot;&quot;&quot;" name="phone"/>
<field eval="&quot;&quot;&quot;Chaussée de Namur, 40&quot;&quot;&quot;" name="street"/>
</record>
@ -154,7 +158,11 @@
<field eval="&quot;&quot;&quot;Louvain-La-Neuve&quot;&quot;&quot;" name="city"/>
<field eval="&quot;&quot;&quot;1348&quot;&quot;&quot;" name="zip"/>
<field eval="&quot;&quot;&quot;contact&quot;&quot;&quot;" name="type"/>
<field name="country_id" ref="base.be"/>
<!-- The partner associated with the main company should not have a country specified in the demo data,
as it may conflicts with the accounting installing chart wizard. This wizard will indeed try to
install the localization module accordingly to this variable automatically. Thus, in demo data,
everyone would have the belgian chart of account by default, what should be avoided. -->
<!-- <field name="country_id" ref="base.be"/> -->
<field eval="&quot;&quot;&quot;rue du pré, 115&quot;&quot;&quot;" name="street"/>
<field eval="1" name="active"/>
</record>
@ -162,7 +170,11 @@
<field eval="&quot;&quot;&quot;Charleroi&quot;&quot;&quot;" name="city"/>
<field eval="&quot;&quot;&quot;6000&quot;&quot;&quot;" name="zip"/>
<field eval="&quot;&quot;&quot;contact&quot;&quot;&quot;" name="type"/>
<field name="country_id" ref="base.be"/>
<!-- The partner associated with the main company should not have a country specified in the demo data,
as it may conflicts with the accounting installing chart wizard. This wizard will indeed try to
install the localization module accordingly to this variable automatically. Thus, in demo data,
everyone would have the belgian chart of account by default, what should be avoided. -->
<!-- <field name="country_id" ref="base.be"/> -->
<field eval="&quot;&quot;&quot;Boulevars Tirou, 32&quot;&quot;&quot;" name="street"/>
<field eval="1" name="active"/>
</record>

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

@ -64,7 +64,7 @@
country_id: base.be
first_name: Nicolas
job_ids:
- address_id: base.main_address
- address_id: base.res_partner_address_1
function: CTO
state: current
- address_id: base.res_partner_address_3000

View File

@ -59,13 +59,21 @@ class report_xml(osv.osv):
return True
def report_get(self, cr, uid, report_id, context=None):
if context is None:
context = {}
# skip osv.fields.sanitize_binary_value() because we want the raw bytes in all cases
context.update(bin_raw=True)
report = self.browse(cr, uid, report_id, context=context)
sxw_data=(report.report_sxw_content).encode("iso-8859-1", "replace")
rml_data= (report.report_rml_content).encode("iso-8859-1", "replace")
sxw_data = report.report_sxw_content
rml_data = report.report_rml_content
if isinstance(sxw_data, unicode):
sxw_data = sxw_data.encode("iso-8859-1", "replace")
if isinstance(rml_data, unicode):
rml_data = rml_data.encode("iso-8859-1", "replace")
return {
'file_type' : report.report_type,
'report_sxw_content': report.report_sxw_content and base64.encodestring(sxw_data) or False,
'report_rml_content': report.report_rml_content and base64.encodestring(rml_data) or False
'file_type' : report.report_type,
'report_sxw_content': sxw_data and base64.encodestring(sxw_data) or False,
'report_rml_content': rml_data and base64.encodestring(rml_data) or False
}
report_xml()

View File

@ -23,7 +23,7 @@
<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="100"/>
<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>

View File

@ -19,6 +19,7 @@
#
##############################################################################
import res_company
import base_vat
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -33,6 +33,21 @@ be validated for all supported countries. The country is inferred from the
2-letter country code that prefixes the VAT number, e.g. ``BE0477472701``
will be validated using the Belgian rules.
There are two different levels of VAT number validation:
* By default, a simple off-line check is performed using the known validation
rules for the country, usually a simple check digit. This is quick and
always available, but allows numbers that are perhaps not truly allocated,
or not valid anymore.
* When the "VAT VIES Check" option is enabled (in the configuration of the user's
Company), VAT numbers will be instead submitted to the online EU VIES
database, which will truly verify that the number is valid and currently
allocated to a EU company. This is a little bit slower than the simple
off-line check, requires an Internet connection, and may not be available
all the time. If the service is not available or does not support the
requested country (e.g. for non-EU countries), a simple check will be performed
instead.
Supported countries currently include EU countries, and a few non-EU countries
such as Chile, Colombia, Mexico, Norway or Russia. For unsupported countries,
only the country code will be validated.

View File

@ -61,27 +61,48 @@ class res_partner(osv.osv):
vat_country, vat_number = vat[:2].lower(), vat[2:].replace(' ', '')
return vat_country, vat_number
def check_vat(self, cr, uid, ids, context=None):
def simple_vat_check(self, cr, uid, country_code, vat_number, context=None):
'''
Check the VAT number depending of the country.
http://sima-pc.com/nif.php
'''
country_obj = self.pool.get('res.country')
check_func_name = 'check_vat_' + country_code
check_func = getattr(self, check_func_name, None) or \
getattr(vatnumber, check_func_name, None)
if not check_func:
# No VAT validation available, default to check that the country code exists
res_country = self.pool.get('res.country')
return bool(res_country.search(cr, uid, [('code', '=ilike', country_code)], context=context))
return check_func(vat_number)
def vies_vat_check(self, cr, uid, country_code, vat_number, context=None):
try:
# Validate against VAT Information Exchange System (VIES)
# see also http://ec.europa.eu/taxation_customs/vies/
return vatnumber.check_vies(country_code.upper()+vat_number)
except Exception:
# see http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl
# Fault code may contain INVALID_INPUT, SERVICE_UNAVAILABLE, MS_UNAVAILABLE,
# TIMEOUT or SERVER_BUSY. There is no way we can validate the input
# with VIES if any of these arise, including the first one (it means invalid
# country code or empty VAT number), so we fall back to the simple check.
return self.simple_vat_check(cr, uid, country_code, vat_number, context=context)
def check_vat(self, cr, uid, ids, context=None):
user_company = self.pool.get('res.users').browse(cr, uid, uid).company_id
if user_company.vat_check_vies:
# force full VIES online check
check_func = self.vies_vat_check
else:
# quick and partial off-line checksum validation
check_func = self.simple_vat_check
for partner in self.browse(cr, uid, ids, context=context):
if not partner.vat:
continue
vat_country, vat_number = self._split_vat(partner.vat)
check_func_name = 'check_vat_' + vat_country
check_func = getattr(self, check_func_name, None) or \
getattr(vatnumber, check_func_name, None)
if not check_func:
# No VAT validation available, default to check that the country code
# exists.
if country_obj.search(cr, uid, [('code', 'ilike', vat_country)], context=context):
continue
# Country code not found, considered invalid
if not check_func(cr, uid, vat_country, vat_number, context=context):
return False
return check_func(vat_number)
return True
def vat_change(self, cr, uid, ids, value, context=None):

View File

@ -7,12 +7,23 @@
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="property_account_payable" position="after">
<group colspan="2" col="6">
<field name="vat" on_change="vat_change(vat)" colspan="4" />
<field name="vat_subjected" colspan="1" groups="base.group_extended" />
</group>
<field name="property_account_payable" position="after">
<group colspan="2" col="6">
<field name="vat" on_change="vat_change(vat)" colspan="4" />
<field name="vat_subjected" colspan="1" groups="base.group_extended" />
</group>
</field>
</field>
</record>
<record id="company_form_vat" model="ir.ui.view">
<field name="name">res.company.form.vat.inherit</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="vat_check_vies" groups="base.group_extended" />
</field>
</field>
</record>

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2011 OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
class res_company_vat (osv.osv):
_inherit = 'res.company'
_columns = {
'vat_check_vies': fields.boolean('VIES VAT Check',
help="If checked, Partners VAT numbers will be fully validated against EU's VIES service "
"rather than via a simple format validation (checksum)."),
}

View File

@ -118,18 +118,14 @@ 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,
'active': False,

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
@ -206,6 +206,7 @@ class crm_lead(crm_case, osv.osv):
'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('section_ids', '=', section_id)]"),
'color': fields.integer('Color Index'),
'partner_address_name': fields.related('partner_address_id', 'name', type='char', string='Partner Contact Name', readonly=True),
'partner_address_email': fields.related('partner_address_id', 'email', type='char', string='Partner Contact Email', readonly=True),
'company_currency': fields.related('company_id', 'currency_id', 'symbol', type='char', string='Company Currency', readonly=True),
'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True),
'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True),
@ -351,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"""
@ -440,24 +785,17 @@ class crm_lead(crm_case, osv.osv):
This opens Meeting's calendar view to schedule meeting on current Opportunity
@return : Dictionary value for created Meeting view
"""
if context is None:
context = {}
value = {}
data_obj = self.pool.get('ir.model.data')
for opp in self.browse(cr, uid, ids, context=context):
data_obj = self.pool.get('ir.model.data')
# 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
context = {
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,
'default_user_id': uid,
@ -465,7 +803,7 @@ class crm_lead(crm_case, osv.osv):
'default_email_from': opp.email_from,
'default_state': 'open',
'default_name': opp.name
}
})
value = {
'name': _('Meetings'),
'context': context,
@ -473,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

@ -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,34 +143,6 @@
type="object" icon="gtk-convert" />
</group>
</page>
<page string="Extra Info" groups="base.group_extended">
<group colspan="2" col="2">
<separator string="Categorization" colspan="2" col="2"/>
<field name="company_id"
groups="base.group_multi_company"
widget="selection" colspan="2" />
<field name="type_id" select="1" widget="selection"/>
<field name="channel_id" select="1" widget="selection"/>
<field name="referred"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2" col="2"/>
<field name="create_date"/>
<field name="write_date"/>
<field name="date_open"/>
<field name="date_closed"/>
</group>
<group colspan="2" col="2">
<separator string="Mailings" colspan="2" col="2"/>
<field name="optin" on_change="on_change_optin(optin)"/>
<field name="optout" on_change="on_change_optout(optout)"/>
</group>
<group colspan="2" col="2">
<separator string="Statistics" colspan="2" col="2"/>
<field name="day_open"/>
<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"/>
@ -222,6 +195,34 @@
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"/>
<field name="company_id"
groups="base.group_multi_company"
widget="selection" colspan="2" />
<field name="type_id" select="1" widget="selection"/>
<field name="channel_id" select="1" widget="selection"/>
<field name="referred"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2" col="2"/>
<field name="create_date"/>
<field name="write_date"/>
<field name="date_open"/>
<field name="date_closed"/>
</group>
<group colspan="2" col="2">
<separator string="Mailings" colspan="2" col="2"/>
<field name="optin" on_change="on_change_optin(optin)"/>
<field name="optout" on_change="on_change_optout(optout)"/>
</group>
<group colspan="2" col="2">
<separator string="Statistics" colspan="2" col="2"/>
<field name="day_open"/>
<field name="day_close"/>
</group>
</page>
</notebook>
</form>
</field>
@ -304,31 +305,46 @@
<field name="priority"/>
<field name="planned_revenue" sum="Expected Revenues"/>
<field name="user_email"/>
<field name="user_id"/>
<field name="partner_address_email"/>
<templates>
<t t-name="lead_details">
<ul class="oe_kanban_tooltip">
<li t-if="record.phone.raw_value"><b>Phone:</b> <field name="phone"/></li>
<li><b>Probability:</b> <field name="probability"/>%%</li>
<li><b>Creation date:</b> <field name="create_date"/></li>
<li t-if="record.date_deadline.raw_value"><b>Date Deadline:</b> <field name="date_deadline"/></li>
</ul>
</t>
<t t-name="kanban-box">
<t t-set="color" t-value="kanban_color(record.color.raw_value)"/>
<div t-att-class="color + (record.priority.raw_value == 1 ? ' oe_kanban_color_alert' : '')">
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="border">oe_kanban_color_red</t>
<div t-attf-class="#{kanban_color(record.color.raw_value)} #{border || ''}">
<div class="oe_kanban_box oe_kanban_color_border">
<table class="oe_kanban_table oe_kanban_box_header oe_kanban_color_bgdark oe_kanban_color_border oe_kanban_draghandle">
<tr>
<td class="oe_kanban_title3" align="left" valign="middle">
<td align="left" valign="middle" width="16">
<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_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)"/>
<field name="company_currency"/>
</t>
</td>
<td class="oe_kanban_title2" align="right" valign="middle" t-if="record.planned_revenue.raw_value" nowrap="nowrap">
<t t-esc="Math.round(record.planned_revenue.value)"/> <field name="company_currency"/>
</td>
<td valign="top" width="22"><img t-att-src="kanban_gravatar(record.user_email.value, 22)" class="oe_kanban_gravatar"/></td>
<td valign="top" width="22"><img t-att-src="kanban_gravatar(record.user_email.value, 22)" class="oe_kanban_gravatar" t-att-title="record.user_id.value"/></td>
</tr>
</table>
<div class="oe_kanban_box_content oe_kanban_color_bglight oe_kanban_box_show_onclick_trigger">
<div class="oe_kanban_right oe_kanban_small">
<field name="user_login"/>
</div>
<div>
<b><field name="partner_address_name"/></b>
<b>
<a t-if="record.partner_address_email.raw_value" t-attf-href="mailto:#{record.partner_address_email.raw_value}">
<field name="partner_address_name"/>
</a>
<field t-if="!record.partner_address_email.raw_value" name="partner_address_name"/>
</b>
</div>
<div>
<field name="name"/>
@ -344,13 +360,14 @@
<a string="Change Color" icon="color-picker" type="color" name="color"/>
<a string="Send New Email" name="%(mail.action_email_compose_message_wizard)d" icon="terp-mail-message-new" type="action"/>
<a string="Schedule/Log Call" name="%(opportunity2phonecall_act)d" icon="terp-call-start" type="action"/>
<a string="Add Internal Note" name="%(crm.action_crm_add_note)d" context="{'model': 'crm.lead' }" icon="terp-document-new" type="action"/>
<a string="Schedule Meeting" name="action_makeMeeting" type="object" icon="stock_calendar"/>
<a string="Add Internal Note" name="%(crm.action_crm_add_note)d" context="{'model': 'crm.lead' }" icon="terp-document-new" type="action"/>
</div>
<div class="oe_kanban_right">
<a name="case_pending" string="Pending" states="draft,open" type="object" icon="kanban-pause" />
<a name="case_mark_won" string="Mark Won" states="open,pending" type="object" icon="kanban-apply" />
<a name="case_mark_lost" string="Mark Lost" states="open,pending" type="object" icon="kanban-stop" />
<a name="case_pending" string="Pending" states="draft,open" type="object" icon="kanban-pause" />
<a name="case_open" string="Open" states="pending" type="object" icon="gtk-media-play" />
<a name="case_mark_won" string="Mark Won" states="open,pending" type="object" icon="kanban-apply" />
</div>
<br class="oe_kanban_clear"/>
</div>
@ -443,7 +460,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">
@ -689,6 +706,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

@ -147,6 +147,7 @@ class crm_lead_report(osv.osv):
extract('epoch' from (c.date_open-c.create_date))/(3600*24) as delay_open
FROM
crm_lead c
WHERE c.active = 'true'
)""")
crm_lead_report()

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')})

View File

@ -1,26 +0,0 @@
- |
I start by creating a new phonecall.
-
!record {model: crm.phonecall, id: crm_phonecall_dummycall}:
date: !eval time.strftime('%Y-%m-%d 08:00:00')
name: Dummy call
duration: 0.0
section_id: crm.section_sales_department
partner_id: base.res_partner_agrolait
state: open
-
I change Contact Detail of the Partner.
-
!python {model: crm.phonecall}: |
self.onchange_partner_address_id(cr, uid,[ref("crm_phonecall_dummycall")], ref("base.res_partner_address_8invoice"))
-
I setting Phone call to Held (Done).
-
!python {model: crm.phonecall}: |
self.case_close(cr, uid, [ref("crm_phonecall_dummycall")])
-
I check that the hone call is in 'Held' state.
-
!assert {model: crm.phonecall, id: crm_phonecall_dummycall, string: Phone call Helded}:
- state == "done"

View File

@ -1,106 +0,0 @@
-
In order to test recurrent meetings in OpenERP, I create meetings with different recurrency.
-
I create a customer meeting record with daily recurrency.
-
!record {model: crm.meeting, id: crm_meeting_pricelistdiscussion0}:
categ_id: crm.categ_meet1
count: 0.0
date: '2011-01-05 00:00:00'
date_deadline: '2011-01-05 01:00:00'
day: 0.0
duration: 1.0
end_date: '2011-01-12'
end_type: end_date
name: Pricelist Discussion
recurrency: true
recurrent_uid: 0.0
rrule: FREQ=DAILY;INTERVAL=1;UNTIL=20110112T235959Z
rrule_type: daily
sequence: 0.0
-
I create another meeting record with weekly recurrency.
-
!record {model: crm.meeting, id: crm_meeting_changesindesigning0}:
categ_id: crm.categ_meet2
count: 15
date: '2011-01-22 11:05:05'
date_deadline: '2011-01-22 16:05:05'
day: 0.0
duration: 5.0
email_from: info@opensides.be
end_type: count
fr: true
mo: true
name: Changes in Designing
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
recurrency: true
recurrent_uid: 0.0
rrule: FREQ=WEEKLY;BYDAY=FR,TU,TH,WE,MO;INTERVAL=1;COUNT=15
rrule_type: weekly
section_id: crm.section_sales_department
sequence: 0.0
th: true
tu: true
user_id: base.user_demo
we: true
-
I create a meeting record with monthly recurrency.
-
!record {model: crm.meeting, id: crm_meeting_reviewneeds0}:
categ_id: crm.categ_meet3
count: 0.0
date: '2011-01-20 10:02:02'
date_deadline: '2011-01-20 16:02:02'
day: 15
duration: 6.0
end_date: '2011-05-31'
end_type: end_date
name: Review needs
partner_address_id: base.res_partner_address_15
partner_id: base.res_partner_11
recurrency: true
recurrent_uid: 0.0
rrule: FREQ=MONTHLY;INTERVAL=1;UNTIL=20110531T235959Z;BYMONTHDAY=15
rrule_type: monthly
section_id: crm.section_sales_department
sequence: 0.0
user_id: base.user_demo
-
I create a record for daily scrum meeting.
-
!record {model: crm.meeting, id: crm_meeting_scrummeeting0}:
categ_id: crm.categ_meet2
count: 0.0
date: '2011-01-06 00:00:00'
date_deadline: '2011-01-06 01:00:00'
day: 0.0
duration: 1.0
name: Scrum meeting
recurrency: true
recurrent_uid: 0.0
rrule: FREQ=DAILY;INTERVAL=1
rrule_type: daily
sequence: 0.0
-
I create a meeting record for yearly recurrency.
-
!record {model: crm.meeting, id: crm_meeting_updatethedata0}:
categ_id: crm.categ_meet2
count: 0.0
date: '2011-01-18 13:12:49'
date_deadline: '2011-01-19 02:30:49'
day: 0.0
duration: 13.300000000000001
end_date: '2015-01-06'
end_type: end_date
name: Update the data
partner_address_id: base.res_partner_address_7
partner_id: base.res_partner_4
recurrency: true
recurrent_uid: 0.0
rrule: FREQ=YEARLY;INTERVAL=1;UNTIL=20150106T235959Z
rrule_type: yearly
section_id: crm.section_sales_department
sequence: 0.0

View File

@ -1,38 +0,0 @@
- |
I will test segmentation which create specific partner categories criteria.
-
I create a new segmentation record.
-
!record {model: crm.segmentation, id: crm_segmentation_id_0}:
categ_id: base.res_partner_category_5
exclusif: true
name: segment
som_interval: 0.0
sales_purchase_active : True
-
I start the process.
-
!python {model: crm.segmentation}: |
self.process_start(cr, uid, [ref("crm_segmentation_id_0")],context)
-
I continue the segmentation process.
-
!python {model: crm.segmentation}: |
context.update({'start': True})
self.process_continue(cr, uid, [ref("crm_segmentation_id_0")], context)
-
I create the segmentation line.
-
!record {model: crm.segmentation.line, id: crm_segmentation_line_id_0}:
expr_name: sale
expr_operator: '>'
expr_value: 1000.0
name: Rule1
operator: or
segmentation_id: crm_segmentation_id_0
-
I check the Segmentation line record.
-
!python {model: crm.segmentation.line}: |
self.test(cr, uid, [ref("crm_segmentation_line_id_0")],partner_id=0)

View File

@ -1,96 +0,0 @@
-
In order to test the changes on stage of a lead or an opportunity with OpenERP,
I create some leads and test the stage changes.
-
I want to change the probability to 0.0 when the opportunity is marked as lost.
So I set its Change probability automatically true.
-
!record {model: crm.case.stage, id: crm.stage_lead6}:
name: Lost
on_change: true
probability: 0.0
section_ids:
- crm.section_sales_department
sequence: 0
-
I create a lead 'Test Lead1'.
-
!record {model: crm.lead, id: crm_lead_openerppresentation0}:
categ_id: crm.categ_oppor4
day_close: 0.0
day_open: 0.0
name: Test Lead1
planned_revenue: 0.0
probability: 10.0
section_id: crm.section_sales_department
-
I open the lead.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref('crm_lead_openerppresentation0')])
-
I assigning stage.
-
!python {model: crm.lead}: |
self.onchange_stage_id(cr, uid, [ref('crm_lead_openerppresentation0')], [], context)
-
I assigning percent.
-
!python {model: crm.lead}: |
self.stage_find_percent(cr, uid, 10.0, [])
-
I find that this lead can be converted to opportunity.
-
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner0}:
action: 'create'
name: 'convert'
-
So I convert the lead to opportunity.
-
!python {model: crm.lead2opportunity.partner}: |
self.action_apply(cr, uid, [ref('crm_lead2opportunity_partner0')], context={'active_ids': [ref('crm_lead_openerppresentation0')]})
-
I check that lead is now converted to opportunity.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref('crm_lead_openerppresentation0'))
assert lead.type == 'opportunity', 'Lead is not converted to opportunity!'
-
I mark this opportunity as lost.
-
!python {model: crm.lead}: |
self.case_mark_lost(cr, uid, [ref('crm_lead_openerppresentation0')])
-
I check whether the probability is set according to stage change or not.
-
!python {model: crm.lead}: |
opportunity = self.browse(cr, uid, ref('crm_lead_openerppresentation0'))
assert opportunity.stage_id.id == ref('crm.stage_lead6'), 'Stage is not changed!'
assert opportunity.probability == 0.0, 'Probability is wrong!'
-
I create one more opportunity.
-
!record {model: crm.lead, id: crm_lead_test2}:
name: Partner Demo
type: opportunity
categ_id: crm.categ_oppor3
planned_revenue: 50000.0
probability: 100.0
section_id: crm.section_sales_department
-
I open this opportunity.
-
!python {model: crm.lead}: |
self.case_open(cr, uid, [ref('crm_lead_test2')])
-
I mark this opportunity as won.
-
!python {model: crm.lead}: |
self.case_mark_won(cr, uid, [ref('crm_lead_test2')])
-
I check whether the stage is changed to 'Won' and probability is 100.0 or not.
-
!python {model: crm.lead}: |
opportunity = self.browse(cr, uid, ref('crm_lead_test2'))
assert opportunity.stage_id.id == ref('crm.stage_lead5'), 'Stage is not changed!'
assert opportunity.probability == 100.0, 'Probability is wrong!'

View File

@ -0,0 +1,29 @@
-
I create lead record to call of partner onchange, stage onchange and Mailing opt-in onchange method.
-
!record {model: crm.lead, id: crm_case_shelvehouse}:
name: 'Need more info about your pc2'
partner_id: base.res_partner_theshelvehouse0
type: opportunity
stage_id: crm.stage_lead1
state: draft
optin: True
-
I create lead record to call Mailing opt-out onchange method.
-
!record {model: crm.lead, id: crm_case_mediapoleunits0}:
name: 'Need 20 Days of Consultancy'
type: opportunity
state: draft
optout: True
-
I create phonecall record to call partner onchange method.
-
!record {model: crm.phonecall, id: crm_case_phone05}:
name: 'Bad time'
partner_id: base.res_partner_5
-
I setting next stage "New" for the lead.
-
!python {model: crm.lead}: |
self.stage_next(cr, uid, [ref("crm_case_qrecorp0")], context={'stage_type': 'lead'})

View File

@ -0,0 +1,5 @@
-
I Unlink the Lead.
-
!python {model: crm.lead}: |
self.unlink(cr, uid, [ref("crm_case_qrecorp0")])

View File

@ -0,0 +1,5 @@
-
I make duplicate the Lead.
-
!python {model: crm.lead}: |
self.copy(cr, uid, ref("crm_case_qrecorp0"))

View File

@ -24,11 +24,11 @@ import crm_add_note
import crm_lead_to_partner
import crm_lead_to_opportunity
import crm_opportunity_to_phonecall
import crm_phonecall_to_phonecall
import crm_opportunity_to_phonecall
import crm_phonecall_to_partner
import crm_phonecall_to_opportunity
import crm_partner_to_opportunity
import crm_phonecall_to_opportunity
import crm_merge_opportunities

View File

@ -54,6 +54,8 @@ class crm_lead2opportunity_partner(osv.osv_memory):
email = False
for lead in lead_obj.browse(cr, uid, opportunities, context=context):
partner_id = lead.partner_id and lead.partner_id.id or False
#TOFIX: use mail.mail_message.to_mail
email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '')
email = map(lambda x: "'" + x + "'", email)
@ -93,139 +95,51 @@ class crm_lead2opportunity_partner(osv.osv_memory):
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
"""
if context is None:
context = {}
lead_obj = self.pool.get('crm.lead')
for lead in lead_obj.browse(cr, uid, context.get('active_ids', []), context=context):
if lead.state in ['done', 'cancel']:
raise osv.except_osv(_("Warning !"), _("Closed/Cancelled Leads can not be converted into Opportunity"))
return False
def _convert(self, cr, uid, ids, lead, partner_id, stage_ids, context=None):
leads = self.pool.get('crm.lead')
address_id = False
if partner_id:
address_id = self.pool.get('res.partner.address').search(cr, uid,
[('partner_id', '=', partner_id)],
order='create_date desc',
limit=1)
vals = {
'planned_revenue': lead.planned_revenue,
'probability': lead.probability,
'name': lead.name,
'partner_id': partner_id,
'user_id': (lead.user_id and lead.user_id.id),
'type': 'opportunity',
'stage_id': stage_ids and stage_ids[0] or False,
'date_action': time.strftime('%Y-%m-%d %H:%M:%S'),
}
if partner_id and address_id:
vals['partner_address_id'] = address_id[0]
else:
vals['partner_address_id'] = False
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
if context is None:
context = {}
lead = self.pool.get('crm.lead')
partner_id = self._create_partner(cr, uid, ids, context=context)
lead_ids = vals.get('lead_ids', [])
user_ids = vals.get('user_ids', False)
team_id = vals.get('section_id', False)
return lead.convert_opportunity(cr, uid, lead_ids, partner_id, user_ids, team_id, context=context)
lead.write(vals, context=context)
text = _('Converted to opportunity')
leads.message_append(cr, uid, [lead], text, body_text=text, context=context)
if lead.partner_id:
msg_ids = [ x.id for x in lead.message_ids]
self.pool.get('mail.message').write(cr, uid, msg_ids, {
'partner_id': lead.partner_id.id
}, context=context)
leads.log(cr, uid, lead.id, _("Lead '%s' has been converted to an opportunity.") % lead.name)
def send_mail_to_salesman(self, cr, uid, lead):
email_to = lead.user_id and lead.user_id.user_email
if not email_to:
return False
message_pool = self.pool.get('mail.message')
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_pool.schedule_with_attach(cr, uid, email_from, [email_to], subject, body)
def _merge_opportunity(self, cr, uid, ids, opportunity_ids, action='merge', context=None):
#TOFIX: is it usefully ?
if context is None:
context = {}
merge_opportunity = self.pool.get('crm.merge.opportunity')
res = False
#If we convert in mass, don't merge if there is no other opportunity but no warning
if action == 'merge' and (len(opportunity_ids) > 1 or not context.get('mass_convert') ):
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [opportunity_ids[0].id])]}, context=context)
context.update({'lead_ids' : record_id, "convert" : True})
res = merge_opportunity.merge(cr, uid, data.opportunity_ids, context=context)
return res
def action_apply(self, cr, uid, ids, context=None):
"""
This converts lead to opportunity and opens Opportunity view
@param ids: ids of the leads to convert to opportunities
@return : View dictionary opening the Opportunity form view
"""
if not context:
context = {}
record_id = context and context.get('active_ids') or False
if not record_id:
return {'type': 'ir.actions.act_window_close'}
leads = self.pool.get('crm.lead')
models_data = self.pool.get('ir.model.data')
# Get Opportunity views
result = models_data._get_id(
cr, uid, 'crm', 'view_crm_case_opportunities_filter')
opportunity_view_search = models_data.browse(
cr, uid, result, context=context).res_id
opportunity_view_form = models_data._get_id(
cr, uid, 'crm', 'crm_case_form_view_oppor')
opportunity_view_tree = models_data._get_id(
cr, uid, 'crm', 'crm_case_tree_view_oppor')
if opportunity_view_form:
opportunity_view_form = models_data.browse(
cr, uid, opportunity_view_form, context=context).res_id
if opportunity_view_tree:
opportunity_view_tree = models_data.browse(
cr, uid, opportunity_view_tree, context=context).res_id
for lead in leads.browse(cr, uid, record_id, context=context):
if lead.section_id:
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('sequence','>=',1), ('section_ids','=', lead.section_id.id)])
else:
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('sequence','>=',1)])
data = self.browse(cr, uid, ids[0], context=context)
if data.action == 'create':
partner_ids = []
partner_ids = self._create_partner(cr, uid, ids, context=context)
partner_id = partner_ids and partner_ids[0]
elif data.action == 'exist':
partner_id = data.partner_id and data.partner_id.id
else:
partner_id = False
self._convert(cr, uid, ids, lead, partner_id, stage_ids, context=context)
self.send_mail_to_salesman(cr, uid, lead)
#If we convert in mass, don't merge if there is no other opportunity but no warning
if data.name == 'merge' and (len(data.opportunity_ids) > 1 or not context.get('mass_convert') ):
merge_obj = self.pool.get('crm.merge.opportunity')
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [data.opportunity_ids[0].id])]}, context=context)
context.update({'lead_ids' : record_id, "convert" : True})
return merge_obj.merge(cr, uid, data.opportunity_ids, context=context)
return {
'name': _('Opportunity'),
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'crm.lead',
'domain': [('type', '=', 'opportunity')],
'res_id': int(lead.id),
'view_id': False,
'views': [(opportunity_view_form, 'form'),
(opportunity_view_tree, 'tree'),
(False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window',
'search_view_id': opportunity_view_search
}
lead = self.pool.get('crm.lead')
lead_ids = context.get('active_ids', [])
data = self.browse(cr, uid, ids, context=context)[0]
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context)
self._merge_opportunity(cr, uid, ids, data.opportunity_ids, data.action, context=context)
return lead.redirect_opportunity_view(cr, uid, lead_ids[0], context=context)
crm_lead2opportunity_partner()
@ -240,55 +154,19 @@ class crm_lead2opportunity_mass_convert(osv.osv_memory):
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
}
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
data = self.browse(cr, uid, ids, context=context)[0]
salesteam_id = data.section_id and data.section_id.id or False
salesman = []
if data.user_ids:
salesman = [x.id for x in data.user_ids]
vals.update({'user_ids': salesman, 'section_id': salesteam_id})
return super(crm_lead2opportunity_mass_convert, self)._convert_opportunity(cr, uid, ids, vals, context=context)
def mass_convert(self, cr, uid, ids, context=None):
lead_obj = self.pool.get('crm.lead')
if not context:
context = {}
active_ids = context.get('active_ids')
data = self.browse(cr, uid, ids, context=context)[0]
salesteam = data.section_id and data.section_id.id
if data.user_ids:
salesmans = map(lambda x : x.id, data.user_ids)
index = 0
else:
salesmans = False
for lead_id in active_ids:
value = {}
if salesteam:
value['section_id'] = salesteam
if salesmans:
value['user_id'] = salesmans[index]
index += 1
index = index < len(salesmans) and index or 0
if value:
lead_obj.write(cr, uid, [lead_id], value, context=context)
context['active_ids'] = [lead_id]
value = self.default_get(cr, uid, ['partner_id', 'opportunity_ids'], context=context)
value['opportunity_ids'] = [(6, 0, value['opportunity_ids'])]
self.write(cr, uid, ids, value, context=context)
self.action_apply(cr, uid, ids, context=context)
models_data = self.pool.get('ir.model.data')
result = models_data._get_id(cr, uid, 'crm', 'view_crm_case_opportunities_filter')
opportunity_view_search = models_data.browse(cr, uid, result, context=context).res_id
return {
'name': _('Opportunity'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'crm.lead',
'domain': [('type', '=', 'opportunity'), ('id', 'in', active_ids)],
'type': 'ir.actions.act_window',
'search_view_id': opportunity_view_search,
}
value = self.default_get(cr, uid, ['partner_id', 'opportunity_ids'], context=context)
value['opportunity_ids'] = [(6, 0, value['opportunity_ids'])]
self.write(cr, uid, ids, value, context=context)
return self.action_apply(cr, uid, ids, context=context)
crm_lead2opportunity_mass_convert()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -65,6 +65,15 @@
</form>
</field>
</record>
<record id="action_crm_lead2opportunity_partner" model="ir.actions.act_window">
<field name="name">Create a Partner</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">crm.lead2opportunity.partner</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_crm_lead2opportunity_partner"/>
<field name="target">new</field>
</record>
<act_window id="action_crm_send_mass_convert"
multi="True"

View File

@ -21,11 +21,9 @@
from osv import osv, fields
from tools.translate import _
import re
class crm_lead2partner(osv.osv_memory):
""" Converts lead to partner """
_name = 'crm.lead2partner'
_description = 'Lead to Partner'
@ -35,171 +33,89 @@ class crm_lead2partner(osv.osv_memory):
'Action', required=True),
'partner_id': fields.many2one('res.partner', 'Partner'),
}
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
"""
lead_obj = self.pool.get('crm.lead')
if context is None:
context = {}
model = context.get('active_model')
model = self.pool.get(model)
rec_ids = context and context.get('active_ids', [])
for lead in lead_obj.browse(cr, uid, rec_ids, context=context):
if lead.partner_id:
for this in model.browse(cr, uid, rec_ids, context=context):
if this.partner_id:
raise osv.except_osv(_('Warning !'),
_('A partner is already defined on this lead.'))
_('A partner is already defined.'))
def _select_partner(self, cr, uid, context=None):
if context is None:
context = {}
lead = self.pool.get('crm.lead')
partner = self.pool.get('res.partner')
lead_ids = list(context and context.get('active_ids', []) or [])
if not len(lead_ids):
return False
this = lead.browse(cr, uid, lead_ids[0], context=context)
# Find partner address matches the email_from of the lead
res = lead.message_partner_by_email(cr, uid, this.email_from, context=context)
partner_id = res.get('partner_id', False)
# Find partner name that matches the name of the lead
if not partner_id and this.partner_name:
partner_ids = partner.search(cr, uid, [('name', '=', this.partner_name)], context=context)
if partner_ids and len(partner_ids):
partner_id = partner_ids[0]
return partner_id
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : default values of fields.
"""
res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
partner_id = self._select_partner(cr, uid, context=context)
lead_obj = self.pool.get('crm.lead')
partner_obj = self.pool.get('res.partner')
partner_id = False
data = list(context and context.get('active_ids', []) or [])
res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
for lead in lead_obj.browse(cr, uid, data, context=context):
partner_ids = []
# Find partner address matches the email_from of the lead
email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '')
email = map(lambda x: "'" + x + "'", email)
if email:
cr.execute("""select partner_id from res_partner_address
where
substring(email from '([^ ,<@]+@[^> ,]+)') in (%s)""" % (','.join(email)))
partner_ids = map(lambda x: x[0], cr.fetchall())
# Find partner name that matches the name of the lead
if not partner_ids and lead.partner_name:
partner_ids = partner_obj.search(cr, uid, [('name', '=ilike', lead.partner_name)], context=context)
partner_id = partner_ids and partner_ids[0] or False
if 'partner_id' in fields:
res.update({'partner_id': partner_id})
if 'action' in fields:
res.update({'action': partner_id and 'exist' or 'create'})
if 'opportunity_ids' in fields:
res.update({'opportunity_ids': data})
if 'partner_id' in fields:
res.update({'partner_id': partner_id})
if 'action' in fields:
res.update({'action': partner_id and 'exist' or 'create'})
return res
def open_create_partner(self, cr, uid, ids, context=None):
"""
This function Opens form of create partner.
@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 Lead to Partner's IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for next form.
"""
if context is None:
context = {}
view_obj = self.pool.get('ir.ui.view')
view_id = view_obj.search(cr, uid, [('model', '=', 'crm.lead2partner'), \
('name', '=', 'crm.lead2partner.view')])
view_id = view_obj.search(cr, uid, [('model', '=', self._name), \
('name', '=', self._name+'.view')])
return {
'view_mode': 'form',
'view_type': 'form',
'view_id': view_id or False,
'res_model': 'crm.lead2partner',
'res_model': self._name,
'context': context,
'type': 'ir.actions.act_window',
'target': 'new',
}
}
def _create_partner(self, cr, uid, ids, context=None):
"""
This function Creates partner based on action.
@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 Lead to Partner's IDs
@param context: A standard dictionary for contextual values
@return : Dictionary {}.
"""
if context is None:
context = {}
lead_obj = self.pool.get('crm.lead')
partner_obj = self.pool.get('res.partner')
contact_obj = self.pool.get('res.partner.address')
partner_ids = []
partner_id = False
rec_ids = context and context.get('active_ids', [])
for data in self.browse(cr, uid, ids, context=context):
for lead in lead_obj.browse(cr, uid, rec_ids, context=context):
if data.action == 'create':
partner_id = partner_obj.create(cr, uid, {
'name': lead.partner_name or lead.contact_name or lead.name,
'user_id': lead.user_id.id,
'comment': lead.description,
'address': []
})
contact_obj.create(cr, uid, {
'partner_id': partner_id,
'name': lead.contact_name,
'phone': lead.phone,
'mobile': lead.mobile,
'email': lead.email_from,
'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,
})
else:
if data.partner_id:
partner_id = data.partner_id.id
self.assign_partner(cr, uid, lead.id, partner_id)
partner_ids.append(partner_id)
return partner_ids
def assign_partner(self, cr, uid, lead_id, partner_id):
self.pool.get("crm.lead").write(cr, uid, [lead_id], {'partner_id' : partner_id})
lead = self.pool.get('crm.lead')
lead_ids = context and context.get('active_ids') or []
data = self.browse(cr, uid, ids, context=context)[0]
partner_id = data.partner_id and data.partner_id.id or False
partner_ids = lead.convert_partner(cr, uid, lead_ids, data.action, partner_id, context=context)
return partner_ids[lead_ids[0]]
def make_partner(self, cr, uid, ids, context=None):
"""
This function Makes partner based on action.
@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 Lead to Partner's IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for created Partner form.
"""
if context is None:
context = {}
partner_ids = self._create_partner(cr, uid, ids, context=context)
return {'type': 'ir.actions.act_window_close'}
partner_id = self._create_partner(cr, uid, ids, context=context)
return self.pool.get('res.partner').redirect_partner_form(cr, uid, partner_id, context=context)
crm_lead2partner()

View File

@ -26,195 +26,16 @@ class crm_merge_opportunity(osv.osv_memory):
_name = 'crm.merge.opportunity'
_description = 'Merge two Opportunities'
def _get_first_not_null_id(self, attr, ops, oldest):
if hasattr(oldest, attr) and getattr(oldest, attr):
return getattr(oldest, attr).id
for op in ops:
if hasattr(op, attr) and getattr(op, attr):
return getattr(op, attr).id
return False
def _get_first_not_null(self, attr, ops, oldest):
if hasattr(oldest, attr) and getattr(oldest, attr):
return getattr(oldest, attr)
for op in ops:
if hasattr(op, attr) and getattr(op, attr):
return getattr(op, attr)
return False
def _concat_all(self, attr, ops):
return ', '.join([getattr(op, attr) for op in ops if hasattr(op, attr) and getattr(op, attr)])
def get_attachments(self, cr, uid, id, context=None):
proxy = self.pool.get('ir.attachment')
ids = proxy.search(cr, uid, [('res_model', '=', 'crm.lead'), ('res_id', '=', id)], context=context)
return proxy.browse(cr, uid, ids, context=context)
def find_oldest(self, cr, uid, op_ids, context=None):
if not context:
context = {}
ids = [op_id.id for op_id in op_ids]
if context.get('convert'):
ids = list(set(ids) - set(context.get('lead_ids', False)) )
lead_obj = self.pool.get('crm.lead')
op_id = lead_obj.search(cr, uid, [('id', 'in', ids)], order='create_date' , context=context)
if not op_id:
return False
opps = lead_obj.browse(cr, uid, [op_id[0]], context=context)
return opps[0]
def _update_data(self, op_ids, oldest_opp):
data = {
'partner_id': self._get_first_not_null_id('partner_id', op_ids, oldest_opp), # !!
'title': self._get_first_not_null_id('title', op_ids, oldest_opp),
'name' : self._get_first_not_null('name', op_ids, oldest_opp), #not lost
'categ_id' : self._get_first_not_null_id('categ_id', op_ids, oldest_opp), # !!
'channel_id' : self._get_first_not_null_id('channel_id', op_ids, oldest_opp), # !!
'city' : self._get_first_not_null('city', op_ids, oldest_opp), # !!
'company_id' : self._get_first_not_null_id('company_id', op_ids, oldest_opp), #!!
'contact_name' : self._get_first_not_null('contact_name', op_ids, oldest_opp), #not lost
'country_id' : self._get_first_not_null_id('country_id', op_ids, oldest_opp), #!!
'partner_address_id' : self._get_first_not_null_id('partner_address_id', op_ids, oldest_opp), #!!
'type_id' : self._get_first_not_null_id('type_id', op_ids, oldest_opp), #!!
'user_id' : self._get_first_not_null_id('user_id', op_ids, oldest_opp), #!!
'section_id' : self._get_first_not_null_id('section_id', op_ids, oldest_opp), #!!
'state_id' : self._get_first_not_null_id('state_id', op_ids, oldest_opp),
'description' : self._concat_all('description', op_ids), #not lost
'email' : self._get_first_not_null('email', op_ids, oldest_opp), # !!
'fax' : self._get_first_not_null('fax', op_ids, oldest_opp),
'mobile' : self._get_first_not_null('mobile', op_ids, oldest_opp),
'partner_name' : self._get_first_not_null('partner_name', op_ids, oldest_opp),
'phone' : self._get_first_not_null('phone', op_ids, oldest_opp),
'probability' : self._get_first_not_null('probability', op_ids, oldest_opp),
'planned_revenue' : self._get_first_not_null('planned_revenue', op_ids, oldest_opp),
'street' : self._get_first_not_null('street', op_ids, oldest_opp),
'street2' : self._get_first_not_null('street2', op_ids, oldest_opp),
'zip' : self._get_first_not_null('zip', op_ids, oldest_opp),
'state' : 'open',
'create_date' : self._get_first_not_null('create_date', op_ids, oldest_opp),
'date_action_last': self._get_first_not_null('date_action_last', op_ids, oldest_opp),
'date_action_next': self._get_first_not_null('date_action_next', op_ids, oldest_opp),
'email_from' : self._get_first_not_null('email_from', op_ids, oldest_opp),
'email_cc' : self._get_first_not_null('email_cc', op_ids, oldest_opp),
'partner_name' : self._get_first_not_null('partner_name', op_ids, oldest_opp),
}
return data
def merge(self, cr, uid, op_ids, context=None):
"""
:param opp_ids: list of opportunities ids to merge
"""
opp_obj = self.pool.get('crm.lead')
message_obj = self.pool.get('mail.message')
lead_ids = context and context.get('lead_ids', []) or []
if len(op_ids) <= 1:
raise osv.except_osv(_('Warning !'),_('Please select more than one opportunities.'))
opportunities = opp_obj.browse(cr, uid, lead_ids, context=context)
opportunities_list = list(set(op_ids) - set(opportunities))
oldest_opp = self.find_oldest(cr, uid, op_ids, context=context)
if opportunities :
first_opportunity = opportunities[0]
tail_opportunities = opportunities_list
else:
first_opportunity = opportunities_list[0]
tail_opportunities = opportunities_list[1:]
data = self._update_data(op_ids, oldest_opp)
#copy message into the first opportunity + merge attachement
count = 1
first_attachments = self.get_attachments(cr, uid, first_opportunity, context=context)
for opp in tail_opportunities:
attachments = self.get_attachments(cr, uid, opp, context=context)
for first in first_attachments:
for attachment in attachments:
if attachment.name == first.name:
values = dict(
name = "%s (%s)" % (attachment.name, count,),
res_id = first_opportunity.id,
)
attachment.write(values)
count+=1
for history in opp.message_ids:
message_obj.write(cr, uid, history.id, {'res_id': first_opportunity.id, 'subject' : _("From %s : %s") % (opp.name, history.subject) }, context=context)
#Notification about loss of information
details = []
subject = ['Merged opportunities :']
for opp in op_ids:
subject.append(opp.name)
details.append(_('Merged Opportunity: %s\n Partner: %s\n Stage: %s\n Section: %s\n Salesman: %s\n Category: %s\n Channel: %s\n Company: %s\n Contact name: %s\n Email: %s\n Phone number: %s\n Fax: %s\n Mobile: %s\n State: %s\n Description: %s\n Probability: %s\n Planned revennue: %s\n Country: %s\n City: %s\n Street: %s\n Street 2: %s\n Zip 2: %s') % ( opp.name, opp.partner_id.name or '',
opp.stage_id.name or '',
opp.section_id.name or '',
opp.user_id.name or '',
opp.categ_id.name or '',
opp.channel_id.name or '',
opp.company_id.name or '',
opp.contact_name or '',
opp.email_from or '',
opp.phone or '',
opp.fax or '',
opp.mobile or '',
opp.state_id.name or '',
opp.description or '',
opp.probability or '',
opp.planned_revenue or '',
opp.country_id.name or '',
opp.city or '',
opp.street or '',
opp.street2 or '',
opp.zip or '',
))
subject = subject[0] + ", ".join(subject[1:])
details = "\n\n".join(details)
opp_obj.message_append(cr, uid, [first_opportunity], subject, body_text=details)
#data.update({'message_ids' : [(6, 0 ,self._concat_o2m('message_ids', op_ids))]})
opp_obj.write(cr, uid, [first_opportunity.id], data, context=context)
unlink_ids = map(lambda x: x.id, tail_opportunities)
opp_obj.unlink(cr, uid, unlink_ids, context=context)
models_data = self.pool.get('ir.model.data')
# Get Opportunity views
opportunity_view_form = models_data._get_id(
cr, uid, 'crm', 'crm_case_form_view_oppor')
opportunity_view_tree = models_data._get_id(
cr, uid, 'crm', 'crm_case_tree_view_oppor')
if opportunity_view_form:
opportunity_view_form = models_data.browse(
cr, uid, opportunity_view_form, context=context).res_id
if opportunity_view_tree:
opportunity_view_tree = models_data.browse(
cr, uid, opportunity_view_tree, context=context).res_id
return {
'name': _('Opportunity'),
'view_type': 'form',
'view_mode': 'tree, form',
'res_model': 'crm.lead',
'domain': [('type', '=', 'opportunity')],
'res_id': int(first_opportunity.id),
'view_id': False,
'views': [(opportunity_view_form, 'form'),
(opportunity_view_tree, 'tree'),
(False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window',
}
def action_merge(self, cr, uid, ids, context=None):
obj_opportunity = self.browse(cr, uid, ids[0], context=context)
op_ids = obj_opportunity.opportunity_ids
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [op_ids[0].id])]}, context=context)
context['lead_ids'] = [op_ids[0].id]
return self.merge(cr, uid, op_ids, context)
lead = self.pool.get('crm.lead')
record = self.browse(cr, uid, ids[0], context=context)
opportunities = record.opportunity_ids
#TOFIX: why need to check lead_ids here
lead_ids = [opportunities[0].id]
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, lead_ids)]}, context=context)
context['lead_ids'] = lead_ids
merge_id = lead.merge_opportunity(cr, uid, [x.id for x in opportunities], context=context)
return lead.redirect_opportunity_view(cr, uid, merge_id, context=context)
_columns = {
'opportunity_ids' : fields.many2many('crm.lead', 'merge_opportunity_rel', 'merge_id', 'opportunity_id', 'Opportunities', domain=[('type', '=', 'opportunity')]),
@ -223,13 +44,6 @@ class crm_merge_opportunity(osv.osv_memory):
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : default values of fields.
"""
record_ids = context and context.get('active_ids', False) or False
res = super(crm_merge_opportunity, self).default_get(cr, uid, fields, context=context)

View File

@ -28,36 +28,11 @@ import time
class crm_opportunity2phonecall(osv.osv_memory):
"""Converts Opportunity to Phonecall"""
_inherit = 'crm.phonecall2phonecall'
_name = 'crm.opportunity2phonecall'
_description = 'Opportunity to Phonecall'
_columns = {
'name' : fields.char('Call summary', size=64, required=True, select=1),
'user_id' : fields.many2one('res.users', "Assign To"),
'contact_name':fields.char('Contact', size=64),
'phone':fields.char('Phone', size=64),
'partner_id' : fields.many2one('res.partner', "Partner"),
'date': fields.datetime('Date'),
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="['|',('section_id','=',False),('section_id','=',section_id),\
('object_id.model', '=', 'crm.phonecall')]"),
'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
'note':fields.text('Note'),
}
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : default values of fields.
"""
opp_obj = self.pool.get('crm.lead')
categ_id = False
data_obj = self.pool.get('ir.model.data')
@ -66,8 +41,8 @@ class crm_opportunity2phonecall(osv.osv_memory):
categ_id = data_obj.browse(cr, uid, res_id, context=context).res_id
record_ids = context and context.get('active_ids', []) or []
res = super(crm_opportunity2phonecall, self).default_get(cr, uid, fields, context=context)
res.update({'action': 'log', 'date': time.strftime('%Y-%m-%d %H:%M:%S')})
res = {}
res.update({'action': 'schedule', 'date': time.strftime('%Y-%m-%d %H:%M:%S')})
for opp in opp_obj.browse(cr, uid, record_ids, context=context):
if 'name' in fields:
res.update({'name': opp.name})
@ -87,84 +62,20 @@ class crm_opportunity2phonecall(osv.osv_memory):
res.update({'phone': opp.phone or (opp.partner_address_id and opp.partner_address_id.phone or False)})
return res
def action_cancel(self, cr, uid, ids, context=None):
"""
Closes Opportunity to Phonecall form
@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 Opportunity to Phonecall's IDs
@param context: A standard dictionary for contextual values
"""
return {'type': 'ir.actions.act_window_close'}
def action_apply(self, cr, uid, ids, context=None):
"""
This converts Opportunity to Phonecall and opens Phonecall view
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current user's ID for security checks,
@param ids: List of Opportunity to Phonecall IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for created Opportunity form
"""
def action_schedule(self, cr, uid, ids, context=None):
value = {}
record_ids = context and context.get('active_ids', []) or []
phonecall_obj = self.pool.get('crm.phonecall')
opp_obj = self.pool.get('crm.lead')
mod_obj = self.pool.get('ir.model.data')
result = mod_obj._get_id(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
res = mod_obj.read(cr, uid, result, ['res_id'])
data_obj = self.pool.get('ir.model.data')
# Select the view
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_tree_view')
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_form_view')
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
for this in self.browse(cr, uid, ids, context=context):
for opp in opp_obj.browse(cr, uid, record_ids, context=context):
vals = {
'name' : opp.name,
'case_id' : opp.id,
'user_id' : this.user_id and this.user_id.id or False,
'categ_id' : this.categ_id.id,
'description' : opp.description or False,
'date' : this.date,
'section_id' : this.section_id.id or False,
'partner_id': opp.partner_id and opp.partner_id.id or False,
'partner_address_id': opp.partner_address_id and opp.partner_address_id.id or False,
'partner_phone' : opp.phone or (opp.partner_address_id and opp.partner_address_id.phone or False),
'partner_mobile' : opp.partner_address_id and opp.partner_address_id.mobile or False,
'priority': opp.priority,
'opportunity_id': opp.id,
'date_open': time.strftime('%Y-%m-%d %H:%M:%S')
}
new_case = phonecall_obj.create(cr, uid, vals, context=context)
if this.action == 'log':
phonecall_obj.case_close(cr, uid, [new_case])
return {'type': 'ir.actions.act_window_close'}
value = {
'name': _('Phone Call'),
'domain': "[('user_id','=',%s),('opportunity_id','=',%s)]" % (uid,opp.id),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'crm.phonecall',
'res_id' : new_case,
'views': [(id3, 'form'), (id2, 'tree'), (False, 'calendar')],
'type': 'ir.actions.act_window',
'search_view_id': res['res_id'],
}
return value
if context is None:
context = {}
phonecall = self.pool.get('crm.phonecall')
opportunity_ids = context and context.get('active_ids') or []
opportunity = self.pool.get('crm.lead')
data = self.browse(cr, uid, ids, context=context)[0]
call_ids = opportunity.schedule_phonecall(cr, uid, opportunity_ids, data.date, data.name, \
data.note, data.phone, data.contact_name, data.user_id and data.user_id.id or False, \
data.section_id and data.section_id.id or False, \
data.categ_id and data.categ_id.id or False, \
action=data.action, context=context)
return phonecall.redirect_phonecall_view(cr, uid, call_ids[opportunity_ids[0]], context=context)
crm_opportunity2phonecall()

View File

@ -16,24 +16,19 @@
<field name="name"/>
<field name="date" string="Planned Date" attrs="{'invisible': [('action','=','log')]}"/>
<newline/>
<group colspan="4">
<field name="partner_id" readonly="True"/>
<field name="categ_id" string="Type" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<field name="contact_name"/>
<field name="phone"/>
</group>
<group colspan="4">
<field name="user_id" attrs="{'invisible': [('action','=','log')]}"/>
<field name="section_id" widget="selection" attrs="{'invisible': [('action','=','log')]}"/>
</group>
<group colspan="4">
<field name="note"/>
</group>
<field name="partner_id" readonly="True"/>
<field name="categ_id" string="Type" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<field name="contact_name"/>
<field name="phone"/>
<field name="user_id" attrs="{'invisible': [('action','=','log')]}"/>
<field name="section_id" widget="selection" attrs="{'invisible': [('action','=','log')]}"/>
<separator string="Notes" colspan="4"/>
<field name="note" colspan="4" nolabel="1"/>
<separator string="" colspan="4"/>
<group colspan="4" col="3">
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
<button name="action_apply" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
<button name="action_apply" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
<button name="action_schedule" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
<button name="action_schedule" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
</group>
</form>
</field>

View File

@ -35,16 +35,15 @@ class crm_partner2opportunity(osv.osv_memory):
'partner_id': fields.many2one('res.partner', 'Partner'),
}
def action_cancel(self, cr, uid, ids, context=None):
"""
Closes Partner 2 Opportunity
"""
return {'type':'ir.actions.act_window_close'}
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : default values of fields.
"""
partner_obj = self.pool.get('res.partner')
data = context and context.get('active_ids', []) or []
@ -58,56 +57,17 @@ class crm_partner2opportunity(osv.osv_memory):
return res
def make_opportunity(self, cr, uid, ids, context=None):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
"""
data = context and context.get('active_ids', []) or []
make_opportunity = self.pool.get('crm.partner2opportunity')
data_obj = self.pool.get('ir.model.data')
part_obj = self.pool.get('res.partner')
categ_obj = self.pool.get('crm.case.categ')
case_obj = self.pool.get('crm.lead')
for make_opportunity_obj in make_opportunity.browse(cr, uid, ids, context=context):
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_opportunities_filter')
res = data_obj.read(cr, uid, result, ['res_id'])
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_oppor')
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_oppor')
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
address = part_obj.address_get(cr, uid, data)
categ_ids = categ_obj.search(cr, uid, [('object_id.model','=','crm.lead')])
opp_id = case_obj.create(cr, uid, {
'name' : make_opportunity_obj.name,
'planned_revenue' : make_opportunity_obj.planned_revenue,
'probability' : make_opportunity_obj.probability,
'partner_id' : make_opportunity_obj.partner_id.id,
'partner_address_id' : address['default'],
'categ_id' : categ_ids and categ_ids[0] or '',
'state' :'draft',
'type': 'opportunity'
})
value = {
'name' : _('Opportunity'),
'view_type' : 'form',
'view_mode' : 'form,tree',
'res_model' : 'crm.lead',
'res_id' : opp_id,
'view_id' : False,
'views' : [(id2, 'form'), (id3, 'tree'), (False, 'calendar'), (False, 'graph')],
'type' : 'ir.actions.act_window',
'search_view_id' : res['res_id']
}
return value
partner_ids = context and context.get('active_ids', []) or []
partner = self.pool.get('res.partner')
lead = self.pool.get('crm.lead')
data = self.browse(cr, uid, ids, context=context)[0]
opportunity_ids = partner.make_opportunity(cr, uid, partner_ids,
data.name,
data.planned_revenue,
data.probability,
)
opportunity_id = opportunity_ids[partner_ids[0]]
return lead.redirect_opportunity_view(cr, uid, opportunity_id, context=context)
crm_partner2opportunity()

View File

@ -16,7 +16,7 @@
<field name="probability"/>
<separator string="" colspan="4" />
<group col="4" colspan="4">
<button special="cancel" string="_Cancel" icon="gtk-cancel"/>
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
<button name="make_opportunity" string="Create Opportunity" type="object" icon="gtk-ok"/>
</group>
</form>

View File

@ -26,97 +26,31 @@ class crm_phonecall2opportunity(osv.osv_memory):
""" Converts Phonecall to Opportunity"""
_name = 'crm.phonecall2opportunity'
_inherit = 'crm.partner2opportunity'
_description = 'Phonecall To Opportunity'
def action_cancel(self, cr, uid, ids, context=None):
"""
Closes Phonecall to Opportunity form
"""
return {'type':'ir.actions.act_window_close'}
def action_apply(self, cr, uid, ids, context=None):
def make_opportunity(self, cr, uid, ids, context=None):
"""
This converts Phonecall to Opportunity and opens Phonecall view
"""
record_id = context and context.get('active_id', False) or False
if record_id:
opp_obj = self.pool.get('crm.lead')
phonecall_obj = self.pool.get('crm.phonecall')
case = phonecall_obj.browse(cr, uid, record_id, context=context)
data_obj = self.pool.get('ir.model.data')
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_opportunities_filter')
res = data_obj.read(cr, uid, result, ['res_id'])
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_oppor')
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_oppor')
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
for this in self.browse(cr, uid, ids, context=context):
address = None
if this.partner_id:
address_id = self.pool.get('res.partner').address_get(cr, uid, [this.partner_id.id])
if address_id['default']:
address = self.pool.get('res.partner.address').browse(cr, uid, address_id['default'], context=context)
new_opportunity_id = opp_obj.create(cr, uid, {
'name': this.name,
'planned_revenue': this.planned_revenue,
'probability': this.probability,
'partner_id': this.partner_id and this.partner_id.id or False,
'partner_address_id': address and address.id,
'phone': address and address.phone,
'mobile': address and address.mobile,
'section_id': case.section_id and case.section_id.id or False,
'description': case.description or False,
'phonecall_id': case.id,
'priority': case.priority,
'type': 'opportunity',
'phone': case.partner_phone or False,
})
vals = {
'partner_id': this.partner_id.id,
'opportunity_id' : new_opportunity_id,
}
phonecall_obj.write(cr, uid, [case.id], vals)
phonecall_obj.case_close(cr, uid, [case.id])
opp_obj.case_open(cr, uid, [new_opportunity_id])
value = {
'name': _('Opportunity'),
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'crm.lead',
'res_id': int(new_opportunity_id),
'view_id': False,
'views': [(id2, 'form'), (id3, 'tree'), (False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window',
'search_view_id': res['res_id']
}
return value
_columns = {
'name' : fields.char('Opportunity Summary', size=64, required=True, select=1),
'probability': fields.float('Success Probability'),
'planned_revenue': fields.float('Expected Revenue'),
'partner_id': fields.many2one('res.partner', 'Partner'),
}
if not len(ids):
return False
call_ids = context and context.get('active_ids', False) or False
this = self.browse(cr, uid, ids[0], context=context)
if not call_ids:
return {}
opportunity = self.pool.get('crm.lead')
phonecall = self.pool.get('crm.phonecall')
opportunity_ids = phonecall.convert_opportunity(cr, uid, call_ids, this.name, this.partner_id and this.partner_id.id or False, \
this.planned_revenue, this.probability, context=context)
return opportunity.redirect_opportunity_view(cr, uid, opportunity_ids[call_ids[0]], context=context)
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : default values of fields.
"""
record_id = context and context.get('active_id', False) or False
res = super(crm_phonecall2opportunity, self).default_get(cr, uid, fields, context=context)
res = {}
if record_id:
phonecall = self.pool.get('crm.phonecall').browse(cr, uid, record_id, context=context)

View File

@ -19,7 +19,7 @@
<group colspan="4" col="3" >
<label string=" " />
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
<button name="action_apply" type="object" string="_Convert" icon="gtk-convert" />
<button name="make_opportunity" type="object" string="_Convert" icon="gtk-convert" />
</group>
</form>
</field>

View File

@ -26,42 +26,12 @@ class crm_phonecall2partner(osv.osv_memory):
""" Converts phonecall to partner """
_name = 'crm.phonecall2partner'
_inherit = 'crm.lead2partner'
_description = 'Phonecall to Partner'
_columns = {
'action': fields.selection([('exist', 'Link to an existing partner'), \
('create', 'Create a new partner')], \
'Action', required=True),
'partner_id': fields.many2one('res.partner', 'Partner')
}
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
"""
phonecall_obj = self.pool.get('crm.phonecall')
rec_ids = context and context.get('active_ids', [])
for phonecall in phonecall_obj.browse(cr, uid, rec_ids, context=context):
if phonecall.partner_id:
raise osv.except_osv(_('Warning !'),
_('A partner is already defined on this phonecall.'))
def _select_partner(self, cr, uid, context=None):
"""
This function Searches for Partner from selected 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 fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : Partner id if any for selected phonecall.
"""
if context is None:
context = {}
@ -75,7 +45,7 @@ class crm_phonecall2partner(osv.osv_memory):
for phonecall in phonecall_obj.browse(cr, uid, rec_ids, context=context):
partner_ids = partner_obj.search(cr, uid, [('name', '=', phonecall.name or phonecall.name)])
if not partner_ids and phonecall.email_from:
address_ids = contact_obj.search(cr, uid, [('email', '=', phonecall.email_from)])
address_ids = contact_obj.search(cr, uid, ['|', ('phone', '=', phonecall.partner_phone), ('mobile','=',phonecall.partner_mobile)])
if address_ids:
addresses = contact_obj.browse(cr, uid, address_ids)
partner_ids = addresses and [addresses[0].partner_id.id] or False
@ -83,117 +53,20 @@ class crm_phonecall2partner(osv.osv_memory):
partner_id = partner_ids and partner_ids[0] or False
return partner_id
_defaults = {
'action': lambda *a:'exist',
'partner_id': _select_partner
}
def open_create_partner(self, cr, uid, ids, context=None):
"""
This function Opens form of create partner.
@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 Partner's IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for next form.
"""
view_obj = self.pool.get('ir.ui.view')
view_id = view_obj.search(cr, uid, [('model', '=', 'crm.phonecall2partner'), \
('name', '=', 'crm.phonecall2partner.view')])
return {
'view_mode': 'form',
'view_type': 'form',
'view_id': view_id or False,
'res_model': 'crm.phonecall2partner',
'context': context,
'type': 'ir.actions.act_window',
'target': 'new',
}
def _create_partner(self, cr, uid, ids, context=None):
"""
This function Creates partner based on action.
@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 Partner's IDs
@param context: A standard dictionary for contextual values
@return : Dictionary {}.
"""
if context is None:
context = {}
phonecall = self.pool.get('crm.phonecall')
phonecall_obj = self.pool.get('crm.phonecall')
partner_obj = self.pool.get('res.partner')
contact_obj = self.pool.get('res.partner.address')
partner_ids = []
contact_id = False
rec_ids = context and context.get('active_ids', [])
for data in self.browse(cr, uid, ids, context=context):
for phonecall in phonecall_obj.browse(cr, uid, rec_ids, context=context):
if data.action == 'create':
partner_id = partner_obj.create(cr, uid, {
'name': phonecall.name or phonecall.name,
'user_id': phonecall.user_id.id,
'comment': phonecall.description,
})
contact_id = contact_obj.create(cr, uid, {
'partner_id': partner_id,
'name': phonecall.name,
'phone': phonecall.partner_phone,
})
else:
if data.partner_id:
partner_id = data.partner_id.id
contact_id = partner_obj.address_get(cr, uid, [partner_id])['default']
partner_ids.append(partner_id)
vals = {}
if partner_id:
vals.update({'partner_id': partner_id})
if contact_id:
vals.update({'partner_address_id': contact_id})
phonecall_obj.write(cr, uid, [phonecall.id], vals)
return partner_ids
def make_partner(self, cr, uid, ids, context=None):
"""
This function Makes partner based on action.
@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 Partner's IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for created Partner form.
"""
partner_ids = self._create_partner(cr, uid, ids, context=context)
mod_obj = self.pool.get('ir.model.data')
result = mod_obj._get_id(cr, uid, 'base', 'view_res_partner_filter')
res = mod_obj.read(cr, uid, result, ['res_id'])
value = {
'domain': "[]",
'view_type': 'form',
'view_mode': 'form,tree',
'res_model': 'res.partner',
'res_id': partner_ids and int(partner_ids[0]) or False,
'view_id': False,
'context': context,
'type': 'ir.actions.act_window',
'search_view_id': res['res_id']
}
return value
data = self.browse(cr, uid, ids, context=context)[0]
call_ids = context and context.get('active_ids') or []
partner_id = data.partner_id and data.partner_id.id or False
partner_ids = phonecall.convert_partner(cr, uid, call_ids, data.action, partner_id, context=context)
return partner_ids[call_ids[0]]
crm_phonecall2partner()

View File

@ -25,108 +25,50 @@ from tools.translate import _
import time
class crm_phonecall2phonecall(osv.osv_memory):
""" Converts Phonecall to Phonecall"""
_name = 'crm.phonecall2phonecall'
_description = 'Phonecall To Phonecall'
_columns = {
'name' : fields.char('Call summary', size=64, required=True, select=1),
'user_id' : fields.many2one('res.users',"Assign To"),
'contact_name':fields.char('Contact', size=64),
'phone':fields.char('Phone', size=64),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="['|',('section_id','=',False),('section_id','=',section_id),\
('object_id.model', '=', 'crm.phonecall')]"),
'date': fields.datetime('Date'),
'section_id':fields.many2one('crm.case.section','Sales Team'),
'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
'partner_id' : fields.many2one('res.partner', "Partner"),
'note':fields.text('Note')
}
def action_cancel(self, cr, uid, ids, context=None):
"""
Closes Phonecall to Phonecall form
@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 Phonecall's IDs
@param context: A standard dictionary for contextual values
"""
return {'type':'ir.actions.act_window_close'}
def action_apply(self, cr, uid, ids, context=None):
"""
This converts Phonecall to Phonecall and opens Phonecall view
@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 Phonecall IDs
@param context: A standard dictionary for contextual values
@return : Dictionary value for created Opportunity form
"""
res = {}
record_id = context and context.get('active_id', False) or False
phonecall_obj = self.pool.get('crm.phonecall')
if record_id:
data_obj = self.pool.get('ir.model.data')
# Get Phonecall views
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
res = data_obj.read(cr, uid, result, ['res_id'])
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_form_view')
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_tree_view')
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
phonecall = phonecall_obj.browse(cr, uid, record_id, context=context)
for this in self.browse(cr, uid, ids, context=context):
values = {
'name': this.name,
'user_id': this.user_id and this.user_id.id,
'categ_id': this.categ_id.id,
'section_id': this.section_id.id or (phonecall.section_id and phonecall.section_id.id),
'description': phonecall.description or '',
'partner_id': phonecall.partner_id.id,
'partner_address_id': phonecall.partner_address_id.id,
'partner_mobile': phonecall.partner_mobile or False,
'priority': phonecall.priority,
'partner_phone': phonecall.partner_phone or False,
'date': this.date
}
phonecall_id = phonecall_obj.create(cr, uid, values, context=context)
if this.action == 'schedule':
phonecall_obj.case_open(cr, uid, [phonecall_id])
elif this.action == 'log':
phonecall_obj.case_close(cr, uid, [phonecall_id])
res = {
'name': _('Phone Call'),
'view_type': 'form',
'view_mode': 'form',
'res_model': 'crm.phonecall',
'view_id': False,
'views': [(id2, 'form'), (id3, 'tree'), (False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window',
'res_id': phonecall_id,
'domain': [('id', '=', phonecall_id)],
'search_view_id': res['res_id']
}
return res
_columns = {
'name' : fields.char('Call summary', size=64, required=True, select=1),
'user_id' : fields.many2one('res.users',"Assign To"),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
domain="['|',('section_id','=',False),('section_id','=',section_id),\
('object_id.model', '=', 'crm.phonecall')]"),
'date': fields.datetime('Date'),
'section_id':fields.many2one('crm.case.section','Sales Team'),
'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
'partner_id' : fields.many2one('res.partner', "Partner"),
}
def action_schedule(self, cr, uid, ids, context=None):
value = {}
if context is None:
context = {}
phonecall = self.pool.get('crm.phonecall')
phonecall_ids = context and context.get('active_ids') or []
for this in self.browse(cr, uid, ids, context=context):
phocall_ids = phonecall.schedule_another_phonecall(cr, uid, phonecall_ids, this.date, this.name, \
this.user_id and this.user_id.id or False, \
this.section_id and this.section_id.id or False, \
this.categ_id and this.categ_id.id or False, \
action=this.action, context=context)
return phonecall.redirect_phonecall_view(cr, uid, phocall_ids[phonecall_ids[0]], context=context)
def default_get(self, cr, uid, fields, context=None):
"""
This function gets default values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
@return : default values of fields.
"""
res = super(crm_phonecall2phonecall, self).default_get(cr, uid, fields, context=context)
record_id = context and context.get('active_id', False) or False

View File

@ -22,8 +22,8 @@
<separator string=" " colspan="4"/>
<group colspan="4" col="3" >
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
<button name="action_apply" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
<button name="action_apply" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
<button name="action_schedule" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
<button name="action_schedule" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
</group>
</form>
</field>

View File

@ -48,7 +48,9 @@ automatically new claims based on incoming emails.
'demo_xml': [
'crm_claim_demo.xml',
],
'test': ['test/test_crm_claim.yml'],
'test': ['test/process/claim.yml',
'test/ui/claim_demo.yml'
],
'installable': True,
'active': False,
'certificate' : '00612027414703404749',

View File

@ -46,6 +46,7 @@ class crm_claim(crm.crm_case, osv.osv):
_columns = {
'id': fields.integer('ID', readonly=True),
'name': fields.char('Claim Subject', size=128, required=True),
'active': fields.boolean('Active'),
'action_next': fields.char('Next Action', size=200),
'date_action_next': fields.datetime('Next Action Date'),
'description': fields.text('Description'),
@ -95,6 +96,7 @@ class crm_claim(crm.crm_case, osv.osv):
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
'active': lambda *a: 1
}
def onchange_partner_id(self, cr, uid, ids, part, email=False):
@ -129,8 +131,6 @@ class crm_claim(crm.crm_case, osv.osv):
if l.state == 'draft':
message = _("The claim '%s' has been opened.") % l.name
self.log(cr, uid, l.id, message)
value = {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')}
self.write(cr, uid, [l.id], value)
stage_id = self.stage_find(cr, uid, l.section_id.id or False, [('sequence','>',0)])
if stage_id:
self.stage_set(cr, uid, [l.id], stage_id)

View File

@ -15,8 +15,6 @@
<field eval="&quot;Problem with the delivery of goods&quot;" name="name"/>
<field eval="&quot;open&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot;(726) 782-0636&quot;" name="partner_mobile"/>
<field eval="1" name="active"/>
<field name="categ_id" ref="crm_claim.categ_claim1"/>
<field name="stage_id" ref="crm_claim.stage_claim1"/>
<field eval="&quot;(769) 703-274&quot;" name="partner_phone"/>
@ -31,8 +29,6 @@
<field eval="&quot;Damaged Products&quot;" name="name"/>
<field eval="&quot;open&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot;(392) 895-7917&quot;" name="partner_mobile"/>
<field eval="1" name="active"/>
<field name="categ_id" ref="crm_claim.categ_claim2"/>
<field name="stage_id" ref="crm_claim.stage_claim5"/>
<field eval="&quot;(956) 293-2595&quot;" name="partner_phone"/>
@ -47,8 +43,6 @@
<field eval="&quot;Document related problems&quot;" name="name"/>
<field eval="&quot;done&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot;(820) 167-3208&quot;" name="partner_mobile"/>
<field eval="1" name="active"/>
<field name="categ_id" ref="crm_claim.categ_claim3"/>
<field name="stage_id" ref="crm_claim.stage_claim2"/>
<field eval="&quot;(079) 681-2139&quot;" name="partner_phone"/>
@ -63,8 +57,6 @@
<field eval="&quot;Product quality not maintained&quot;" name="name"/>
<field eval="&quot;draft&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot;(077) 582-4035&quot;" name="partner_mobile"/>
<field eval="1" name="active"/>
<field name="categ_id" ref="crm_claim.categ_claim1"/>
<field name="stage_id" ref="crm_claim.stage_claim5"/>
<field eval="&quot;(514) 698-4118&quot;" name="partner_phone"/>
@ -79,8 +71,6 @@
<field eval="&quot;Some products missing&quot;" name="name"/>
<field eval="&quot;pending&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot;(333) 715-1450&quot;" name="partner_mobile"/>
<field eval="1" name="active"/>
<field name="categ_id" ref="crm_claim.categ_claim3"/>
<field name="stage_id" ref="crm_claim.stage_claim3"/>
<field eval="&quot;(855) 924-4364&quot;" name="partner_phone"/>
@ -88,14 +78,12 @@
<record id="crm_case_claim06" model="crm.claim">
<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;Problem with the delivery of assignments&quot;" name="name"/>
<field eval="&quot;cancel&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot;(468) 017-2684&quot;" name="partner_mobile"/>
<field eval="time.strftime('%Y-%m-28 14:15:30')" name="date"/>
<field name="categ_id" ref="crm_claim.categ_claim1"/>
<field name="stage_id" ref="crm_claim.stage_claim5"/>
@ -104,14 +92,12 @@
</record>
<record id="crm_case_claims07" model="crm.claim">
<field eval="1" name="active"/>
<field name="partner_id" ref="base.res_partner_seagate"/>
<field eval="&quot;3&quot;" name="priority"/>
<field name="user_id" ref="base.user_root"/>
<field eval="&quot;Documents unclear&quot;" name="name"/>
<field eval="&quot;done&quot;" name="state"/>
<field name="section_id" ref="crm.section_sales_department"/>
<field eval="&quot; (463) 014-1208&quot;" name="partner_mobile"/>
<field eval="time.strftime('%Y-%m-19 13:01:05')" name="date"/>
<field name="categ_id" ref="crm_claim.categ_claim3"/>
<field name="stage_id" ref="crm_claim.stage_claim2"/>

View File

@ -0,0 +1,17 @@
Message-ID: <4EA66F25.7080001@customer.com>
Date: Tue, 25 Oct 2011 13:41:17 +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: claims@my.com
Subject: demande de =?ISO-8859-1?Q?r=E8glement_de_votre_produit=2E?=
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit
J'ai acheté votre produit il ya quelques jours. maintenant certains
problèmes sont survenus sur votre produit.
je demande donc à convertir cette demande que la réclamation et de
résoudre les problèmes le plus tôt possible.
Merci

View File

@ -0,0 +1,46 @@
-
Customer requests a claim after the sale of our product. He sends claim request by email.
-
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_claim','test', 'customer_claim.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.claim', request_message)
-
After getting the mail, I check details of new claim of that customer.
-
!python {model: crm.claim}: |
from openerp import tools
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
assert claim_ids and len(claim_ids), "Claim is not created after getting request"
claim = self.browse(cr, uid, claim_ids[0], context=context)
assert claim.name == tools.ustr("demande derèglement de votre produit."), "Subject does not match"
-
I open customer claim.
-
!python {model: crm.claim}: |
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
self.case_open(cr, uid, claim_ids)
-
I check Claim Details after open.
-
!python {model: crm.claim}: |
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
claim = self.browse(cr, uid, claim_ids[0])
assert claim.state == "open", "Claim is not in Open state"
assert claim.stage_id.id == ref("crm.stage_lead1"), "Claim is not in New stage"
-
After complete all service from our side, I close this claim.
-
!python {model: crm.claim}: |
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
self.case_close(cr, uid, claim_ids)
-
I check Claim details after closed.
-
!python {model: crm.claim}: |
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
claim = self.browse(cr, uid, claim_ids[0])
assert claim.state == "done", "Claim is not in close state"

View File

@ -1,44 +0,0 @@
- |
I check claims which contain customer claim information about document
related problem, product related problem.
- |
I start by creating new claims for Damaged product as Value Claims with priority High and specify
date of claim at which claim is created.
-
!record {model: crm.claim, id: crm_claim_damagedproduct0}:
categ_id: crm_claim.categ_claim2
date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
email_from: info@balmerinc.be
name: 'Damaged product '
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
priority: '2'
section_id: crm.section_sales_department
- |
I check that the claims is in 'draft' state.
-
!assert {model: crm.claim, id: crm_claim_damagedproduct0}:
- state == 'draft'
- |
I can change that stage by next button right on it.
-
!python {model: crm.claim}: |
self.stage_next(cr, uid, [ref('crm_claim_damagedproduct0')])
- |
I make this claim as Open.
-
!python {model: crm.claim}: |
self.case_open(cr, uid, [ref('crm_claim_damagedproduct0')])
- |
I am changing partner Assigned to the Claim.
-
!python {model: crm.claim}: |
self.onchange_partner_id(cr, uid, [ref('crm_claim_damagedproduct0')], [])
self.onchange_partner_id(cr, uid, [ref('crm_claim_damagedproduct0')], ref('base.res_partner_10'))
- |
I am changing partner Address to the Claim.
-
!python {model: crm.claim}: |
self.onchange_partner_address_id(cr, uid, [ref('crm_claim_damagedproduct0')], [], email = False)

View File

@ -0,0 +1,15 @@
-
I create claim record to call of partner onchange method.
-
!record {model: crm.claim, id: crm_case_claim04}:
name: 'Damaged Product'
partner_id: base.res_partner_6
-
I Update the message for claim.
-
!python {model: crm.claim}: |
try:
self.message_update(cr, uid,[ref('crm_case_claim04')], {'subject': 'Claim Update record','body_text': 'first training session completed',})
except:
pass

View File

@ -51,7 +51,7 @@ fund status.
'demo_xml': [
'crm_fundraising_demo.xml',
],
'test': ['test/test_crm_fund.yml'],
'test': ['test/process/fund-rising.yml'],
'installable': True,
'active': False,
'certificate' : '00871545204231528989',

View File

@ -97,6 +97,7 @@ class crm_fundraising_report(osv.osv):
avg(extract('epoch' from (c.date_closed-c.create_date)))/(3600*24) as delay_close
from
crm_fundraising c
where c.active = 'true'
group by to_char(c.date, 'YYYY'), to_char(c.date, 'MM'),\
c.state, c.user_id,c.section_id,c.categ_id,type_id,c.partner_id,c.company_id,
c.create_date,to_char(c.date, 'YYYY-MM-DD')

View File

@ -0,0 +1,14 @@
Message-ID: <4EA66F25.7080010@customer.com>
Date: Tue, 25 Oct 2011 13:41:17 +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: contribute@my.com
Subject: Demande de controbute dans votre fonds.
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit
Client est très heureux d'utiliser notre produit et il l'intérêt de donner une partie des fonds dans notre produit. Il a donc envoyé la demande par courriel pour les collectes de fonds.
Merci

View File

@ -0,0 +1,19 @@
-
Customer is very happy with our service and he interest to contribute into our fund. so He sent request by email for Fundraising.
-
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_fundraising','test', 'customer_fundraising.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.fundraising', request_message)
-
After getting the mail, I check details of new fundraising of that customer.
-
!python {model: crm.fundraising}: |
from openerp import tools
fund_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
assert fund_ids and len(fund_ids), "Fund is not created after getting request"
fund = self.browse(cr, uid, fund_ids[0], context=context)
assert fund.name == tools.ustr("Demande de controbute dans votre fonds."), "Subject does not match"

View File

@ -1,45 +0,0 @@
- |
I start test Fund Raising which contain information about Donation or charity
given by user.
- |
I start by creating new Funds entry for donation for books to poor school children
with cost 500000.00 and category as "Learning And Education"
I make payment by Cheque so I make sure that the mode on fund is selected as cheque.
-
!record {model: crm.fundraising, id: crm_fundraising_donationforbookstopoorschoolchildren0}:
categ_id: crm_fundraising.categ_fund2
email_from: info@balmerinc.be
name: Donation for books to poor school children
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
planned_cost: 500000.0
section_id: crm.section_sales_department
type_id: crm_fundraising.type_fund2
- |
I check that the Funds is in 'draft' state.
-
!assert {model: crm.fundraising, id: crm_fundraising_donationforbookstopoorschoolchildren0}:
- state == 'draft'
- |
I open Funds by click on "Open" button.
-
!python {model: crm.fundraising}: |
self.case_open(cr, uid, [ref('crm_fundraising_donationforbookstopoorschoolchildren0')])
-
I create the message regarding the all details of fundraising.
-
!python {model: crm.fundraising}: |
msg = {
'subject': 'fundraising_email',
'body_text': 'fundraising details',
'from': 'Administrator <admin@openerp.com>',
'priority':'3',
}
context = None
self.message_new(cr, uid,msg,context)
- |
After a request via email now I close this fundraising Request by clicking on "Done" button.
-
!python {model: crm.fundraising}: |
self.case_close(cr, uid, [ref('crm_fundraising_donationforbookstopoorschoolchildren0')])

View File

@ -49,7 +49,7 @@ and categorize your interventions with a channel and a priority level.
'demo_xml': [
'crm_helpdesk_demo.xml',
],
'test': ['test/test_crm_helpdesk.yml'],
'test': ['test/process/help-desk.yml'],
'installable': True,
'active': False,
'certificate' : '00830691522781519309',

View File

@ -101,6 +101,7 @@ class crm_helpdesk_report(osv.osv):
abs(avg(extract('epoch' from (c.date_deadline - c.date_closed)))/(3600*24)) as delay_expected
from
crm_helpdesk c
where c.active = 'true'
group by to_char(c.date, 'YYYY'), to_char(c.date, 'MM'),to_char(c.date, 'YYYY-MM-DD'),\
c.state, c.user_id,c.section_id,c.priority,\
c.partner_id,c.company_id,c.date_deadline,c.create_date,c.date,c.date_closed,\

View File

@ -0,0 +1,15 @@
Message-ID: <4EA66F25.7080013@customer.com>
Date: Tue, 25 Oct 2011 13:41:17 +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: info@my.com
Subject: Where is download link of user manual of your product ?
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8bit
I want to download user manual of your product.
can you provide download link?
Thanks

View File

@ -0,0 +1,30 @@
-
Customer has Questions regarding our service. so He sent questions list by email.
-
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_helpdesk','test', 'customer_question.eml'),'rb')
request_message = request_file.read()
self.message_process(cr, uid, 'crm.helpdesk', request_message)
-
After getting the mail, I check details of new question of that customer.
-
!python {model: crm.helpdesk}: |
from openerp import tools
question_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
assert question_ids and len(question_ids), "Question is not created after getting request"
question = self.browse(cr, uid, question_ids[0], context=context)
assert question.name == tools.ustr("Where is download link of user manual of your product ? "), "Subject does not match"
-
Now I Update message according to provide services.
-
!python {model: crm.helpdesk}: |
question_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
try:
self.message_update(cr, uid, question_ids, {'subject': 'Link of product', 'body_text': 'www.openerp.com'})
except:
pass

View File

@ -1,57 +0,0 @@
-
|
I start by creating New helpdesk request regarding some functional questions.
I select Date at which helpdesk request is created.
-
!record {model: crm.helpdesk, id: crm_helpdesk_somefunctionalquestion0}:
date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
email_from: info@balmerinc.be
name: Some functional question.
partner_address_id: base.res_partner_address_1
partner_id: base.res_partner_9
section_id: crm.section_sales_department
-
I create the message.
-
!python {model: crm.helpdesk}: |
msg = {
'subject': 'test_email',
'body_text': 'Testing',
'from': 'Administrator <admin@openerp.com>',
}
context = None
self.message_new(cr, uid,msg,context)
- |
I check that the Helpdesk request is in 'Draft' state.
-
!assert {model: crm.helpdesk, id: crm_helpdesk_somefunctionalquestion0}:
- state == 'draft'
- |
I make it "Open".
-
!python {model: crm.helpdesk}: |
self.case_open(cr, uid, [ref('crm_helpdesk_somefunctionalquestion0')])
-
Update the created message.
-
!python {model: crm.helpdesk}: |
vals = {}
msg = {
'subject': 'test_email',
'body_text': 'Testing',
'from': 'Administrator <admin@openerp.com>',
'priority': 'done'
}
context = None
default_act = 'pending'
try:
self.message_update(cr, uid,[ref('crm_helpdesk_somefunctionalquestion0')], msg,context)
except:
pass
- |
After a proper communication for the request via email I make sure that the request is fulfilled and
I close this HelpDesk Request by clicking on "Close" button.
-
!python {model: crm.helpdesk}: |
self.case_close(cr, uid, [ref('crm_helpdesk_somefunctionalquestion0')])

View File

@ -38,6 +38,9 @@ You can also use the geolocalization without using the GPS coordinates.
""",
'author': 'OpenERP SA',
'depends': ['crm'],
'demo_xml': [
'res_partner_demo.xml',
],
'update_xml': [
'security/ir.model.access.csv',
'res_partner_view.xml',
@ -46,7 +49,9 @@ You can also use the geolocalization without using the GPS coordinates.
'report/crm_lead_report_view.xml',
'report/crm_partner_report_view.xml',
],
'test': ['test/test_crm_partner_assign.yml'],
'test': [
'test/process/partner_assign.yml',
],
'installable': True,
'active': False,
'certificate': '00503409558942442061',

View File

@ -8,7 +8,7 @@
<field name="inherit_id" ref="crm.crm_case_form_view_oppor"/>
<field name="arch" type="xml">
<data>
<xpath expr="//notebook[last()]" position="inside">
<xpath expr="//notebook/page[@string='Lead']" position="after">
<page string="Assignation" groups="base.group_extended">
<group name="partner_assign_group" col="5" colspan="4">
<separator string="Partner Assignation" colspan="5"/>
@ -27,7 +27,7 @@
<field name="partner_latitude"/>
<field name="partner_longitude"/>
<group colspan="1" col="1">
<button string="Geo Assign" name="assign_partner" type="object" colspan="1"
<button string="Geo Assign" name="action_assign_partner" type="object" colspan="1"
icon="gtk-apply"/>
</group>
</group>

View File

@ -24,22 +24,25 @@ from osv import fields
import urllib,re
import random, time
from tools.translate import _
import tools
def geo_find(addr):
addr = addr.encode('utf8')
regex = '<coordinates>([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)</coordinates>'
url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false'
try:
regex = '<coordinates>([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)</coordinates>'
url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false'
xml = urllib.urlopen(url).read()
if '<error>' in xml:
return None
result = re.search(regex, xml, re.M|re.I)
if not result:
return None
return float(result.group(2)),float(result.group(1))
except Exception, e:
raise osv.except_osv(_('Network error'),
_('Could not contact geolocation servers, please make sure you have a working internet connection (%s)') % e)
if '<error>' in xml:
return None
result = re.search(regex, xml, re.M|re.I)
if not result:
return None
return float(result.group(2)),float(result.group(1))
class res_partner_grade(osv.osv):
_order = 'sequence'
@ -74,9 +77,13 @@ class res_partner(osv.osv):
for partner in self.browse(cr, uid, ids, context=context):
if not partner.address:
continue
part = partner.address[0]
addr = ', '.join(filter(None, [part.street, (part.zip or '')+' '+(part.city or ''), part.state_id and part.state_id.name, part.country_id and part.country_id.name]))
result = geo_find(addr.encode('utf8'))
contact = partner.address[0] #TOFIX: should be get latitude and longitude for default contact?
addr = ', '.join(filter(None, [
contact.street,
"%s %s" % (contact.zip , contact.city),
contact.state_id and contact.state_id.name,
contact.country_id and contact.country_id.name]))
result = geo_find(tools.ustr(addr))
if result:
self.write(cr, uid, [partner.id], {
'partner_latitude': result[0],
@ -94,14 +101,13 @@ class crm_lead(osv.osv):
'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner', help="Partner this case has been forwarded/assigned to.", select=True),
'date_assign': fields.date('Assignation Date', help="Last date this case was forwarded/assigned to a partner"),
}
def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
fields += ['partner_latitude', 'partner_longitude', 'partner_assigned_id', 'date_assign']
return super(crm_lead, self)._merge_data(cr, uid, ids, oldest, fields, context=context)
def onchange_assign_id(self, cr, uid, ids, partner_assigned_id, context=None):
"""This function updates the "assignation date" automatically, when manually assign a partner in the geo assign tab
@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 stages IDs
@stage_id: change state id on run time """
"""
if not partner_assigned_id:
return {'value':{'date_assign': False}}
else:
@ -112,73 +118,113 @@ class crm_lead(osv.osv):
'user_id' : user_id}
}
def assign_partner(self, cr, uid, ids, context=None):
ok = False
for part in self.browse(cr, uid, ids, context=context):
if not part.country_id:
continue
addr = ', '.join(filter(None, [part.street, (part.zip or '')+' '+(part.city or ''), part.state_id and part.state_id.name, part.country_id and part.country_id.name]))
result = geo_find(addr.encode('utf8'))
if result:
self.write(cr, uid, [part.id], {
'partner_latitude': result[0],
'partner_longitude': result[1]
}, context=context)
def action_assign_partner(self, cr, uid, ids, context=None):
return self.assign_partner(cr, uid, ids, partner_id=False, context=context)
def assign_partner(self, cr, uid, ids, partner_id=False, context=None):
partner_ids = {}
res = False
res_partner = self.pool.get('res.partner')
if not partner_id:
partner_ids = self.search_geo_partner(cr, uid, ids, context=context)
for lead in self.browse(cr, uid, ids, context=context):
if not partner_id:
partner_id = partner_ids.get(lead.id, False)
if not partner_id:
continue
self.assign_geo_localize(cr, uid, [lead.id], lead.partner_latitude, lead.partner_longitude, context=context)
partner = res_partner.browse(cr, uid, partner_id, context=context)
if partner.user_id:
for lead_id in ids:
self.allocate_salesman(cr, uid, [lead_id], [partner.user_id.id], context=context)
self.write(cr, uid, [lead.id], {'date_assign': time.strftime('%Y-%m-%d'), 'partner_assigned_id': partner_id}, context=context)
return res
def assign_geo_localize(self, cr, uid, ids, latitude=False, longitude=False, context=None):
for lead in self.browse(cr, uid, ids, context=context):
if not lead.country_id:
continue
addr = ', '.join(filter(None, [
lead.street,
"%s %s" % (lead.zip, lead.city),
lead.state_id and lead.state_id.name or '',
lead.country_id and lead.country_id.name or ''
]))
result = geo_find(tools.ustr(addr))
if not latitude and result:
latitude = result[0]
if not longitude and result:
longitude = result[1]
self.write(cr, uid, [lead.id], {
'partner_latitude': latitude,
'partner_longitude': longitude
}, context=context)
return True
def search_geo_partner(self, cr, uid, ids, context=None):
res_partner = self.pool.get('res.partner')
res_partner_ids = {}
self.assign_geo_localize(cr, uid, ids, context=context)
for lead in self.browse(cr, uid, ids, context=context):
partner_ids = []
if not lead.country_id:
continue
latitude = lead.partner_latitude
longitude = lead.partner_longitude
if latitude and longitude:
# 1. first way: in the same country, small area
part_ids = self.pool.get('res.partner').search(cr, uid, [
('partner_weight','>',0),
('partner_latitude','>',result[0]-2), ('partner_latitude','<',result[0]+2),
('partner_longitude','>',result[1]-1.5), ('partner_longitude','<',result[1]+1.5),
('country', '=', part.country_id.id),
partner_ids = res_partner.search(cr, uid, [
('partner_weight', '>', 0),
('partner_latitude', '>', latitude - 2), ('partner_latitude', '<', latitude + 2),
('partner_longitude', '>', longitude - 1.5), ('partner_longitude', '<', longitude + 1.5),
('country', '=', lead.country_id.id),
], context=context)
# 2. second way: in the same country, big area
if not part_ids:
part_ids = self.pool.get('res.partner').search(cr, uid, [
('partner_weight','>',0),
('partner_latitude','>',result[0]-4), ('partner_latitude','<',result[0]+4),
('partner_longitude','>',result[1]-3), ('partner_longitude','<',result[1]+3),
('country', '=', part.country_id.id),
if not partner_ids:
partner_ids = res_partner.search(cr, uid, [
('partner_weight', '>', 0),
('partner_latitude', '>', latitude - 4), ('partner_latitude', '<', latitude + 4),
('partner_longitude', '>', longitude - 3), ('partner_longitude', '<' , longitude + 3),
('country', '=', lead.country_id.id),
], context=context)
# 5. fifth way: anywhere in same country
if not part_ids:
if not partner_ids:
# still haven't found any, let's take all partners in the country!
part_ids = self.pool.get('res.partner').search(cr, uid, [
('partner_weight','>',0),
('country', '=', part.country_id.id),
partner_ids = res_partner.search(cr, uid, [
('partner_weight', '>', 0),
('country', '=', lead.country_id.id),
], context=context)
# 6. sixth way: closest partner whatsoever, just to have at least one result
if not part_ids:
if not partner_ids:
# warning: point() type takes (longitude, latitude) as parameters in this order!
cr.execute("""SELECT id, distance
FROM (select id, (point(partner_longitude, partner_latitude) <-> point(%s,%s)) AS distance FROM res_partner
WHERE partner_longitude is not null
AND partner_latitude is not null
AND partner_weight > 0) AS d
ORDER BY distance LIMIT 1""", (result[1],result[0]))
ORDER BY distance LIMIT 1""", (longitude, latitude))
res = cr.dictfetchone()
if res:
part_ids.append(res['id'])
partner_ids.append(res['id'])
total = 0
total_weight = 0
toassign = []
for part2 in self.pool.get('res.partner').browse(cr, uid, part_ids, context=context):
total += part2.partner_weight
toassign.append( (part2.id, total) )
for partner in res_partner.browse(cr, uid, partner_ids, context=context):
total_weight += partner.partner_weight
toassign.append( (partner.id, total_weight) )
random.shuffle(toassign) # avoid always giving the leads to the first ones in db natural order!
mypartner = random.randint(0,total)
for t in toassign:
if mypartner<=t[1]:
vals = self.onchange_assign_id(cr,uid, ids, t[0], context=context)['value']
vals.update({'partner_assigned_id': t[0], 'date_assign': time.strftime('%Y-%m-%d')})
self.write(cr, uid, [part.id], vals, context=context)
nearest_weight = random.randint(0, total_weight)
for partner_id, weight in toassign:
if nearest_weight <= weight:
res_partner_ids[lead.id] = partner_id
break
ok = True
return ok
return res_partner_ids
crm_lead()

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="res_partner_grade_first" model="res.partner.grade">
<field name="name">First</field>
<field name="sequence">1</field>
</record>
<record id="base.res_partner_ericdubois0" model="res.partner">
<field name="grade_id" ref="res_partner_grade_first"/>
<field name="partner_weight">10</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,37 @@
-
In order to test find nearest Partner functionality and assign to opportunity ,
-
I Set Geo Lattitude and Longitude according to partner address.
-
!python {model: res.partner}: |
self.geo_localize(cr, uid, [ref('base.res_partner_ericdubois0')], context)
-
I check Geo Latitude and Longitude of partner after set
-
!python {model: res.partner}: |
partner = self.browse(cr, uid, ref('base.res_partner_ericdubois0'))
assert partner.partner_latitude == 50.4530495 , "Latitude is wrong"
assert partner.partner_longitude == 3.9693885 , "Longitude is wrong"
-
I assign nearest partner to opportunity.
-
!python {model: crm.lead}: |
self.assign_partner(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], context=context)
-
I check assigned partner of opportunity who is nearest Geo Latitude and Longitude of opportunity.
-
!python {model: crm.lead}: |
lead = self.browse(cr, uid, ref('crm.crm_case_abcfuelcounits0'))
assert lead.partner_assigned_id.id == ref('base.res_partner_ericdubois0') , "Opportuniy is not assigned nearest partner"
assert lead.partner_latitude == 50.8495239 , "Latitude is wrong"
assert lead.partner_longitude == 4.3667002 , "Longitude is wrong"
-
I forward this opportunity to its nearest partner.
-
!python {model: crm.lead.forward.to.partner}: |
context.update({'active_model': 'crm.lead', 'active_id': ref('crm.crm_case_abcfuelcounits0'), 'active_ids': [ref('crm.crm_case_abcfuelcounits0')]})
forward_id = self.create(cr, uid, {'email_from': 'test@openerp.com', 'send_to': 'partner'}, context=context)
try:
self.action_forward(cr, uid, [forward_id], context=context)
except:
pass

View File

@ -1,137 +0,0 @@
-
In order to test Forward Partner functionality, I create an opportunity and forward it to partner.
-
I assign an email address to Administrator.
-
!record {model: res.users, id: base.user_root}:
user_email: admin@openerp.com
-
I create some partner grades.
-
I create a grade 'First'.
-
!record {model: res.partner.grade, id: res_partner_grade_first0}:
name: First
sequence: 1
-
I create another grade 'Second'.
-
!record {model: res.partner.grade, id: res_partner_grade_second0}:
name: Second
sequence: 2
-
I create one more grade 'Third'.
-
!record {model: res.partner.grade, id: res_partner_grade_third0}:
name: Third
sequence: 3
-
I assign grade 'First' to the partner 'Axelor'.
-
!record {model: res.partner, id: base.res_partner_desertic_hispafuentes}:
grade_id: res_partner_grade_first0
-
I change the User email id or partner if needed.
-
!python {model: res.partner}: |
self.geo_localize(cr, uid, [ref('base.res_partner_desertic_hispafuentes')], context)
-
I assgin a reply-to email address to Sales Team.
-
!record {model: crm.case.section, id: crm.section_sales_department}:
reply_to: sales_openerp@openerp.com
-
I create an opportunity 'Questionnaire on OpenERP'.
-
!record {model: crm.lead, id: crm_lead_questionnaireonopenerp0}:
categ_id: crm.categ_oppor7
section_id: crm.section_sales_department
country_id: base.fr
date_assign: '2011-02-07'
day_close: 0.0
day_open: 0.0
email_from: info@axelor.com
name: Questionnaire on OpenERP
partner_address_id: base.res_partner_address_3000
partner_assigned_id: base.res_partner_desertic_hispafuentes
partner_id: base.res_partner_desertic_hispafuentes
partner_latitude: 0.0
partner_longitude: 0.0
phone: +33 1 64 61 04 01
planned_revenue: 0.0
probability: 0.0
type: opportunity
-
I change the assigned partner.
-
!python {model: crm.lead}: |
self.onchange_assign_id(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], ref('base.res_partner_desertic_hispafuentes'), context)
self.assign_partner(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], context)
-
I change the User email id or partner if needed.
-
!python {model: crm.lead.forward.to.partner}: |
context.update({'history': 'latest', })
user = ref('base.user_root')
self.on_change_email(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], user)
self.on_change_partner(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], ref('base.res_partner_desertic_hispafuentes'))
-
I change in history define.
-
!python {model: crm.lead.forward.to.partner}: |
context.update({'history': 'info', })
self.on_change_history(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], context.get('history'), context)
-
I check the case history.
-
!python {model: crm.lead.forward.to.partner}: |
context.update({'history': 'latest', })
self._get_case_history(cr, uid, context.get('history'), ref('crm_lead_questionnaireonopenerp0'), context=context)
context.update({'history': 'info', })
self._get_case_history(cr, uid, context.get('history'), ref('crm_lead_questionnaireonopenerp0'), context=context)
context.update({'history': 'whole', })
self._get_case_history(cr, uid, context.get('history'), ref('crm_lead_questionnaireonopenerp0'), context=context)
-
I get lead details.
-
!python {model: crm.lead.forward.to.partner}: |
self.get_lead_details(cr, uid, ref('crm_lead_questionnaireonopenerp0'), context)
-
I click on Forward button.
-
!python {model: crm.lead.forward.to.partner}: |
from tools import config
vals = {
'subject': 'email',
'email_to': 'info@axelor.com',
'email_from': 'Administrator <admin@openerp.com>',
'reply_to': 'sales_openerp@openerp.com',
'state': 'draft',
'history': 'latest',
}
ids = self.create(cr, uid, vals, context={'active_id': ref('crm_lead_questionnaireonopenerp0'), 'active_model': 'crm.lead'})
host = config.get('smtp_user', '127.0.0.1')
assert config.get(host, True), 'SMTP not configured !'
try:
self.action_forward(cr, uid, [ids], context={'active_id': ref('crm_lead_questionnaireonopenerp0'), 'active_model': 'crm.lead'})
except:
pass
-
I create the opportunity.
-
!record {model: crm.lead, id: crm_opportunity2}:
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 Update the data.
-
!python {model: crm.merge.opportunity}: |
self._update_data([ref('crm_opportunity2')], ref('crm_lead_questionnaireonopenerp0'))

View File

@ -20,6 +20,3 @@
##############################################################################
import crm_forward_to_partner
import crm_merge_opportunity
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

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