[MERGE]
bzr revid: stephane@openerp.com-20100715141756-fhzyv8tjynlykage
This commit is contained in:
@@ -2684,6 +2684,15 @@ class wizard_multi_charts_accounts(osv.osv_memory):
|
||||
'position_id' : new_fp,
|
||||
}
|
||||
obj_ac_fp.create(cr, uid, vals_acc)
|
||||
|
||||
#fially inactive the demo chart of accounts
|
||||
data_id = data_pool.search(cr, uid, [('model','=','account.account'), ('name','=','chart0')])
|
||||
if data_id:
|
||||
data = data_pool.browse(cr, uid, data_id[0])
|
||||
account_id = data.res_id
|
||||
if account_id:
|
||||
cr.execute("update account_account set active='f' where id=%s" % (account_id))
|
||||
|
||||
wizard_multi_charts_accounts()
|
||||
|
||||
class account_bank_accounts_wizard(osv.osv_memory):
|
||||
|
||||
@@ -25,6 +25,7 @@ from osv import fields, osv
|
||||
|
||||
from tools.misc import currency
|
||||
from tools.translate import _
|
||||
import decimal_precision as dp
|
||||
|
||||
class account_bank_statement(osv.osv):
|
||||
|
||||
@@ -130,9 +131,9 @@ class account_bank_statement(osv.osv):
|
||||
states={'confirm': [('readonly', True)]}, domain=[('type', '=', 'cash')]),
|
||||
'period_id': fields.many2one('account.period', 'Period', required=True,
|
||||
states={'confirm':[('readonly', True)]}),
|
||||
'balance_start': fields.float('Starting Balance', digits=(16,2),
|
||||
'balance_start': fields.float('Starting Balance', digits_compute=dp.get_precision('Account'),
|
||||
states={'confirm':[('readonly',True)]}),
|
||||
'balance_end_real': fields.float('Ending Balance', digits=(16,2),
|
||||
'balance_end_real': fields.float('Ending Balance', digits_compute=dp.get_precision('Account'),
|
||||
states={'confirm':[('readonly', True)]}),
|
||||
'balance_end': fields.function(_end_balance, method=True, string='Balance'),
|
||||
'line_ids': fields.one2many('account.bank.statement.line',
|
||||
|
||||
@@ -25,6 +25,7 @@ import time
|
||||
from mx import DateTime
|
||||
from decimal import Decimal
|
||||
from tools.translate import _
|
||||
import decimal_precision as dp
|
||||
|
||||
class account_cashbox_line(osv.osv):
|
||||
|
||||
@@ -55,9 +56,9 @@ class account_cashbox_line(osv.osv):
|
||||
return {'value':{'subtotal': sub or 0.0}}
|
||||
|
||||
_columns = {
|
||||
'pieces': fields.float('Values', digits=(16,2)),
|
||||
'pieces': fields.float('Values', digits_compute=dp.get_precision('Account')),
|
||||
'number': fields.integer('Number'),
|
||||
'subtotal': fields.function(_sub_total, method=True, string='Sub Total', type='float',digits=(16,2)),
|
||||
'subtotal': fields.function(_sub_total, method=True, string='Sub Total', type='float', digits_compute=dp.get_precision('Account')),
|
||||
'starting_id': fields.many2one('account.bank.statement',ondelete='cascade'),
|
||||
'ending_id': fields.many2one('account.bank.statement',ondelete='cascade'),
|
||||
}
|
||||
@@ -176,7 +177,7 @@ class account_cash_statement(osv.osv):
|
||||
_columns = {
|
||||
'company_id':fields.many2one('res.company', 'Company', required=False),
|
||||
'journal_id': fields.many2one('account.journal', 'Journal', required=True),
|
||||
'balance_end_real': fields.float('Closing Balance', digits=(16,2), states={'confirm':[('readonly', True)]}, help="closing balance entered by the cashbox verifier"),
|
||||
'balance_end_real': fields.float('Closing Balance', digits_compute=dp.get_precision('Account'), states={'confirm':[('readonly', True)]}, help="closing balance entered by the cashbox verifier"),
|
||||
'state': fields.selection(
|
||||
[('draft', 'Draft'),
|
||||
('confirm', 'Confirm'),
|
||||
|
||||
@@ -201,13 +201,13 @@
|
||||
<field name="amount_total"/>
|
||||
<field name="state"/>
|
||||
<field name="residual"/>
|
||||
<group col="3" colspan="4">
|
||||
<group col="4" colspan="4">
|
||||
<button name="invoice_open" states="draft,proforma2" string="Approve" icon="terp-camera_test"/>
|
||||
<button name="%(action_account_invoice_refund)d" type='action' string='Credit Note' states='open,paid' icon="gtk-execute"/>
|
||||
<button name="%(action_account_invoice_pay)d" type='action' string='Pay Invoice' states='open' icon="gtk-ok"/>
|
||||
<button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" icon="terp-gtk-stop"/>
|
||||
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" icon="terp-stock_effects-object-colorize"/>
|
||||
<button name="%(action_account_state_open)d" type='action' string='Re-Open' states='paid' icon="gtk-convert"/>
|
||||
<button name="%(action_account_invoice_refund)d" type='action' string='Credit Note' states='paid' icon="terp-dolar"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
@@ -295,14 +295,14 @@
|
||||
<field name="amount_total"/>
|
||||
<field name="state"/>
|
||||
<field name="residual"/>
|
||||
<group col="4" colspan="4" groups="base.group_user">
|
||||
<group col="6" colspan="4" groups="base.group_user">
|
||||
<button name="invoice_proforma2" states="draft" string="PRO-FORMA" icon="terp-check"/>
|
||||
<button name="invoice_open" states="draft,proforma2" string="Create" icon="terp-document-new"/>
|
||||
<button name="%(action_account_invoice_refund)d" type='action' string='Credit Note' states='open,paid' icon="gtk-execute"/>
|
||||
<button name="%(action_account_invoice_pay)d" type='action' string='Pay Invoice' states='open' icon="gtk-ok"/>
|
||||
<button name="invoice_cancel" states="draft,proforma2,sale,open" string="Cancel" icon="gtk-cancel"/>
|
||||
<button name="action_cancel_draft" states="cancel" string="Set to Draft" type="object" icon="terp-stock_effects-object-colorize"/>
|
||||
<button name='%(action_account_state_open)d' type='action' string='Re-Open' states='paid' icon="gtk-convert"/>
|
||||
<button name="%(action_account_invoice_refund)d" type='action' string='Credit Note' states='paid' icon="gtk-execute"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="view_account_list" model="ir.ui.view">
|
||||
<field name="name">account.account.list</field>
|
||||
<field name="model">account.account</field>
|
||||
@@ -206,6 +206,7 @@
|
||||
<tree string="Chart of accounts" toolbar="1" colors="blue:type in ('view');black:type not in ('view')">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="parent_id" invisible="1"/>
|
||||
<field name="user_type" invisible="1"/>
|
||||
<field name="debit"/>
|
||||
<field name="credit"/>
|
||||
@@ -365,7 +366,7 @@
|
||||
<field name="view_id" widget="selection"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Company" colspan="4"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
@@ -1213,13 +1214,13 @@
|
||||
<field name="search_view_id" ref="view_account_move_filter"/>
|
||||
<field name="domain">[('to_check','=',True), ('state','=','draft')]</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
action="action_move_to_review"
|
||||
id="menu_action_move_to_review"
|
||||
|
||||
<menuitem
|
||||
action="action_move_to_review"
|
||||
id="menu_action_move_to_review"
|
||||
parent="periodical_processing_journal_entries_validation"
|
||||
/>
|
||||
|
||||
|
||||
<!-- <menuitem id="next_id_29" name="Search Entries" parent="account.menu_finance_entries" sequence="40"/>-->
|
||||
<!-- <menuitem action="action_move_line_form" id="menu_action_move_line_form" parent="next_id_29"/>-->
|
||||
|
||||
|
||||
@@ -27,15 +27,19 @@
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Account Board">
|
||||
<hpaned>
|
||||
<vpaned>
|
||||
<child1>
|
||||
<action colspan="4" height="160" name="%(account.action_invoice_tree1)d" string="Draft Customer Invoices" domain="[('state','=','draft'),('type','=','out_invoice')]"/>
|
||||
</child1>
|
||||
<child2>
|
||||
<action colspan="4" height="220" name="%(action_aged_receivable)d" string="Aged receivables"/>
|
||||
<action colspan="4" height="220" name="%(action_aged_income)d" string="Aged income"/>
|
||||
<group col="2" colspan="2" expand="1">
|
||||
<action colspan="4" name="%(action_aged_receivable)d" string="Aged receivables"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<action colspan="4" height="220" name="%(action_aged_income)d" string="Aged income"/>
|
||||
</group>
|
||||
</child2>
|
||||
</hpaned>
|
||||
</vpaned>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -68,7 +68,7 @@ class account_pl_report(osv.osv_memory):
|
||||
'fiscalyear' : False,
|
||||
'display_account': 'bal_all',
|
||||
'display_type': True,
|
||||
}
|
||||
}
|
||||
|
||||
def next_view(self, cr, uid, ids, context=None):
|
||||
obj_model = self.pool.get('ir.model.data')
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Select Chart">
|
||||
<label string="Select account chart to print profit and loss account report" colspan="4"/>
|
||||
<separator colspan="4"/>
|
||||
<field name="Account_list"/>
|
||||
<separator colspan="4"/>
|
||||
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
|
||||
|
||||
@@ -2,51 +2,51 @@
|
||||
<openerp>
|
||||
<data>
|
||||
<!---->
|
||||
<!-- <record id="view_account_print_journal" model="ir.ui.view">-->
|
||||
<!-- <record id="view_account_print_journal" model="ir.ui.view">-->
|
||||
<!-- <field name="name">Account Print Journal</field>-->
|
||||
<!-- <field name="model">account.print.journal</field>-->
|
||||
<!-- <field name="type">form</field>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <form string="Print Journal">-->
|
||||
<!-- <group col="4" colspan="6">-->
|
||||
<!-- <field name="journal_id"/>-->
|
||||
<!-- <field name="period_id"/>-->
|
||||
<!-- <newline/>-->
|
||||
<!-- <field name="sort_selection"/>-->
|
||||
<!-- </group>-->
|
||||
<!-- <separator colspan="4"/>-->
|
||||
<!-- <group col="2" colspan="4">-->
|
||||
<!-- <button special="cancel" string="Cancel" icon='gtk-cancel'/>-->
|
||||
<!-- <button name="check_data" string="Print" colspan="1" type="object" icon="gtk-ok"/>-->
|
||||
<!-- </group>-->
|
||||
<!-- </form>-->
|
||||
<!-- <form string="Print Journal">-->
|
||||
<!-- <group col="4" colspan="6">-->
|
||||
<!-- <field name="journal_id"/>-->
|
||||
<!-- <field name="period_id"/>-->
|
||||
<!-- <newline/>-->
|
||||
<!-- <field name="sort_selection"/>-->
|
||||
<!-- </group>-->
|
||||
<!-- <separator colspan="4"/>-->
|
||||
<!-- <group col="2" colspan="4">-->
|
||||
<!-- <button special="cancel" string="Cancel" icon='gtk-cancel'/>-->
|
||||
<!-- <button name="check_data" string="Print" colspan="1" type="object" icon="gtk-ok"/>-->
|
||||
<!-- </group>-->
|
||||
<!-- </form>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
|
||||
<record id="view_account_print_journal" model="ir.ui.view">
|
||||
<record id="view_account_print_journal" model="ir.ui.view">
|
||||
<field name="name">Account Print Journal</field>
|
||||
<field name="model">account.print.journal</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Print Journal">
|
||||
<group height="400" width="400">
|
||||
<group>
|
||||
<separator string="Journals"/><newline/>
|
||||
<field name="journal_id" nolabel="1"/><newline/>
|
||||
<separator string="Periods"/><newline/>
|
||||
<field name="period_id" nolabel="1"/><newline/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group>
|
||||
<field name="sort_selection"/>
|
||||
<newline/>
|
||||
<separator colspan="4"/>
|
||||
<button special="cancel" string="Cancel" icon='gtk-cancel'/>
|
||||
<button name="check_data" string="Print" colspan="1" type="object" icon="gtk-ok"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
<form string="Print Journal">
|
||||
<group height="430" width="420">
|
||||
<group>
|
||||
<separator string="Journals"/><newline/>
|
||||
<field name="journal_id" nolabel="1"/><newline/>
|
||||
<separator string="Periods"/><newline/>
|
||||
<field name="period_id" nolabel="1"/><newline/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group>
|
||||
<field name="sort_selection"/>
|
||||
<newline/>
|
||||
<separator colspan="4"/>
|
||||
<button special="cancel" string="Cancel" icon='gtk-cancel'/>
|
||||
<button name="check_data" string="Print" colspan="1" type="object" icon="gtk-ok"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -59,12 +59,12 @@
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Journals"
|
||||
parent="account.menu_generic_report"
|
||||
action="action_account_print_journal"
|
||||
id="menu_account_print_journal"
|
||||
icon="STOCK_PRINT"/>
|
||||
<menuitem
|
||||
name="Journals"
|
||||
parent="account.menu_generic_report"
|
||||
action="action_account_print_journal"
|
||||
id="menu_account_print_journal"
|
||||
icon="STOCK_PRINT"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+4
-6
@@ -441,14 +441,13 @@ class crm_case_section(osv.osv):
|
||||
_columns = {
|
||||
'name': fields.char('Sales Team', size=64, required=True, translate=True),
|
||||
'code': fields.char('Code', size=8),
|
||||
'active': fields.boolean('Active', help="If the active field is set to \
|
||||
true, it will allow you to hide the sales team without removing it."),
|
||||
'active': fields.boolean('Active', help="If the active field is set to "\
|
||||
"true, it will allow you to hide the sales team without removing it."),
|
||||
'allow_unlink': fields.boolean('Allow Delete', help="Allows to delete non draft cases"),
|
||||
'change_responsible': fields.boolean('Change Responsible', help="Thick this box if you want that on escalation, the responsible of this sale team automatically becomes responsible of the lead/opportunity escaladed"),
|
||||
'user_id': fields.many2one('res.users', 'Responsible User'),
|
||||
'member_ids':fields.many2many('res.users', 'sale_member_rel', 'section_id', 'member_id', 'Team Members'),
|
||||
'reply_to': fields.char('Reply-To', size=64, help="The email address put \
|
||||
in the 'Reply-To' of all emails sent by Open ERP about cases in this sales team"),
|
||||
'reply_to': fields.char('Reply-To', size=64, help="The email address put in the 'Reply-To' of all emails sent by Open ERP about cases in this sales team"),
|
||||
'parent_id': fields.many2one('crm.case.section', 'Parent Team'),
|
||||
'child_ids': fields.one2many('crm.case.section', 'parent_id', 'Child Teams'),
|
||||
'resource_calendar_id': fields.many2one('resource.calendar', "Resource's Calendar"),
|
||||
@@ -586,8 +585,7 @@ class crm_case_stage(osv.osv):
|
||||
_columns = {
|
||||
'name': fields.char('Stage Name', size=64, required=True, translate=True),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order \
|
||||
when displaying a list of case stages."),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of case stages."),
|
||||
'object_id': fields.many2one('ir.model', 'Object Name'),
|
||||
'probability': fields.float('Probability (%)', required=True),
|
||||
'on_change': fields.boolean('Change Probability Automatically', \
|
||||
|
||||
@@ -113,11 +113,10 @@ class crm_lead(osv.osv, crm_case):
|
||||
'date_action_next': fields.datetime('Next Action', readonly=1),
|
||||
'email_from': fields.char('Email', size=128, help="E-mail address of the contact"),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
|
||||
select=True, help='Sales team to which this case belongs to.\
|
||||
Defines responsible user and e-mail address for the mail gateway.'),
|
||||
select=True, help='Sales team to which this case belongs to. Defines responsible user and e-mail address for the mail gateway.'),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These \
|
||||
addresses will receive a copy of the future e-mail communication between partner \
|
||||
addresses(Comma-separated) will receive a copy of the future e-mail communication between partner \
|
||||
and users"),
|
||||
'description': fields.text('Notes'),
|
||||
'write_date': fields.datetime('Update Date' , readonly=True),
|
||||
|
||||
@@ -51,8 +51,7 @@ class crm_meeting(osv.osv, crm_case):
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
domain="[('partner_id','=',partner_id)]", states={'done': [('readonly', True)]}),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', states={'done': [('readonly', True)]}, \
|
||||
select=True, help='Sales team to which Case belongs to.\
|
||||
Define Responsible user and Email account for mail gateway.'),
|
||||
select=True, help='Sales team to which Case belongs to.'),
|
||||
'email_from': fields.char('Email', size=128, states={'done': [('readonly', True)]}, help="These people will receive email."),
|
||||
'id': fields.integer('ID'),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
|
||||
@@ -41,8 +41,7 @@ class crm_phonecall(osv.osv, crm_case):
|
||||
'date_action_next': fields.datetime('Next Action', readonly=1),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
|
||||
select=True, help='Sales team to which Case belongs to.\
|
||||
Define Responsible user and Email account for mail gateway.'),
|
||||
select=True, help='Sales team to which Case belongs to.'),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
##############################################################################
|
||||
|
||||
import base64
|
||||
import itertools
|
||||
import time
|
||||
import re
|
||||
from osv import osv, fields
|
||||
@@ -165,63 +164,26 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
||||
email = self.pool.get('res.partner.address').browse(cr, uid, address_id).email
|
||||
return {'value': {'email_to' : email}}
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
return {'type' : 'ir.actions.act_window_close'}
|
||||
|
||||
def action_forward(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Forward the lead to a partner
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
res_id = context.get('active_id', False)
|
||||
|
||||
model = context.get('active_model', False)
|
||||
if not res_id or not model:
|
||||
return {}
|
||||
|
||||
email_re = r'([^ ,<@]+@[^> ,]+)'
|
||||
|
||||
this = self.browse(cr, uid, ids[0], context=context)
|
||||
|
||||
case_pool = self.pool.get(model)
|
||||
case_pool = self.pool.get(context.get('active_model'))
|
||||
res_id = context and context.get('active_id', False) or False
|
||||
case = case_pool.browse(cr, uid, res_id, context=context)
|
||||
|
||||
emails = [this.email_to]
|
||||
body = case_pool.format_body(this.body)
|
||||
email_from = this.email_from or False
|
||||
context.update({'mail': 'forward'})
|
||||
super(crm_lead_forward_to_partner, self).action_send(cr, uid, ids, context=context)
|
||||
|
||||
# extract attachements from case and emails according to mode
|
||||
attachments = []
|
||||
attach_pool = self.pool.get('ir.attachment')
|
||||
direct_attachments = attach_pool.search(cr, uid, [('res_model', '=', 'crm.lead'), ('res_id', '=', res_id)], context=context)
|
||||
attachments += attach_pool.browse(cr, uid, direct_attachments, context=context)
|
||||
if this.history in ['latest', 'whole'] and case.message_ids:
|
||||
msgs = case.message_ids
|
||||
if this.history == 'latest':
|
||||
msgs = msgs[:1]
|
||||
attachments.extend(itertools.chain(*[m.attachment_ids for m in msgs]))
|
||||
attach = [(a.datas_fname or a.name, base64.decodestring(a.datas)) for a in attachments if a.datas]
|
||||
|
||||
result = tools.email_send(
|
||||
email_from,
|
||||
emails,
|
||||
this.subject,
|
||||
body,
|
||||
openobject_id=str(case.id),
|
||||
attach=attach,
|
||||
reply_to=case.section_id.reply_to,
|
||||
)
|
||||
|
||||
if result:
|
||||
case_pool.history(cr, uid, [case], _('Forward'), history=True, email=this.email_to, subject=this.subject, details=body, email_from=email_from, attach=attach)
|
||||
to_write = {'date_assign': time.strftime('%Y-%m-%d')}
|
||||
if (this.name == 'partner' and this.partner_id):
|
||||
to_write['partner_assigned_id'] = this.partner_id.id
|
||||
case_pool.write(cr, uid, case.id, to_write)
|
||||
else:
|
||||
raise osv.except_osv(_('Error!'), _('Unable to send mail. Please check SMTP is configured properly.'))
|
||||
to_write = {'date_assign': time.strftime('%Y-%m-%d')}
|
||||
if (this.name == 'partner' and this.partner_id):
|
||||
to_write['partner_assigned_id'] = this.partner_id.id
|
||||
|
||||
if this.name == 'user':
|
||||
to_write.update({'user_id' : this.user_id.id})
|
||||
email_re = r'([^ ,<@]+@[^> ,]+)'
|
||||
email_cc = re.findall(email_re, case.email_cc or '')
|
||||
new_cc = ''
|
||||
for to in this.email_to.split(','):
|
||||
@@ -229,7 +191,8 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
||||
email_to = email_to and email_to[0] or ''
|
||||
if email_to not in email_cc:
|
||||
new_cc += ', ' + to
|
||||
case_pool.write(cr, uid, case.id, {'email_cc' : case.email_cc and case.email_cc + new_cc})
|
||||
to_write.update({'email_cc' : case.email_cc and case.email_cc + new_cc})
|
||||
case_pool.write(cr, uid, case.id, to_write, context=context)
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
@@ -126,9 +126,9 @@ class crm_lead2opportunity(osv.osv_memory):
|
||||
if lead.state in ['done', 'cancel']:
|
||||
raise osv.except_osv(_("Warning !"), _("Closed/Cancelled \
|
||||
Leads Could not convert into Opportunity"))
|
||||
if lead.state != 'open':
|
||||
if lead.state not in ('open', 'pending'):
|
||||
raise osv.except_osv(_('Warning !'), _('Lead should be in \
|
||||
\'Open\' state before converting to Opportunity.'))
|
||||
\'Open\' or \'Pending\' state before converting to Opportunity.'))
|
||||
return False
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
@@ -289,9 +289,9 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
||||
if lead.state in ['done', 'cancel']:
|
||||
raise osv.except_osv(_("Warning !"), _("Closed/Cancelled \
|
||||
Leads Could not convert into Opportunity"))
|
||||
if lead.state != 'open':
|
||||
if lead.state not in ('open', 'pending'):
|
||||
raise osv.except_osv(_('Warning !'), _('Lead should be in \
|
||||
\'Open\' state before converting to Opportunity.'))
|
||||
\'Open\' or \'Pending\' state before converting to Opportunity.'))
|
||||
return False
|
||||
|
||||
crm_lead2opportunity_partner()
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from crm import crm
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
import base64
|
||||
import itertools
|
||||
import tools
|
||||
from crm import crm
|
||||
import re
|
||||
|
||||
class crm_send_new_email_attachment(osv.osv_memory):
|
||||
_name = 'crm.send.mail.attachment'
|
||||
@@ -46,23 +48,16 @@ class crm_send_new_email(osv.osv_memory):
|
||||
'email_to' : fields.char('To', size=512, required=True),
|
||||
'email_from' : fields.char('From', size=128, required=True),
|
||||
'reply_to' : fields.char('Reply To', size=128, required=True, help="Reply-to of the Sales team defined on this case"),
|
||||
'email_cc' : fields.char('CC', size=512, help="Carbon Copy: list of recipients that will receive"\
|
||||
" a copy of this mail, and future communication related to this case"),
|
||||
'email_cc' : fields.char('CC', size=512, help="Carbon Copy: list of recipients that will receive a copy of this mail"),
|
||||
'subject': fields.char('Subject', size=512, required=True),
|
||||
'body': fields.text('Message Body', required=True),
|
||||
'state': fields.selection(crm.AVAILABLE_STATES, string='Set New State To', required=True),
|
||||
'attachment_ids' : fields.one2many('crm.send.mail.attachment', 'wizard_id'),
|
||||
}
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
""" Closes Phonecall to Opportunity form
|
||||
"""
|
||||
return {'type':'ir.actions.act_window_close'}
|
||||
|
||||
def action_send(self, cr, uid, ids, context=None):
|
||||
""" This sends an email to ALL the addresses of the selected partners.
|
||||
"""
|
||||
|
||||
hist_obj = self.pool.get('mailgate.message')
|
||||
|
||||
if not context:
|
||||
@@ -83,20 +78,34 @@ class crm_send_new_email(osv.osv_memory):
|
||||
message_id = None
|
||||
ref_id = None
|
||||
|
||||
case = case_pool.browse(cr, uid, res_id)
|
||||
case = case_pool.browse(cr, uid, res_id, context=context)
|
||||
if context.get('mail', 'new') == 'new':
|
||||
if case.message_ids:
|
||||
message_id = case.message_ids[0].message_id
|
||||
elif context.get('mail') == 'forward':
|
||||
# extract attachements from case and emails according to mode
|
||||
attachments = []
|
||||
attach_pool = self.pool.get('ir.attachment')
|
||||
direct_attachments = attach_pool.search(cr, uid, [('res_model', '=', 'crm.lead'), ('res_id', '=', res_id)], context=context)
|
||||
attachments += attach_pool.browse(cr, uid, direct_attachments, context=context)
|
||||
if obj.history in ['latest', 'whole'] and case.message_ids:
|
||||
msgs = case.message_ids
|
||||
if obj.history == 'latest':
|
||||
msgs = msgs[:1]
|
||||
attachments.extend(itertools.chain(*[m.attachment_ids for m in msgs]))
|
||||
attach_all = [(a.datas_fname or a.name, base64.decodestring(a.datas)) for a in attachments if a.datas]
|
||||
attach += attach_all
|
||||
|
||||
else:
|
||||
hist = hist_obj.browse(cr, uid, res_id)
|
||||
hist = hist_obj.browse(cr, uid, res_id, context=context)
|
||||
message_id = hist.message_id
|
||||
model = hist.model
|
||||
case_pool = self.pool.get(model)
|
||||
res_id = hist.res_id
|
||||
ref_id = hist.ref_id
|
||||
case = case_pool.browse(cr, uid, res_id)
|
||||
case = case_pool.browse(cr, uid, res_id, context=context)
|
||||
emails = [obj.email_to]
|
||||
email_cc = obj.email_cc and obj.email_cc.split(',') or ''
|
||||
email_cc = re.findall(r'([^ ,<@]+@[^> ,]+)', obj.email_cc)
|
||||
emails = filter(None, emails)
|
||||
body = obj.body
|
||||
|
||||
@@ -121,7 +130,8 @@ class crm_send_new_email(osv.osv_memory):
|
||||
if not flag:
|
||||
raise osv.except_osv(_('Error!'), _('Unable to send mail. Please check SMTP is configured properly.'))
|
||||
|
||||
case_pool.history(cr, uid, [case], _('Send'), history=True, \
|
||||
msg_dict = {'new': 'Send', 'reply': 'Reply', 'forward': 'Forward'}
|
||||
case_pool.history(cr, uid, [case], _(msg_dict[context.get('mail', 'new')]), history=True, \
|
||||
email=obj.email_to, details=body, \
|
||||
subject=obj.subject, email_from=email_from, \
|
||||
email_cc=', '.join(email_cc), message_id=message_id, \
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<separator string="" colspan="6"/>
|
||||
<group colspan="6" col="4" >
|
||||
<field name="state" />
|
||||
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
|
||||
<button string="_Cancel" icon="gtk-cancel" special="cancel" />
|
||||
<button name="action_send" type="object" string="_Send" icon="gtk-go-forward" />
|
||||
</group>
|
||||
</form>
|
||||
|
||||
@@ -74,7 +74,7 @@ class crm_claim(osv.osv, crm.crm_case):
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
# domain="[('partner_id','=',partner_id)]"
|
||||
),
|
||||
'email_cc': fields.text('Watchers Emails', size=252, help="These people will receive a copy of the future communication between partner and users by email"),
|
||||
'email_cc': fields.text('Watchers Emails', size=252, help="These addresses(Comma-separated) will receive a copy of the future communication between partner and users"),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'partner_name': fields.char("Employee's Name", size=64),
|
||||
'partner_mobile': fields.char('Mobile', size=32),
|
||||
|
||||
@@ -46,7 +46,7 @@ class crm_fundraising(osv.osv, crm.crm_case):
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
domain="[('partner_id','=',partner_id)]"),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These people will receive a copy of the future communication between partner and users by email"),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These addresses(Comma-separated) will receive a copy of the future communication between partner and users"),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
'date': fields.datetime('Date'),
|
||||
|
||||
@@ -49,9 +49,7 @@ class crm_helpdesk(osv.osv, crm.crm_case):
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
domain="[('partner_id','=',partner_id)]"),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These people\
|
||||
will receive a copy of the future" \
|
||||
" communication between partner and users by email"),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These addresses(Comma-separated) will receive a copy of the future communication between partner and users"),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'date': fields.datetime('Date'),
|
||||
'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
'init_xml': ['event_data.xml'],
|
||||
'update_xml': [
|
||||
'wizard/event_confirm_registration_view.xml',
|
||||
'wizard/event_confirm_view.xml',
|
||||
'event_view.xml',
|
||||
'report/report_event_registration_view.xml',
|
||||
'event_sequence.xml',
|
||||
|
||||
+249
-142
@@ -26,7 +26,7 @@ import netsvc
|
||||
import pooler
|
||||
import time
|
||||
import tools
|
||||
|
||||
import decimal_precision as dp
|
||||
|
||||
class event_type(osv.osv):
|
||||
""" Event Type """
|
||||
@@ -41,16 +41,8 @@ class event_event(osv.osv):
|
||||
"""Event"""
|
||||
_name = 'event.event'
|
||||
_description = __doc__
|
||||
_inherit = 'crm.case.section'
|
||||
_order = 'date_begin'
|
||||
|
||||
def _get_currency(self, cr, uid, context):
|
||||
user = self.pool.get('res.users').browse(cr, uid, [uid])[0]
|
||||
if user.company_id:
|
||||
return user.company_id.currency_id.id
|
||||
else:
|
||||
return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
""" Copy record of Given id
|
||||
@param id: Id of Event record.
|
||||
@@ -87,14 +79,9 @@ class event_event(osv.osv):
|
||||
def button_done(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
|
||||
|
||||
def button_confirm(self, cr, uid, ids, context=None):
|
||||
"""This Funtion send reminder who had already confirmed their event registration.
|
||||
@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 Event IDs
|
||||
@param return: True
|
||||
"""
|
||||
def do_confirm(self, cr, uid, ids, context=None):
|
||||
""" Confirm Event and send confirmation email to all register peoples
|
||||
"""
|
||||
register_pool = self.pool.get('event.registration')
|
||||
for event in self.browse(cr, uid, ids, context=context):
|
||||
if event.mail_auto_confirm:
|
||||
@@ -106,6 +93,39 @@ class event_event(osv.osv):
|
||||
|
||||
return self.write(cr, uid, ids, {'state': 'confirm'})
|
||||
|
||||
def button_confirm(self, cr, uid, ids, context=None):
|
||||
"""This Function Confirm Event.
|
||||
@param ids: List of Event IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
@return: True
|
||||
"""
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
unconfirmed_ids = []
|
||||
for event in self.browse(cr, uid, ids, context=context):
|
||||
total_confirmed = event.register_current
|
||||
if total_confirmed >= event.register_min or event.register_max == 0:
|
||||
self.do_confirm(cr, uid, [event.id], context=context)
|
||||
else:
|
||||
unconfirmed_ids.append(event.id)
|
||||
if unconfirmed_ids:
|
||||
view_id = data_pool._get_id(cr, uid, 'event', 'view_event_confirm')
|
||||
view_data = data_pool.browse(cr, uid, view_id)
|
||||
view_id = view_data.res_id
|
||||
context['event_ids'] = unconfirmed_ids
|
||||
return {
|
||||
'name': _('Confirm Event'),
|
||||
'context': context,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'event.confirm',
|
||||
'views': [(view_id, 'form')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'context': context,
|
||||
'nodestroy': True
|
||||
}
|
||||
return True
|
||||
|
||||
|
||||
def _get_register(self, cr, uid, ids, fields, args, context=None):
|
||||
"""Get Confirm or uncofirm register value.
|
||||
@@ -122,7 +142,7 @@ class event_event(osv.osv):
|
||||
res[event.id][field] = False
|
||||
state = []
|
||||
if 'register_current' in fields:
|
||||
state.append('open')
|
||||
state += ['open', 'done']
|
||||
if 'register_prospect' in fields:
|
||||
state.append('draft')
|
||||
|
||||
@@ -169,77 +189,134 @@ class event_event(osv.osv):
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'type': fields.many2one('event.type', 'Type', help="Type of Event like Seminar, Exhibition, Conference, Training."),
|
||||
'register_max': fields.integer('Maximum Registrations', help="Provide Maximun Number of Registrations"),
|
||||
'register_min': fields.integer('Minimum Registrations', help="Providee Minimum Number of Registrations"),
|
||||
'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations', multi='register_current', help="Total of Open Registrations"),
|
||||
'register_prospect': fields.function(_get_register, method=True, string='Unconfirmed Registrations', multi='register_prospect', help="Total of Prospect Registrations"),
|
||||
'date_begin': fields.datetime('Beginning date', required=True, help="Beginning Date of Event"),
|
||||
'date_end': fields.datetime('Closing date', required=True, help="Closing Date of Event"),
|
||||
'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'State', readonly=True, required=True, help='If event is created, the state is \'Draft\'.\n If event is confirmed for the particular dates the state is set to \'Confirmed\'.\
|
||||
\nIf the event is over, the state is set to \'Done\'.\n If event is cancelled the state is set to \'Cancelled\'.'),
|
||||
'mail_auto_registr': fields.boolean('Mail Auto Register', help='Check this box if you want to use the automatic mailing for new registration'),
|
||||
'mail_auto_confirm': fields.boolean('Mail Auto Confirm', help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
|
||||
'mail_registr': fields.text('Registration Email', help='This email will be sent when someone subscribes to the event.'),
|
||||
'mail_confirm': fields.text('Confirmation Email', help="This email will be sent when the event gets confimed or when someone subscribes to a confirmed event. This is also the email sent to remind someone about the event."),
|
||||
'product_id': fields.many2one('product.product', 'Product', required=True, help="Product which is provided cost of event. Invoice of event will be created with this Product."),
|
||||
'note': fields.text('Notes', help="Description or Summary of Event"),
|
||||
'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
|
||||
"unit_price": fields.float('Cost'),
|
||||
'main_speaker_id': fields.many2one('res.partner','Main Speaker'),
|
||||
'speaker_ids':fields.many2many('res.partner', 'event_speaker_rel', 'speaker_id', 'partner_id', 'Other Speakers'),
|
||||
'address_id': fields.many2one('res.partner.address','Location Room'),
|
||||
'speaker_confirmed': fields.boolean('Speaker Confirmed'),
|
||||
'name': fields.char('Name', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}),
|
||||
'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'parent_id': fields.many2one('event.event', 'Parent Event', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sale Team', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'child_ids': fields.one2many('event.event', 'parent_id', 'Child Events', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'reply_to': fields.char('Reply-To', size=64, readonly=False, states={'done': [('readonly', True)]}, help="The email address put in the 'Reply-To' of all emails sent by Open ERP"),
|
||||
'type': fields.many2one('event.type', 'Type', help="Type of Event like Seminar, Exhibition, Conference, Training.", readonly=False, states={'done': [('readonly', True)]}),
|
||||
'register_max': fields.integer('Maximum Registrations', help="Provide Maximun Number of Registrations", readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'register_min': fields.integer('Minimum Registrations', help="Providee Minimum Number of Registrations", readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations', multi='register_current',
|
||||
help="Total of Open and Done Registrations"),
|
||||
'register_prospect': fields.function(_get_register, method=True, string='Unconfirmed Registrations', multi='register_prospect',
|
||||
help="Total of Prospect Registrations"),
|
||||
'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'date_begin': fields.datetime('Beginning date', required=True, help="Beginning Date of Event", readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'date_end': fields.datetime('Closing date', required=True, help="Closing Date of Event", readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'state': fields.selection([
|
||||
('draft', 'Draft'),
|
||||
('confirm', 'Confirmed'),
|
||||
('done', 'Done'),
|
||||
('cancel', 'Cancelled')],
|
||||
'State', readonly=True, required=True,
|
||||
help='If event is created, the state is \'Draft\'.If event is confirmed for the particular dates the state is set to \'Confirmed\'. If the event is over, the state is set to \'Done\'.If event is cancelled the state is set to \'Cancelled\'.'),
|
||||
'mail_auto_registr': fields.boolean('Mail Auto Register', readonly=False, states={'done': [('readonly', True)]}, help='Check this box if you want to use the automatic mailing for new registration'),
|
||||
'mail_auto_confirm': fields.boolean('Mail Auto Confirm', readonly=False, states={'done': [('readonly', True)]}, help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
|
||||
'mail_registr': fields.text('Registration Email', readonly=False, states={'done': [('readonly', True)]}, help='This email will be sent when someone subscribes to the event.'),
|
||||
'mail_confirm': fields.text('Confirmation Email', readonly=False, states={'done': [('readonly', True)]}, help="This email will be sent when the event gets confimed or when someone subscribes to a confirmed event. This is also the email sent to remind someone about the event."),
|
||||
'product_id': fields.many2one('product.product', 'Product', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Product which is provided cost of event. Invoice of event will be created with this Product."),
|
||||
'note': fields.text('Notes', help="Description or Summary of Event", readonly=False, states={'done': [('readonly', True)]}),
|
||||
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', readonly=True, states={'draft': [('readonly', False)]}, help="Pricelist version for current event."),
|
||||
"unit_price": fields.float('Registration Cost', digits_compute= dp.get_precision('Event Price'), readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'main_speaker_id': fields.many2one('res.partner','Main Speaker', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'speaker_ids':fields.many2many('res.partner', 'event_speaker_rel', 'speaker_id', 'partner_id', 'Other Speakers', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'address_id': fields.many2one('res.partner.address','Location Address', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'speaker_confirmed': fields.boolean('Speaker Confirmed', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'country_id': fields.related('address_id', 'country_id',
|
||||
type='many2one', relation='res.country', string='Country'),
|
||||
'language': fields.char('Language',size=64),
|
||||
type='many2one', relation='res.country', string='Country', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'language': fields.char('Language',size=64, readonly=False, states={'done': [('readonly', True)]}),
|
||||
'note': fields.text('Description', readonly=False, states={'done': [('readonly', True)]}),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True, change_default=True, readonly=False, states={'done': [('readonly', True)]}),
|
||||
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
# 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'event.event'),
|
||||
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
|
||||
'user_id': lambda obj, cr, uid, context: uid,
|
||||
'currency_id': _get_currency,
|
||||
}
|
||||
|
||||
def _check_recursion(self, cr, uid, ids):
|
||||
"""
|
||||
Checks for recursion level for event
|
||||
"""
|
||||
level = 100
|
||||
|
||||
while len(ids):
|
||||
cr.execute('select distinct parent_id from event_event where id IN %s', (tuple(ids),))
|
||||
ids = filter(None, map(lambda x: x[0], cr.fetchall()))
|
||||
if not level:
|
||||
return False
|
||||
level -= 1
|
||||
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_recursion, 'Error ! You cannot create recursive event.', ['parent_id'])
|
||||
]
|
||||
|
||||
def do_team_change(self, cr, uid, ids, team_id, context=None):
|
||||
"""
|
||||
On Change Callback: when team change, this is call.
|
||||
on this function, take value of reply_to from selected team.
|
||||
"""
|
||||
if not team_id:
|
||||
return {}
|
||||
if context is None:
|
||||
context = {}
|
||||
team_pool = self.pool.get('crm.case.section')
|
||||
team = team_pool.browse(cr, uid, team_id, context=context)
|
||||
res = {}
|
||||
if team.reply_to:
|
||||
res = {'value': {'reply_to': team.reply_to}}
|
||||
return res
|
||||
|
||||
event_event()
|
||||
|
||||
class event_registration(osv.osv):
|
||||
"""Event Registration"""
|
||||
|
||||
"""Event Registration"""
|
||||
_name= 'event.registration'
|
||||
_description = __doc__
|
||||
_inherit = 'crm.meeting'
|
||||
|
||||
def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
|
||||
cur_obj = self.pool.get('res.currency')
|
||||
res = {}
|
||||
context = context or {}
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
price = line.unit_price * line.nb_register
|
||||
pricelist = line.event_id.pricelist_id or line.partner_invoice_id.property_product_pricelist
|
||||
cur = pricelist and pricelist.currency_id or False
|
||||
res[line.id] = cur and cur_obj.round(cr, uid, cur, price) or price
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'email_cc': fields.text('CC', size=252 , help="These \
|
||||
people will receive a copy of the future communication between partner \
|
||||
and users by email"),
|
||||
'nb_register': fields.integer('Number of Registration', readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'event_id': fields.many2one('event.event', 'Event Related', required=True),
|
||||
"partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced'),
|
||||
"contact_id": fields.many2one('res.partner.contact', 'Partner Contact'), #TODO: filter only the contacts that have a function into the selected partner_id
|
||||
"unit_price": fields.float('Unit Price'),
|
||||
"badge_title": fields.char('Badge Title', size=128),
|
||||
"badge_name": fields.char('Badge Name', size=128),
|
||||
"badge_partner": fields.char('Badge Partner', size=128),
|
||||
"event_product": fields.char("Product Name", size=128, required=True),
|
||||
"tobe_invoiced": fields.boolean("To be Invoiced"),
|
||||
'name': fields.char('Summary', size=124, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'email_cc': fields.text('CC', size=252 , readonly=False, states={'done': [('readonly', True)]}, help="These people will receive a copy of the future communication between partner and users by email"),
|
||||
'nb_register': fields.integer('Quantity', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Number of Registrations or Tickets"),
|
||||
'event_id': fields.many2one('event.event', 'Event Related', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
"partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced', readonly=True, states={'draft': [('readonly', False)]}),
|
||||
"contact_id": fields.many2one('res.partner.contact', 'Partner Contact', readonly=False, states={'done': [('readonly', True)]}), #TODO: filter only the contacts that have a function into the selected partner_id
|
||||
"unit_price": fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Event Price'), readonly=True, states={'draft': [('readonly', False)]}),
|
||||
'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', digits_compute= dp.get_precision('Event Price')),
|
||||
"badge_ids": fields.one2many('event.registration.badge', 'registration_id', 'Badges', readonly=False, states={'done': [('readonly', True)]}),
|
||||
"event_product": fields.char("Invoice Name", size=128, required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||
"tobe_invoiced": fields.boolean("To be Invoiced", readonly=True, states={'draft': [('readonly', False)]}),
|
||||
"invoice_id": fields.many2one("account.invoice", "Invoice", readonly=True),
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
'ref': fields.reference('Reference', selection=crm._links_get, size=128),
|
||||
'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
|
||||
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('model','=',_name)]),
|
||||
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
|
||||
'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
|
||||
'section_id': fields.related('event_id', 'section_id', type='many2one', relation='crm.case.section', string='Sale Team', store=True, readonly=True, states={'draft':[('readonly',False)]}),
|
||||
'company_id': fields.related('event_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True, states={'draft':[('readonly',False)]}),
|
||||
}
|
||||
_defaults = {
|
||||
'nb_register': 1,
|
||||
'tobe_invoiced': True,
|
||||
'name': 'Registration',
|
||||
# 'currency_id': _get_currency,
|
||||
'date': time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
|
||||
def _make_invoice(self, cr, uid, reg, lines, context=None):
|
||||
@@ -323,16 +400,38 @@ and users by email"),
|
||||
res = self._make_invoice(cr, uid, val[0][0], [v for k , v in val], context=context)
|
||||
|
||||
for k , v in val:
|
||||
self.write(cr, uid, [k.id], {'state': 'done', 'invoice_id': res}, context=context)
|
||||
self.do_close(cr, uid, [k.id], context={'invoice_id': res})
|
||||
|
||||
else:
|
||||
for k , v in val:
|
||||
res = self._make_invoice(cr, uid, k, [v], context=context)
|
||||
self.write(cr, uid, [k.id], {'state': 'done', 'invoice_id': res}, context=context)
|
||||
self.do_close(cr, uid, [k.id], context={'invoice_id': res})
|
||||
if res: new_invoice_ids.append(res)
|
||||
|
||||
return new_invoice_ids
|
||||
|
||||
def do_open(self, cr, uid, ids, context=None):
|
||||
""" Open Registration
|
||||
"""
|
||||
res = self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
||||
self.mail_user(cr, uid, ids)
|
||||
self._history(cr, uid, ids, _('Open'))
|
||||
return res
|
||||
|
||||
def do_close(self, cr, uid, ids, context=None):
|
||||
""" Close Registration
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
invoice_id = context.get('invoice_id', False)
|
||||
values = {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
msg = _('Done')
|
||||
if invoice_id:
|
||||
values['invoice_id'] = invoice_id
|
||||
res = self.write(cr, uid, ids, values)
|
||||
self._history(cr, uid, ids, msg)
|
||||
return res
|
||||
|
||||
def check_confirm(self, cr, uid, ids, context=None):
|
||||
"""This Function Open Event Registration and send email to user.
|
||||
@param ids: List of Event registration's IDs
|
||||
@@ -344,9 +443,7 @@ and users by email"),
|
||||
for registration in self.browse(cr, uid, ids, context=context):
|
||||
total_confirmed = registration.event_id.register_current + registration.nb_register
|
||||
if total_confirmed <= registration.event_id.register_max or registration.event_id.register_max == 0:
|
||||
self.write(cr, uid, [registration.id], {'state': 'open'}, context=context)
|
||||
self.mail_user(cr, uid, [registration.id])
|
||||
self._history(cr, uid, [registration], _('Open'))
|
||||
self.do_open(cr, uid, [registration.id], context)
|
||||
else:
|
||||
unconfirmed_ids.append(registration.id)
|
||||
if unconfirmed_ids:
|
||||
@@ -368,12 +465,35 @@ and users by email"),
|
||||
}
|
||||
return True
|
||||
|
||||
def button_reg_close(self, cr, uid, ids, *args):
|
||||
def button_reg_close(self, cr, uid, ids, context=None):
|
||||
"""This Function Close Event Registration.
|
||||
"""
|
||||
registrations = self.browse(cr, uid, ids)
|
||||
self._history(cr, uid, registrations, _('Done'))
|
||||
self.write(cr, uid, ids, {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
if not context:
|
||||
context = {}
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
unclosed_ids = []
|
||||
for registration in self.browse(cr, uid, ids, context=context):
|
||||
if registration.tobe_invoiced and not registration.invoice_id:
|
||||
unclosed_ids.append(registration.id)
|
||||
else:
|
||||
self.do_close(cr, uid, [registration.id])
|
||||
if unclosed_ids:
|
||||
view_id = data_pool._get_id(cr, uid, 'event', 'view_event_make_invoice')
|
||||
view_data = data_pool.browse(cr, uid, view_id)
|
||||
view_id = view_data.res_id
|
||||
context['active_ids'] = unclosed_ids
|
||||
return {
|
||||
'name': _('Close Registration'),
|
||||
'context': context,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'event.make.invoice',
|
||||
'views': [(view_id, 'form')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'context': context,
|
||||
'nodestroy': True
|
||||
}
|
||||
return True
|
||||
|
||||
def button_reg_cancel(self, cr, uid, ids, *args):
|
||||
@@ -391,7 +511,6 @@ and users by email"),
|
||||
event = event_obj.browse(cr, uid, values['event_id'], context=context)
|
||||
values['date_deadline']= event.date_begin
|
||||
values['description']= event.mail_confirm
|
||||
values['currency_id'] = event.currency_id.id
|
||||
res = super(event_registration, self).create(cr, uid, values, context=context)
|
||||
registrations = self.browse(cr, uid, [res], context=context)
|
||||
self._history(cr, uid, registrations, _('Created'))
|
||||
@@ -414,32 +533,35 @@ and users by email"),
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
for reg_id in self.browse(cr, uid, ids):
|
||||
src = reg_id.event_id.reply_to or False
|
||||
dest = []
|
||||
if reg_id.email_from:
|
||||
dest += [reg_id.email_from]
|
||||
if reg_id.email_cc:
|
||||
dest += [reg_id.email_cc]
|
||||
if dest and src:
|
||||
if confirm:
|
||||
tools.email_send(src, dest,
|
||||
_('Auto Confirmation: [%s] %s') %(reg_id.id, reg_id.name),
|
||||
reg_id.event_id.mail_confirm,
|
||||
openobject_id = reg_id.id)
|
||||
elif reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
|
||||
if reg_id.event_id.state in ['draft', 'fixed', 'open', 'confirm', 'running'] and reg_id.event_id.mail_auto_registr:
|
||||
tools.email_send(src, dest,
|
||||
_('Auto Registration: [%s] %s') %(reg_id.id, reg_id.name),
|
||||
reg_id.event_id.mail_registr, openobject_id = reg_id.id)
|
||||
if (reg_id.event_id.state in ['confirm', 'running']) and reg_id.event_id.mail_auto_confirm:
|
||||
tools.email_send(src, dest,
|
||||
_('Auto Confirmation: [%s] %s') %(reg_id.id, reg_id.name),
|
||||
reg_id.event_id.mail_confirm, openobject_id = reg_id.id)
|
||||
|
||||
if not src:
|
||||
raise osv.except_osv(_('Error!'), _('You must define a reply-to address in order to mail the participant. You can do this in the Mailing tab of your event. Note that this is also the place where you can configure your event to not send emails automaticly while registering'))
|
||||
|
||||
for regestration in self.browse(cr, uid, ids, context=context):
|
||||
src = regestration.event_id.reply_to or False
|
||||
email_to = []
|
||||
email_cc = []
|
||||
if regestration.email_from:
|
||||
email_to = regestration.email_from
|
||||
if regestration.email_cc:
|
||||
email_cc += [regestration.email_cc]
|
||||
if not (email_to and email_cc):
|
||||
continue
|
||||
subject = ""
|
||||
body = ""
|
||||
if confirm:
|
||||
subject = _('Auto Confirmation: [%s] %s') %(regestration.id, regestration.name)
|
||||
body = regestration.event_id.mail_confirm
|
||||
elif regestration.event_id.mail_auto_confirm or regestration.event_id.mail_auto_registr:
|
||||
if regestration.event_id.state in ['draft', 'fixed', 'open', 'confirm', 'running'] and regestration.event_id.mail_auto_registr:
|
||||
subject = _('Auto Registration: [%s] %s') %(regestration.id, regestration.name)
|
||||
body = regestration.event_id.mail_registr
|
||||
if (regestration.event_id.state in ['confirm', 'running']) and regestration.event_id.mail_auto_confirm:
|
||||
subject = _('Auto Confirmation: [%s] %s') %(regestration.id, regestration.name)
|
||||
body = regestration.event_id.mail_confirm
|
||||
if subject or body:
|
||||
tools.email_send(src, email_to, subject, body, email_cc = email_cc, openobject_id = regestration.id)
|
||||
self.history(cr, uid, [regestration], subject, history=True, \
|
||||
email=email_to, details=body, \
|
||||
subject=subject, email_from=src, \
|
||||
email_cc=', '.join(email_cc))
|
||||
|
||||
return True
|
||||
|
||||
def mail_user_confirm(self, cr, uid, ids, context=None):
|
||||
@@ -451,22 +573,7 @@ and users by email"),
|
||||
def _create_invoice_lines(self, cr, uid, ids, vals):
|
||||
""" Create account Invoice line for Registration Id.
|
||||
"""
|
||||
return self.pool.get('account.invoice.line').create(cr, uid, vals)
|
||||
|
||||
def onchange_badge_name(self, cr, uid, ids, badge_name):
|
||||
"""This function returns value of Registration Name based on Partner Badge Name.
|
||||
@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 Registration IDs
|
||||
@param badge_name: Badge Name
|
||||
"""
|
||||
|
||||
data ={}
|
||||
if not badge_name:
|
||||
return data
|
||||
data['name'] = 'Registration: ' + badge_name
|
||||
return {'value': data}
|
||||
return self.pool.get('account.invoice.line').create(cr, uid, vals)
|
||||
|
||||
def onchange_contact_id(self, cr, uid, ids, contact, partner):
|
||||
|
||||
@@ -486,15 +593,11 @@ and users by email"),
|
||||
job_obj = self.pool.get('res.partner.job')
|
||||
|
||||
contact_id = contact_obj.browse(cr, uid, contact)
|
||||
data['badge_name'] = contact_id.name
|
||||
data['badge_title'] = contact_id.title.name
|
||||
if partner:
|
||||
partner_addresses = addr_obj.search(cr, uid, [('partner_id', '=', partner)])
|
||||
job_ids = job_obj.search(cr, uid, [('contact_id', '=', contact), ('address_id', 'in', partner_addresses)])
|
||||
if job_ids:
|
||||
data['email_from'] = job_obj.browse(cr, uid, job_ids[0]).email
|
||||
d = self.onchange_badge_name(cr, uid, ids, data['badge_name'])
|
||||
data.update(d['value'])
|
||||
return {'value': data}
|
||||
|
||||
def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
|
||||
@@ -515,20 +618,17 @@ and users by email"),
|
||||
res_obj = self.pool.get('res.partner')
|
||||
|
||||
data_event = event_obj.browse(cr, uid, event_id)
|
||||
context['currency_id'] = data_event.currency_id.id
|
||||
res = {'value': {'unit_price': False, 'event_product': False, 'user_id': False}}
|
||||
if data_event.user_id.id:
|
||||
return {'value': {'user_id':data_event.user_id.id}}
|
||||
|
||||
res['value'].update({'user_id':data_event.user_id.id})
|
||||
if data_event.product_id:
|
||||
if not partner_invoice_id:
|
||||
unit_price=prod_obj.price_get(cr, uid, [data_event.product_id.id], context=context)[data_event.product_id.id]
|
||||
return {'value': {'unit_price': unit_price, 'event_product': data_event.product_id.name, 'currency_id': data_event.currency_id.id}}
|
||||
data_partner = res_obj.browse(cr, uid, partner_invoice_id)
|
||||
context.update({'partner_id': data_partner})
|
||||
unit_price = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': data_partner.property_product_pricelist.id})[data_event.product_id.id]
|
||||
return {'value': {'unit_price': unit_price, 'event_product': data_event.product_id.name, 'currency_id': data_event.currency_id.id}}
|
||||
|
||||
return {'value': {'unit_price': False, 'event_product': False}}
|
||||
pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False
|
||||
if partner_invoice_id:
|
||||
partner = res_obj.browse(cr, uid, partner_invoice_id, context=context)
|
||||
pricelist_id = pricelist_id or partner.property_product_pricelist.id
|
||||
unit_price = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id]
|
||||
res['value'].update({'unit_price': unit_price, 'event_product': data_event.product_id.name})
|
||||
return res
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
|
||||
"""This function returns value of Patner Invoice id, Unit Price, badget title based on partner and Event.
|
||||
@@ -542,8 +642,8 @@ and users by email"),
|
||||
job_obj = self.pool.get('res.partner.job')
|
||||
res_obj = self.pool.get('res.partner')
|
||||
|
||||
data={}
|
||||
data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
|
||||
data = {}
|
||||
data['contact_id'], data['partner_invoice_id'], data['email_from'] = (False, False, False)
|
||||
if not part:
|
||||
return {'value': data}
|
||||
data['partner_invoice_id']=part
|
||||
@@ -559,9 +659,7 @@ and users by email"),
|
||||
data['contact_id'] = job_obj.browse(cr, uid, job_ids[0]).contact_id.id
|
||||
d = self.onchange_contact_id(cr, uid, ids, data['contact_id'], part)
|
||||
data.update(d['value'])
|
||||
partner_data = res_obj.browse(cr, uid, part)
|
||||
data['badge_partner'] = partner_data.name
|
||||
|
||||
partner_data = res_obj.browse(cr, uid, part)
|
||||
return {'value': data}
|
||||
|
||||
def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
|
||||
@@ -584,17 +682,26 @@ and users by email"),
|
||||
return {'value': data}
|
||||
data_event = event_obj.browse(cr, uid, event_id)
|
||||
if data_event.product_id:
|
||||
data['event_product']=data_event.product_id.name
|
||||
if not partner_invoice_id:
|
||||
data['unit_price']=prod_obj.price_get(cr, uid, [data_event.product_id.id], context=context)[data_event.product_id.id]
|
||||
return {'value': data}
|
||||
data_partner = res_obj.browse(cr, uid, partner_invoice_id)
|
||||
context.update({'partner_id': data_partner})
|
||||
data['unit_price'] = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': data_partner.property_product_pricelist.id})[data_event.product_id.id]
|
||||
return {'value': data}
|
||||
data['event_product'] = data_event.product_id.name
|
||||
pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False
|
||||
if partner_invoice_id:
|
||||
partner = res_obj.browse(cr, uid, partner_invoice_id, context=context)
|
||||
pricelist_id = pricelist_id or partner.property_product_pricelist.id
|
||||
data['unit_price'] = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id]
|
||||
return {'value': data}
|
||||
|
||||
event_registration()
|
||||
|
||||
class event_registration_badge(osv.osv):
|
||||
_name = 'event.registration.badge'
|
||||
_description = __doc__
|
||||
_columns = {
|
||||
'registration_id': fields.many2one('event.registration', 'Registration', required=True),
|
||||
"title": fields.char('Title', size=128),
|
||||
"name": fields.char('Name', size=128, required=True),
|
||||
"address_id": fields.many2one('res.partner.address', 'Address'),
|
||||
}
|
||||
event_registration_badge()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
<!-- Demo data for Event -->
|
||||
<record id="event_0" model="event.event">
|
||||
<field name="name">Concert of Bon Jovi</field>
|
||||
<field name="date_begin">2008-01-01 19:00:00</field>
|
||||
<field name="date_end">2008-01-01 23:00:00</field>
|
||||
<field eval="time.strftime('%Y-%m-01 19:05:15')" name="date_begin"/>
|
||||
<field eval="time.strftime('%Y-%m-01 23:05:15')" name="date_end"/>
|
||||
<field name="product_id" ref="event_product_0"/>
|
||||
<field name="unit_price">68.00</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
@@ -64,33 +64,11 @@
|
||||
<field name="type" ref="event_type_1"/>
|
||||
<field name="state">draft</field>
|
||||
</record>
|
||||
<!--
|
||||
<record id="demo_event_0bis" model="event.event">
|
||||
<field name="name">Concert of Bon Jovi - Brussel</field>
|
||||
<field name="date_begin">2008-02-02 19:00:00</field>
|
||||
<field name="date_end">2008-02-02 23:00:00</field>
|
||||
<field name="product_id" ref="event_product_0"/>
|
||||
<field name="parent_id" ref="event_0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="register_max">500</field>
|
||||
<field name="type" ref="event_type_1"/>
|
||||
</record>
|
||||
|
||||
<record id="demo_event_0ter" model="event.event">
|
||||
<field name="name">Concert of Bon Jovi - London</field>
|
||||
<field name="date_begin">2008-04-04 19:00:00</field>
|
||||
<field name="date_end">2008-04-04 23:00:00</field>
|
||||
<field name="product_id" ref="event_product_0"/>
|
||||
<field name="parent_id" ref="event_0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="register_max">500</field>
|
||||
<field name="type" ref="event_type_1"/>
|
||||
</record>
|
||||
-->
|
||||
<record id="event_1" model="event.event">
|
||||
<field name="name">Opera of Verdi</field>
|
||||
<field name="date_begin">2008-03-05 18:00:00</field>
|
||||
<field name="date_end">2008-03-05 21:00:00</field>
|
||||
<field eval="time.strftime('%Y-%m-05 18:00:00')" name="date_begin"/>
|
||||
<field eval="time.strftime('%Y-%m-05 21:00:00')" name="date_end"/>
|
||||
<field name="product_id" ref="event_product_1"/>
|
||||
<field name="unit_price">24.00</field>
|
||||
<field name="type" ref="event_type_1"/>
|
||||
@@ -101,8 +79,8 @@
|
||||
|
||||
<record id="event_2" model="event.event">
|
||||
<field name="name">Conference on ERP Buisness</field>
|
||||
<field name="date_begin">2008-09-09 14:00:00</field>
|
||||
<field name="date_end">2008-09-09 16:30:00</field>
|
||||
<field eval="time.strftime('%Y-%m-05 14:00:00')" name="date_begin"/>
|
||||
<field eval="time.strftime('%Y-%m-05 16:30:00')" name="date_end"/>
|
||||
<field name="product_id" ref="event_product_2"/>
|
||||
<field name="unit_price">15.50</field>
|
||||
<field name="type" ref="event_type_2"/>
|
||||
|
||||
+128
-85
@@ -45,31 +45,33 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="Events">
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" string="Event" select="1"/>
|
||||
<field name="type" widget="selection"/>
|
||||
<field name="user_id" select="1"/>
|
||||
<field name="date_begin" select="1"/>
|
||||
<field name="name" string="Event"/>
|
||||
<field name="date_begin"/>
|
||||
<field name="date_end"/>
|
||||
<field name="product_id" on_change="onchange_product(product_id)"/>
|
||||
<field name="type" widget="selection"/>
|
||||
<field name="language"/>
|
||||
<field name="parent_id"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Event Information">
|
||||
<separator string="Description" colspan="4"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="currency_id"/>
|
||||
<field name="register_min"/>
|
||||
<field name="register_max"/>
|
||||
<field name="parent_id" domain="[('parent_id','child_of','Event')]"/>
|
||||
<field name="active"/>
|
||||
<separator string="Location" colspan="4"/>
|
||||
<field name="country_id" />
|
||||
<field name="language"/>
|
||||
<field name="address_id"/>
|
||||
<separator string="Speaker Information" colspan="4"/>
|
||||
<field name="main_speaker_id" domain="[('speaker','=',True)]"/>
|
||||
<field name="speaker_confirmed"/>
|
||||
<field name="speaker_ids" domain="[('speaker','=',True)]" colspan="4"/>
|
||||
<newline/>
|
||||
<page string="Event">
|
||||
<group colspan="4" col="4">
|
||||
<separator string="Invoice Information" colspan="4"/>
|
||||
<field name="product_id" on_change="onchange_product(product_id)" colspan="4"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="pricelist_id" domain="[('type','=','sale')]" groups="base.group_extended"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Contact" colspan="4"/>
|
||||
<field name="user_id"/>
|
||||
<field name="section_id" widget="selection" on_change="do_team_change(section_id)"/>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Location" colspan="4"/>
|
||||
<field name="country_id" />
|
||||
<field name="address_id" domain="[('country_id','=',country_id)]"/>
|
||||
|
||||
</group>
|
||||
<field name="state" select="1"/>
|
||||
<group col="4" colspan="2">
|
||||
<button string="Confirm Event" name="button_confirm" states="draft" type="object" icon="gtk-apply"/>
|
||||
@@ -77,8 +79,54 @@
|
||||
<button string="Event Done" name="button_done" states="confirm" type="object" icon="gtk-jump-to"/>
|
||||
<button string="Set To Draft" name="button_draft" states="confirm,cancel,done" type="object" icon="gtk-convert"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Speakers">
|
||||
<field name="main_speaker_id" domain="[('speaker','=',True)]"/>
|
||||
<field name="speaker_confirmed"/>
|
||||
<separator string="Other Speakers" colspan="4"/>
|
||||
<field name="speaker_ids" domain="[('speaker','=',True)]" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Mailing">
|
||||
<page string="Registrations">
|
||||
<field name="register_min"/>
|
||||
<field name="register_max"/>
|
||||
<field name="register_current"/>
|
||||
<field name="register_prospect"/>
|
||||
<field name="registration_ids" colspan="4" nolabel="1">
|
||||
<form string="Registration">
|
||||
<field name="name"/>
|
||||
<field name="date" string="Date"/>
|
||||
<field name="partner_id" required="1" on_change="onchange_partner_id(partner_id,event_id)"/>
|
||||
<field name="partner_invoice_id" on_change="onchange_partner_invoice_id(event_id, partner_invoice_id)"/>
|
||||
<group colspan="4" col="4">
|
||||
<field name="event_product"/>
|
||||
<field name="nb_register"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="price_subtotal"/>
|
||||
</group>
|
||||
<group col="8" colspan="4">
|
||||
<separator string="" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="state" select="1" colspan="2"/>
|
||||
<button name="button_reg_close" string="Close Registration" states="open" type="object" icon="gtk-close"/>
|
||||
<button name="check_confirm" string="Confirm Registration" states="draft" type="object" icon="gtk-apply"/>
|
||||
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object" icon="gtk-cancel"/>
|
||||
</group>
|
||||
</form>
|
||||
<tree string="Registration" editable="bottom">
|
||||
<field name="date" string="Date"/>
|
||||
<field name="partner_id" required="1" string="Partner" on_change="onchange_partner_id(partner_id,event_id)"/>
|
||||
<field name="event_product"/>
|
||||
<field name="nb_register"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="price_subtotal"/>
|
||||
<field name="state"/>
|
||||
<button name="button_reg_close" string="Close Registration" states="open" type="object" icon="gtk-close"/>
|
||||
<button name="check_confirm" string="Confirm Registration" states="draft" type="object" icon="gtk-apply"/>
|
||||
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object" icon="gtk-cancel"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Mailing">
|
||||
<field name="reply_to" />
|
||||
<newline/>
|
||||
|
||||
@@ -86,23 +134,18 @@
|
||||
<separator string="Auto Registration Email" colspan="2"/>
|
||||
<newline/>
|
||||
<field name="mail_auto_registr"/>
|
||||
<separator string="Registration Email" colspan="2"/>
|
||||
<separator string="Registration Email Body" colspan="2"/>
|
||||
<newline/>
|
||||
<field name="mail_registr" colspan="2" nolabel="1"/>
|
||||
<field name="mail_registr" colspan="2" nolabel="1" attrs="{'readonly':[('mail_auto_registr','=',False)]}"/>
|
||||
</group>
|
||||
<group col="2" colspan="2" >
|
||||
<separator string="Auto Confirmation Email" colspan="2"/>
|
||||
<field name="mail_auto_confirm"/>
|
||||
<newline/>
|
||||
<separator string="Confirmation Email" colspan="2"/>
|
||||
<field name="mail_confirm" colspan="2" nolabel="1"/>
|
||||
<separator string="Confirmation Email Body" colspan="2"/>
|
||||
<field name="mail_confirm" colspan="2" nolabel="1" attrs="{'readonly':[('mail_auto_confirm','=',False)]}"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Statistics">
|
||||
<separator string="Registrations" colspan="4"/>
|
||||
<field name="register_current"/>
|
||||
<field name="register_prospect"/>
|
||||
</page>
|
||||
<page string="Notes">
|
||||
<separator string="Notes" colspan="4"/>
|
||||
<field name="note" colspan="4" nolabel="1"/>
|
||||
@@ -129,6 +172,10 @@
|
||||
<field name="register_min"/>
|
||||
<field name="register_current"/>
|
||||
<field name="state"/>
|
||||
<button string="Confirm Event" help="Confirm Event" name="button_confirm" states="draft" type="object" icon="gtk-apply"/>
|
||||
<button string="Cancel Event" help="Cancel Event" name="button_cancel" states="draft,confirm" type="object" icon="gtk-cancel"/>
|
||||
<button string="Event Done" help="Event Done" name="button_done" states="confirm" type="object" icon="gtk-jump-to"/>
|
||||
<button string="Set To Draft" help="Set To Draft" name="button_draft" states="confirm,cancel,done" type="object" icon="gtk-convert"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -233,7 +280,6 @@
|
||||
|
||||
<!-- EVENTS/REGISTRATIONS/EVENTS -->
|
||||
|
||||
<!-- Registration view (form) by _inherits .................. -->
|
||||
|
||||
<record model="ir.ui.view" id="view_event_registration_tree">
|
||||
<field name="name">event.registration.tree</field>
|
||||
@@ -241,12 +287,15 @@
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Registration">
|
||||
<field name="id"/>
|
||||
<field name="create_date"/>
|
||||
<field name="date" string="Date"/>
|
||||
<field name="event_id"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="nb_register"/>
|
||||
<field name="price_subtotal"/>
|
||||
<field name="state"/>
|
||||
<button name="button_reg_close" string="Close Registration" states="open" type="object" icon="gtk-close"/>
|
||||
<button name="check_confirm" string="Confirm Registration" states="draft" type="object" icon="gtk-apply"/>
|
||||
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object" icon="gtk-cancel"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -258,31 +307,29 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="Registration">
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" select="1" colspan="2"/>
|
||||
<field name="event_id" select="1" on_change="onchange_event(event_id, partner_invoice_id)" domain="[('state','in',('draft','confirm'))]"/>
|
||||
<field name="user_id" select="1"/>
|
||||
<newline/>
|
||||
<field name="partner_id" required="1" select="1" on_change="onchange_partner_id(partner_id,event_id)" />
|
||||
<field name="event_id" on_change="onchange_event(event_id, partner_invoice_id)" domain="[('state','in',('draft','confirm'))]"/>
|
||||
<field name="date" string="Registration Date"/>
|
||||
<field name="name"/>
|
||||
<field name="partner_id" required="1" on_change="onchange_partner_id(partner_id,event_id)" />
|
||||
<field name="partner_invoice_id" on_change="onchange_partner_invoice_id(event_id, partner_invoice_id)"/>
|
||||
<field name="user_id"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="General">
|
||||
<group colspan="4" col="6">
|
||||
<page string="Registration">
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Invoice" colspan="4"/>
|
||||
<field name="event_product"/>
|
||||
<field name="invoice_id"/>
|
||||
<field name="tobe_invoiced"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Registration Cost" colspan="4"/>
|
||||
<field name="nb_register"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="currency_id"/>
|
||||
</group>
|
||||
<separator string="Communication Information" colspan="4"/>
|
||||
<field name="contact_id" on_change="onchange_contact_id(contact_id, partner_id)" />
|
||||
<field name="email_from"/>
|
||||
<newline/>
|
||||
<separator string="Badge" colspan="4"/>
|
||||
<field name="badge_title"/>
|
||||
<field name="badge_name" on_change="onchange_badge_name(badge_name)"/>
|
||||
<field name="badge_partner"/>
|
||||
<newline/>
|
||||
<field name="price_subtotal"/>
|
||||
</group>
|
||||
<group col="8" colspan="4">
|
||||
<separator string="Status" colspan="4"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="state" select="1" colspan="2"/>
|
||||
<button name="button_reg_close" string="Close Registration" states="open" type="object" icon="gtk-close"/>
|
||||
@@ -290,10 +337,32 @@
|
||||
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object" icon="gtk-cancel"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Payments">
|
||||
<field name="event_product" select="1"/>
|
||||
<field name="tobe_invoiced" select="1"/>
|
||||
<field name="invoice_id"/>
|
||||
<page string="Extra Info">
|
||||
<separator string="Contact" colspan="4"/>
|
||||
<field name="contact_id" on_change="onchange_contact_id(contact_id, partner_id)" />
|
||||
<field name="email_from"/>
|
||||
<field name="badge_ids" colspan="4" nolabel="1">
|
||||
<tree string="Badges" editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="title"/>
|
||||
<field name="address_id"/>
|
||||
</tree>
|
||||
<form string="Badges">
|
||||
<field name="name"/>
|
||||
<field name="title"/>
|
||||
<field name="address_id"/>
|
||||
</form>
|
||||
</field>
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Dates" colspan="2"/>
|
||||
<field name="create_date"/>
|
||||
<field name="date_closed"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Misc" colspan="2"/>
|
||||
<field name="id"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Emails" groups="base.group_extended">
|
||||
<group colspan="4">
|
||||
@@ -333,33 +402,7 @@
|
||||
name="%(crm.action_crm_send_mail)d"
|
||||
context="{'mail':'new', 'model': 'event.registration'}"
|
||||
icon="gtk-go-forward" type="action" />
|
||||
</page>
|
||||
<page string="History">
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Dates" colspan="2"/>
|
||||
<field name="create_date"/>
|
||||
<field name="date_closed"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator string="Misc" colspan="2"/>
|
||||
<field name="id"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
<!-- TODO-->
|
||||
<field name="log_ids" nolabel="1" colspan="4">
|
||||
<tree string="Logs">
|
||||
<field name="name" colspan="4"/>
|
||||
<field name="date"/>
|
||||
<field name="user_id"/>
|
||||
</tree>
|
||||
<form string="Logs">
|
||||
<separator string="Action Information" colspan="4"/>
|
||||
<field name="name" colspan="4"/>
|
||||
<field name="date"/>
|
||||
<field name="user_id"/>
|
||||
</form>
|
||||
</field>
|
||||
</page>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -9,3 +9,5 @@
|
||||
"access_crm_case_section_manager","crm.case.section manager","crm.model_crm_case_section","event.group_event_manager",1,1,1,1
|
||||
"access_product_product","product.product.product manager","product.model_product_product","event.group_event_manager",1,1,1,1
|
||||
"access_report_event_registration","report.event.registration","model_report_event_registration","event.group_event_manager",1,1,1,1
|
||||
"access_event_registration_badge","event.registration.badge","model_event_registration_badge","event.group_event_subscriber",1,1,1,1
|
||||
"access_event_registration_badge","event.registration.badge","model_event_registration_badge","event.group_event_manager",1,1,1,1
|
||||
|
||||
|
@@ -54,7 +54,6 @@
|
||||
we create it with a "Conference on OpenERP Offshore Business" event and provide "Beginning date", "Ending Date" and "Product" as Concert Ticket.
|
||||
-
|
||||
!record {model: event.event, id: event_event_conference0}:
|
||||
code: C/004
|
||||
date_begin: '2010-06-07 13:39:00'
|
||||
date_end: '2010-06-10 13:39:00'
|
||||
name: Conference on OpenERP Offshore Business.
|
||||
@@ -94,8 +93,6 @@
|
||||
I create New Registration for "Conference on OpenERP Offshore Business.
|
||||
-
|
||||
!record {model: event.registration, id: event_registration_registrationjacot0}:
|
||||
badge_name: Jacot
|
||||
badge_partner: Mark Johnson
|
||||
contact_id: base_contact.res_partner_contact_jacot0
|
||||
date_deadline: '2010-06-07 13:39:00'
|
||||
event_id: event.event_event_conference0
|
||||
@@ -128,8 +125,6 @@
|
||||
They create New registraion for This event.
|
||||
-
|
||||
!record {model: event.registration, id: event_registration_registrationzen0}:
|
||||
badge_name: Zen
|
||||
badge_partner: China Export
|
||||
contact_id: base_contact.res_partner_contact_zen0
|
||||
date_deadline: '2010-06-07 13:39:00'
|
||||
event_id: event.event_event_conference0
|
||||
@@ -149,8 +144,6 @@
|
||||
Third person create New Registration for "Conference on OpenERP Offshore Business" event.
|
||||
-
|
||||
!record {model: event.registration, id: event_registration_registrationpassot0}:
|
||||
badge_name: Passot
|
||||
badge_partner: Mediapole SPRL
|
||||
contact_id: base_contact.res_partner_contact_passot0
|
||||
date_deadline: '2010-06-07 13:39:00'
|
||||
email_from: info@mediapole.net
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
|
||||
import event_make_invoice
|
||||
import event_confirm_registration
|
||||
import event_confirm
|
||||
import partner_event_registration
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
class event_confirm(osv.osv_memory):
|
||||
"""
|
||||
Confirm Event
|
||||
"""
|
||||
_name = "event.confirm"
|
||||
_description = "Event Confirmation"
|
||||
|
||||
_columns = {
|
||||
'msg': fields.text('Message', readonly=True),
|
||||
}
|
||||
_defaults = {
|
||||
'msg': _('Total Registrations of this Event could not reached Minimum Registration Limit. What do you want to do?')
|
||||
}
|
||||
|
||||
def confirm(self, cr, uid, ids, context):
|
||||
event_pool = self.pool.get('event.event')
|
||||
event_ids = context.get('event_ids', [])
|
||||
event_pool.do_confirm(cr, uid, event_ids, context=context)
|
||||
return {}
|
||||
|
||||
event_confirm()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -50,8 +50,8 @@ class event_confirm_registration(osv.osv_memory):
|
||||
register_max = registration.event_id.register_max
|
||||
if registration.event_id.id not in overlimit_event_ids:
|
||||
overlimit_event_ids.append(registration.event_id.id)
|
||||
msg += _("The Event '%s' is reached Maximum Limit(%s). It has %s Confirmed registration\n") \
|
||||
%(registration.event_id.name, register_max, total_confirmed)
|
||||
msg += _("The Event '%s' is reached Maximum Limit(%s).") \
|
||||
%(registration.event_id.name, register_max)
|
||||
if 'msg' in fields:
|
||||
res.update({'msg': msg})
|
||||
|
||||
@@ -60,10 +60,7 @@ class event_confirm_registration(osv.osv_memory):
|
||||
def confirm(self, cr, uid, ids, context):
|
||||
registration_pool = self.pool.get('event.registration')
|
||||
registration_ids = context.get('registration_ids', [])
|
||||
for reg_id in registration_ids:
|
||||
registration_pool.write(cr, uid, [reg_id], {'state':'open', })
|
||||
registration_pool._history(cr, uid, [reg_id], _('Open'))
|
||||
registration_pool.mail_user(cr, uid, [reg_id])
|
||||
registration_pool.do_open(cr, uid, registration_ids, context=context)
|
||||
return {}
|
||||
|
||||
event_confirm_registration()
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_event_confirm" model="ir.ui.view">
|
||||
<field name="name">Event Confirmation</field>
|
||||
<field name="model">event.confirm</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Event Confirmation">
|
||||
<field name="msg" nolabel="1" colspan="4"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<group colspan="4" col="6">
|
||||
<button icon="gtk-close" special="cancel" string="Close"/>
|
||||
<button icon="gtk-ok" name="confirm" string="Confirm Anyway" type="object"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_event_confirm" model="ir.actions.act_window">
|
||||
<field name="name">Event Confirmation</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">event.confirm</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_event_confirm"/>
|
||||
<field name="context">{'record_id' : active_id}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -10,21 +10,11 @@
|
||||
<field name="inherit_id" ref="event.view_event_form"/>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="register_max" position="after">
|
||||
<notebook position="inside">
|
||||
<page string="Tasks">
|
||||
<separator string="Tasks management" colspan="4"/>
|
||||
<field name="project_id"/>
|
||||
<button string="Create Retro-Planning" name="%(action_event_project)d" type="action" icon="gtk-execute"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_event_form_inherited2">
|
||||
<field name="name">Events</field>
|
||||
<field name="model">event.event</field>
|
||||
<field name="inherit_id" ref="event.view_event_form"/>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="register_prospect" position="after">
|
||||
<field name="task_ids" colspan="4" nolabel="1" widget="one2many_list" >
|
||||
<tree string="All tasks" colors="red:date_deadline<current_date and state=='draft';blue:date_deadline==current_date and state=='draft';grey:state in ('cancel','done');black:state not in ('cancel','done')">
|
||||
<field name="sequence"/>
|
||||
@@ -36,10 +26,10 @@
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window
|
||||
id="act_event_task"
|
||||
name="Tasks"
|
||||
|
||||
@@ -32,7 +32,6 @@ based on geolocalization.
|
||||
'depends': ['crm'],
|
||||
'data': [
|
||||
'res_partner_view.xml',
|
||||
'crm_lead_view.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
|
||||
@@ -214,7 +214,7 @@ class project_task(osv.osv):
|
||||
|
||||
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||
if not context:
|
||||
context = context
|
||||
context = {}
|
||||
if not context.get('planning'):
|
||||
return super(project_task,self).search(cr, user, args, offset, limit, order, context)
|
||||
cr.execute(" SELECT t.id, t.name \
|
||||
@@ -498,7 +498,7 @@ class report_account_analytic_planning_stat(osv.osv):
|
||||
WHERE user_id=%s and account_id=%s and date>=%s and date<=%s''', (line.user_id.id, line.account_id.id, line.planning_id.date_from, line.planning_id.date_to))
|
||||
else:
|
||||
cr.execute('SELECT sum(unit_amount) FROM account_analytic_line WHERE account_id=%s AND date>=%s AND date<=%s', (line.account_id.id, line.planning_id.date_from, line.planning_id.date_to))
|
||||
|
||||
|
||||
sum = cr.fetchone()
|
||||
if sum and sum[0]:
|
||||
result[line.id] = sum[0] * div2
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user