[MERGE] upsteam
bzr revid: fme@openerp.com-20140509144608-btah4s8zorzon2jo
This commit is contained in:
commit
7caabb8f75
|
@ -409,9 +409,7 @@ class account_invoice(osv.osv):
|
||||||
'''
|
'''
|
||||||
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
|
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
|
||||||
self.write(cr, uid, ids, {'sent': True}, context=context)
|
self.write(cr, uid, ids, {'sent': True}, context=context)
|
||||||
context2 = context.copy()
|
return self.pool['report'].get_action(cr, uid, ids, 'account.report_invoice', context=context)
|
||||||
context2['active_ids'] = ids
|
|
||||||
return self.pool['report'].get_action(cr, uid, [], 'account.report_invoice', context=context2)
|
|
||||||
|
|
||||||
def action_invoice_sent(self, cr, uid, ids, context=None):
|
def action_invoice_sent(self, cr, uid, ids, context=None):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -1026,7 +1026,7 @@ class account_move_line(osv.osv):
|
||||||
if opening_reconciliation:
|
if opening_reconciliation:
|
||||||
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
|
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
|
||||||
obj_move_rec.unlink(cr, uid, unlink_ids)
|
obj_move_rec.unlink(cr, uid, unlink_ids)
|
||||||
if all_moves:
|
if len(all_moves) >= 2:
|
||||||
obj_move_line.reconcile_partial(cr, uid, all_moves, 'auto',context=context)
|
obj_move_line.reconcile_partial(cr, uid, all_moves, 'auto',context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,8 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//div[@name='buttons']" position="inside">
|
<xpath expr="//div[@name='buttons']" position="inside">
|
||||||
<button type="action" string="Invoices"
|
<button type="action" string="Invoices"
|
||||||
name="%(account.action_invoice_tree)d"
|
name="%(account.action_invoice_tree1)d"
|
||||||
|
attrs="{'invisible': [('customer', '=', False)]}"
|
||||||
context="{'search_default_partner_id': active_id,'default_partner_id': active_id}" groups="account.group_account_invoice"/>
|
context="{'search_default_partner_id': active_id,'default_partner_id': active_id}" groups="account.group_account_invoice"/>
|
||||||
<button type="action" string="Journal Items" name="%(account.action_account_moves_all_tree)d" groups="account.group_account_user"/>
|
<button type="action" string="Journal Items" name="%(account.action_account_moves_all_tree)d" groups="account.group_account_user"/>
|
||||||
<button type="action" string="Contracts" name="%(account.action_open_partner_analytic_accounts)d"
|
<button type="action" string="Contracts" name="%(account.action_open_partner_analytic_accounts)d"
|
||||||
|
|
|
@ -50,6 +50,6 @@ class account_analytic_balance(osv.osv_memory):
|
||||||
|
|
||||||
datas['form']['active_ids'] = context.get('active_ids', False)
|
datas['form']['active_ids'] = context.get('active_ids', False)
|
||||||
|
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_analyticbalance', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_analyticbalance', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -49,6 +49,6 @@ class account_analytic_cost_ledger_journal_report(osv.osv_memory):
|
||||||
}
|
}
|
||||||
|
|
||||||
datas['form']['active_ids'] = context.get('active_ids', False)
|
datas['form']['active_ids'] = context.get('active_ids', False)
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_analyticcostledgerquantity', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_analyticcostledgerquantity', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -49,6 +49,6 @@ class account_analytic_cost_ledger(osv.osv_memory):
|
||||||
|
|
||||||
datas['form']['active_ids'] = context.get('active_ids', False)
|
datas['form']['active_ids'] = context.get('active_ids', False)
|
||||||
|
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_analyticcostledger', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_analyticcostledger', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -47,6 +47,6 @@ class account_analytic_inverted_balance(osv.osv_memory):
|
||||||
'form': data
|
'form': data
|
||||||
}
|
}
|
||||||
datas['form']['active_ids'] = context.get('active_ids', False)
|
datas['form']['active_ids'] = context.get('active_ids', False)
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_invertedanalyticbalance', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_invertedanalyticbalance', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -57,7 +57,7 @@ class account_analytic_journal_report(osv.osv_memory):
|
||||||
context2 = context.copy()
|
context2 = context.copy()
|
||||||
context2['active_model'] = 'account.analytic.journal'
|
context2['active_model'] = 'account.analytic.journal'
|
||||||
context2['active_ids'] = ids_list
|
context2['active_ids'] = ids_list
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_analyticjournal', data=datas, context=context2)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_analyticjournal', data=datas, context=context2)
|
||||||
|
|
||||||
def default_get(self, cr, uid, fields, context=None):
|
def default_get(self, cr, uid, fields, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>Quantity</th>
|
<th>Quantity</th>
|
||||||
<th groups="product.group_uom">Unit of measure</th>
|
|
||||||
<th class="text-right">Unit Price</th>
|
<th class="text-right">Unit Price</th>
|
||||||
<th class="text-right" groups="sale.group_discount_per_so_line">Discount (%)</th>
|
<th class="text-right" groups="sale.group_discount_per_so_line">Discount (%)</th>
|
||||||
<th class="text-right">Taxes</th>
|
<th class="text-right">Taxes</th>
|
||||||
|
@ -57,8 +56,10 @@
|
||||||
<tbody class="invoice_tbody">
|
<tbody class="invoice_tbody">
|
||||||
<tr t-foreach="o.invoice_line" t-as="l">
|
<tr t-foreach="o.invoice_line" t-as="l">
|
||||||
<td><span t-field="l.name"/></td>
|
<td><span t-field="l.name"/></td>
|
||||||
<td><span t-field="l.quantity"/></td>
|
<td>
|
||||||
<td groups="product.group_uom"><span t-field="l.uos_id"/></td>
|
<span t-field="l.quantity"/>
|
||||||
|
<span t-field="l.uos_id" groups="product.group_uom"/>
|
||||||
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<span t-field="l.price_unit"/>
|
<span t-field="l.price_unit"/>
|
||||||
</td>
|
</td>
|
||||||
|
@ -100,7 +101,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row" t-if="o.tax_line">
|
<div class="row" t-if="o.tax_line">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-6">
|
||||||
<table class="table table-condensed">
|
<table class="table table-condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -136,7 +137,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p t-if="o.fiscal_position">
|
<p t-if="o.fiscal_position">
|
||||||
<strong>Fiscal Position:</strong>
|
<strong>Fiscal Position:</strong>
|
||||||
<span t-field="o.fiscal_position.note"/>
|
<span t-field="o.fiscal_position"/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
|
|
|
@ -89,6 +89,6 @@ class accounting_report(osv.osv_memory):
|
||||||
|
|
||||||
def _print_report(self, cr, uid, ids, data, context=None):
|
def _print_report(self, cr, uid, ids, data, context=None):
|
||||||
data['form'].update(self.read(cr, uid, ids, ['date_from_cmp', 'debit_credit', 'date_to_cmp', 'fiscalyear_id_cmp', 'period_from_cmp', 'period_to_cmp', 'filter_cmp', 'account_report_id', 'enable_filter', 'label_filter','target_move'], context=context)[0])
|
data['form'].update(self.read(cr, uid, ids, ['date_from_cmp', 'debit_credit', 'date_to_cmp', 'fiscalyear_id_cmp', 'period_from_cmp', 'period_to_cmp', 'filter_cmp', 'account_report_id', 'enable_filter', 'label_filter','target_move'], context=context)[0])
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_financial', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_financial', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
|
||||||
|
|
||||||
class account_balance_report(osv.osv_memory):
|
class account_balance_report(osv.osv_memory):
|
||||||
_inherit = "account.common.account.report"
|
_inherit = "account.common.account.report"
|
||||||
_name = 'account.balance.report'
|
_name = 'account.balance.report'
|
||||||
|
@ -36,6 +37,6 @@ class account_balance_report(osv.osv_memory):
|
||||||
|
|
||||||
def _print_report(self, cr, uid, ids, data, context=None):
|
def _print_report(self, cr, uid, ids, data, context=None):
|
||||||
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_trialbalance', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_trialbalance', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -81,6 +81,6 @@ class account_aged_trial_balance(osv.osv_memory):
|
||||||
data['form'].update(res)
|
data['form'].update(res)
|
||||||
if data.get('form',False):
|
if data.get('form',False):
|
||||||
data['ids']=[data['form'].get('chart_account_id',False)]
|
data['ids']=[data['form'].get('chart_account_id',False)]
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_agedpartnerbalance', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_agedpartnerbalance', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
|
||||||
|
|
||||||
class account_central_journal(osv.osv_memory):
|
class account_central_journal(osv.osv_memory):
|
||||||
_name = 'account.central.journal'
|
_name = 'account.central.journal'
|
||||||
_description = 'Account Central Journal'
|
_description = 'Account Central Journal'
|
||||||
|
@ -32,6 +33,6 @@ class account_central_journal(osv.osv_memory):
|
||||||
|
|
||||||
def _print_report(self, cr, uid, ids, data, context=None):
|
def _print_report(self, cr, uid, ids, data, context=None):
|
||||||
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_centraljournal', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_centraljournal', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
|
||||||
|
|
||||||
class account_general_journal(osv.osv_memory):
|
class account_general_journal(osv.osv_memory):
|
||||||
_inherit = "account.common.journal.report"
|
_inherit = "account.common.journal.report"
|
||||||
_name = 'account.general.journal'
|
_name = 'account.general.journal'
|
||||||
|
@ -32,6 +33,6 @@ class account_general_journal(osv.osv_memory):
|
||||||
|
|
||||||
def _print_report(self, cr, uid, ids, data, context=None):
|
def _print_report(self, cr, uid, ids, data, context=None):
|
||||||
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_generaljournal', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_generaljournal', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -59,6 +59,6 @@ class account_report_general_ledger(osv.osv_memory):
|
||||||
if data['form']['landscape'] is False:
|
if data['form']['landscape'] is False:
|
||||||
data['form'].pop('landscape')
|
data['form'].pop('landscape')
|
||||||
|
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_generalledger', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_generalledger', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -44,6 +44,6 @@ class account_partner_balance(osv.osv_memory):
|
||||||
context = {}
|
context = {}
|
||||||
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
||||||
data['form'].update(self.read(cr, uid, ids, ['display_partner'])[0])
|
data['form'].update(self.read(cr, uid, ids, ['display_partner'])[0])
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_partnerbalance', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_partnerbalance', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -58,7 +58,7 @@ class account_partner_ledger(osv.osv_memory):
|
||||||
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
||||||
data['form'].update(self.read(cr, uid, ids, ['initial_balance', 'filter', 'page_split', 'amount_currency'])[0])
|
data['form'].update(self.read(cr, uid, ids, ['initial_balance', 'filter', 'page_split', 'amount_currency'])[0])
|
||||||
if data['form'].get('page_split') is True:
|
if data['form'].get('page_split') is True:
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_partnerledgerother', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_partnerledgerother', data=data, context=context)
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_partnerledger', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_partnerledger', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -67,8 +67,8 @@ class account_print_journal(osv.osv_memory):
|
||||||
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
data = self.pre_print_report(cr, uid, ids, data, context=context)
|
||||||
data['form'].update(self.read(cr, uid, ids, ['sort_selection'], context=context)[0])
|
data['form'].update(self.read(cr, uid, ids, ['sort_selection'], context=context)[0])
|
||||||
if context.get('sale_purchase_only'):
|
if context.get('sale_purchase_only'):
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_salepurchasejournal', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_salepurchasejournal', data=data, context=context)
|
||||||
else:
|
else:
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_journal', data=data, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_journal', data=data, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -61,6 +61,6 @@ class account_vat_declaration(osv.osv_memory):
|
||||||
taxcode = taxcode_obj.browse(cr, uid, [taxcode_id], context=context)[0]
|
taxcode = taxcode_obj.browse(cr, uid, [taxcode_id], context=context)[0]
|
||||||
datas['form']['company_id'] = taxcode.company_id.id
|
datas['form']['company_id'] = taxcode.company_id.id
|
||||||
|
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account.report_vat', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account.report_vat', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -73,9 +73,7 @@ class account_analytic_invoice_line(osv.osv):
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
res = self.pool.get('product.product').browse(cr, uid, product, context=context)
|
res = self.pool.get('product.product').browse(cr, uid, product, context=context)
|
||||||
result.update({'name':res.partner_ref or False,'uom_id': uom_id or res.uom_id.id or False, 'price_unit': res.list_price or 0.0})
|
result.update({'name': name or res.description or False,'uom_id': uom_id or res.uom_id.id or False, 'price_unit': price_unit or res.list_price or 0.0})
|
||||||
if res.description:
|
|
||||||
result['name'] += '\n'+res.description
|
|
||||||
|
|
||||||
res_final = {'value':result}
|
res_final = {'value':result}
|
||||||
if result['uom_id'] != res.uom_id.id:
|
if result['uom_id'] != res.uom_id.id:
|
||||||
|
@ -544,18 +542,17 @@ class account_analytic_account(osv.osv):
|
||||||
'nodestroy': True,
|
'nodestroy': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def on_change_template(self, cr, uid, ids, template_id, date_start=False, fix_price_invoices=False, invoice_on_timesheets=False, recurring_invoices=False, context=None):
|
def on_change_template(self, cr, uid, ids, template_id, date_start=False, context=None):
|
||||||
if not template_id:
|
if not template_id:
|
||||||
return {}
|
return {}
|
||||||
obj_analytic_line = self.pool.get('account.analytic.invoice.line')
|
|
||||||
res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context)
|
res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context)
|
||||||
|
|
||||||
template = self.browse(cr, uid, template_id, context=context)
|
template = self.browse(cr, uid, template_id, context=context)
|
||||||
|
|
||||||
if not fix_price_invoices:
|
if not ids:
|
||||||
res['value']['fix_price_invoices'] = template.fix_price_invoices
|
res['value']['fix_price_invoices'] = template.fix_price_invoices
|
||||||
res['value']['amount_max'] = template.amount_max
|
res['value']['amount_max'] = template.amount_max
|
||||||
if not invoice_on_timesheets:
|
if not ids:
|
||||||
res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets
|
res['value']['invoice_on_timesheets'] = template.invoice_on_timesheets
|
||||||
res['value']['hours_qtt_est'] = template.hours_qtt_est
|
res['value']['hours_qtt_est'] = template.hours_qtt_est
|
||||||
|
|
||||||
|
@ -563,7 +560,7 @@ class account_analytic_account(osv.osv):
|
||||||
res['value']['to_invoice'] = template.to_invoice.id
|
res['value']['to_invoice'] = template.to_invoice.id
|
||||||
if template.pricelist_id.id:
|
if template.pricelist_id.id:
|
||||||
res['value']['pricelist_id'] = template.pricelist_id.id
|
res['value']['pricelist_id'] = template.pricelist_id.id
|
||||||
if not recurring_invoices:
|
if not ids:
|
||||||
invoice_line_ids = []
|
invoice_line_ids = []
|
||||||
for x in template.recurring_invoice_line_ids:
|
for x in template.recurring_invoice_line_ids:
|
||||||
invoice_line_ids.append((0, 0, {
|
invoice_line_ids.append((0, 0, {
|
||||||
|
@ -654,12 +651,10 @@ class account_analytic_account(osv.osv):
|
||||||
'nodestroy': True,
|
'nodestroy': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _prepare_invoice(self, cr, uid, contract, context=None):
|
def _prepare_invoice_data(self, cr, uid, contract, context=None):
|
||||||
context = context or {}
|
context = context or {}
|
||||||
|
|
||||||
inv_obj = self.pool.get('account.invoice')
|
|
||||||
journal_obj = self.pool.get('account.journal')
|
journal_obj = self.pool.get('account.journal')
|
||||||
fpos_obj = self.pool.get('account.fiscal.position')
|
|
||||||
|
|
||||||
if not contract.partner_id:
|
if not contract.partner_id:
|
||||||
raise osv.except_osv(_('No Customer Defined!'),_("You must first select a Customer for Contract %s!") % contract.name )
|
raise osv.except_osv(_('No Customer Defined!'),_("You must first select a Customer for Contract %s!") % contract.name )
|
||||||
|
@ -680,33 +675,36 @@ class account_analytic_account(osv.osv):
|
||||||
elif contract.company_id:
|
elif contract.company_id:
|
||||||
currency_id = contract.company_id.currency_id.id
|
currency_id = contract.company_id.currency_id.id
|
||||||
|
|
||||||
inv_data = {
|
invoice = {
|
||||||
'reference': contract.code or False,
|
|
||||||
'account_id': contract.partner_id.property_account_receivable.id,
|
'account_id': contract.partner_id.property_account_receivable.id,
|
||||||
'type': 'out_invoice',
|
'type': 'out_invoice',
|
||||||
'partner_id': contract.partner_id.id,
|
'partner_id': contract.partner_id.id,
|
||||||
'currency_id': currency_id,
|
'currency_id': currency_id,
|
||||||
'journal_id': len(journal_ids) and journal_ids[0] or False,
|
'journal_id': len(journal_ids) and journal_ids[0] or False,
|
||||||
'date_invoice': contract.recurring_next_date,
|
'date_invoice': contract.recurring_next_date,
|
||||||
'origin': contract.name,
|
'origin': contract.code,
|
||||||
'fiscal_position': fpos and fpos.id,
|
'fiscal_position': fpos and fpos.id,
|
||||||
'payment_term': partner_payment_term,
|
'payment_term': partner_payment_term,
|
||||||
'company_id': contract.company_id.id or False,
|
'company_id': contract.company_id.id or False,
|
||||||
}
|
}
|
||||||
invoice_id = inv_obj.create(cr, uid, inv_data, context=context)
|
return invoice
|
||||||
|
|
||||||
|
def _prepare_invoice_lines(self, cr, uid, contract, fiscal_position_id, context=None):
|
||||||
|
fpos_obj = self.pool.get('account.fiscal.position')
|
||||||
|
fiscal_position = fpos_obj.browse(cr, uid, fiscal_position_id, context=context)
|
||||||
|
invoice_lines = []
|
||||||
for line in contract.recurring_invoice_line_ids:
|
for line in contract.recurring_invoice_line_ids:
|
||||||
|
|
||||||
res = line.product_id
|
res = line.product_id
|
||||||
account_id = res.property_account_income.id
|
account_id = res.property_account_income.id
|
||||||
if not account_id:
|
if not account_id:
|
||||||
account_id = res.categ_id.property_account_income_categ.id
|
account_id = res.categ_id.property_account_income_categ.id
|
||||||
account_id = fpos_obj.map_account(cr, uid, fpos, account_id)
|
account_id = fpos_obj.map_account(cr, uid, fiscal_position, account_id)
|
||||||
|
|
||||||
taxes = res.taxes_id or False
|
taxes = res.taxes_id or False
|
||||||
tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes)
|
tax_id = fpos_obj.map_tax(cr, uid, fiscal_position, taxes)
|
||||||
|
|
||||||
invoice_line_vals = {
|
invoice_lines.append((0, 0, {
|
||||||
'name': line.name,
|
'name': line.name,
|
||||||
'account_id': account_id,
|
'account_id': account_id,
|
||||||
'account_analytic_id': contract.id,
|
'account_analytic_id': contract.id,
|
||||||
|
@ -714,13 +712,14 @@ class account_analytic_account(osv.osv):
|
||||||
'quantity': line.quantity,
|
'quantity': line.quantity,
|
||||||
'uos_id': line.uom_id.id or False,
|
'uos_id': line.uom_id.id or False,
|
||||||
'product_id': line.product_id.id or False,
|
'product_id': line.product_id.id or False,
|
||||||
'invoice_id' : invoice_id,
|
|
||||||
'invoice_line_tax_id': [(6, 0, tax_id)],
|
'invoice_line_tax_id': [(6, 0, tax_id)],
|
||||||
}
|
}))
|
||||||
self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context)
|
return invoice_lines
|
||||||
|
|
||||||
inv_obj.button_compute(cr, uid, [invoice_id], context=context)
|
def _prepare_invoice(self, cr, uid, contract, context=None):
|
||||||
return invoice_id
|
invoice = self._prepare_invoice_data(cr, uid, contract, context=context)
|
||||||
|
invoice['invoice_line'] = self._prepare_invoice_lines(cr, uid, contract, invoice['fiscal_position'], context=context)
|
||||||
|
return invoice
|
||||||
|
|
||||||
def recurring_create_invoice(self, cr, uid, ids, context=None):
|
def recurring_create_invoice(self, cr, uid, ids, context=None):
|
||||||
return self._recurring_create_invoice(cr, uid, ids, context=context)
|
return self._recurring_create_invoice(cr, uid, ids, context=context)
|
||||||
|
@ -730,6 +729,7 @@ class account_analytic_account(osv.osv):
|
||||||
|
|
||||||
def _recurring_create_invoice(self, cr, uid, ids, automatic=False, context=None):
|
def _recurring_create_invoice(self, cr, uid, ids, automatic=False, context=None):
|
||||||
context = context or {}
|
context = context or {}
|
||||||
|
invoice_ids = []
|
||||||
current_date = time.strftime('%Y-%m-%d')
|
current_date = time.strftime('%Y-%m-%d')
|
||||||
if ids:
|
if ids:
|
||||||
contract_ids = ids
|
contract_ids = ids
|
||||||
|
@ -737,8 +737,8 @@ class account_analytic_account(osv.osv):
|
||||||
contract_ids = self.search(cr, uid, [('recurring_next_date','<=', current_date), ('state','=', 'open'), ('recurring_invoices','=', True), ('type', '=', 'contract')])
|
contract_ids = self.search(cr, uid, [('recurring_next_date','<=', current_date), ('state','=', 'open'), ('recurring_invoices','=', True), ('type', '=', 'contract')])
|
||||||
for contract in self.browse(cr, uid, contract_ids, context=context):
|
for contract in self.browse(cr, uid, contract_ids, context=context):
|
||||||
try:
|
try:
|
||||||
invoice_id = self._prepare_invoice(cr, uid, contract, context=context)
|
invoice_values = self._prepare_invoice(cr, uid, contract, context=context)
|
||||||
|
invoice_ids.append(self.pool['account.invoice'].create(cr, uid, invoice_values, context=context))
|
||||||
next_date = datetime.datetime.strptime(contract.recurring_next_date or current_date, "%Y-%m-%d")
|
next_date = datetime.datetime.strptime(contract.recurring_next_date or current_date, "%Y-%m-%d")
|
||||||
interval = contract.recurring_interval
|
interval = contract.recurring_interval
|
||||||
if contract.recurring_rule_type == 'daily':
|
if contract.recurring_rule_type == 'daily':
|
||||||
|
@ -756,7 +756,7 @@ class account_analytic_account(osv.osv):
|
||||||
_logger.error(traceback.format_exc())
|
_logger.error(traceback.format_exc())
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
return True
|
return invoice_ids
|
||||||
|
|
||||||
class account_analytic_account_summary_user(osv.osv):
|
class account_analytic_account_summary_user(osv.osv):
|
||||||
_name = "account_analytic_analysis.summary.user"
|
_name = "account_analytic_analysis.summary.user"
|
||||||
|
|
|
@ -38,9 +38,6 @@
|
||||||
<field name="partner_id" position="attributes">
|
<field name="partner_id" position="attributes">
|
||||||
<attribute name="attrs">{'required': [('type','=','contract'),'|','|',('fix_price_invoices','=',True), ('invoice_on_timesheets', '=', True), ('recurring_invoices', '=', True)]}</attribute>
|
<attribute name="attrs">{'required': [('type','=','contract'),'|','|',('fix_price_invoices','=',True), ('invoice_on_timesheets', '=', True), ('recurring_invoices', '=', True)]}</attribute>
|
||||||
</field>
|
</field>
|
||||||
<field name="template_id" position="attributes">
|
|
||||||
<attribute name="on_change">on_change_template(template_id, date_start, fix_price_invoices, invoice_on_timesheets, recurring_invoices)</attribute>
|
|
||||||
</field>
|
|
||||||
<xpath expr='//group[@name="invoice_on_timesheets"]' position="replace">
|
<xpath expr='//group[@name="invoice_on_timesheets"]' position="replace">
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr='//separator[@name="description"]' position='before'>
|
<xpath expr='//separator[@name="description"]' position='before'>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import time
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
|
|
||||||
class account_crossovered_analytic(osv.osv_memory):
|
class account_crossovered_analytic(osv.osv_memory):
|
||||||
_name = "account.crossovered.analytic"
|
_name = "account.crossovered.analytic"
|
||||||
_description = "Print Crossovered Analytic"
|
_description = "Print Crossovered Analytic"
|
||||||
|
@ -65,6 +66,6 @@ class account_crossovered_analytic(osv.osv_memory):
|
||||||
'model': 'account.analytic.account',
|
'model': 'account.analytic.account',
|
||||||
'form': data
|
'form': data
|
||||||
}
|
}
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account_analytic_plans.report_crossoveredanalyticplans', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account_analytic_plans.report_crossoveredanalyticplans', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -46,6 +46,6 @@ class account_budget_analytic(osv.osv_memory):
|
||||||
'form': data
|
'form': data
|
||||||
}
|
}
|
||||||
datas['form']['ids'] = datas['ids']
|
datas['form']['ids'] = datas['ids']
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account_budget.report_analyticaccountbudget', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account_budget.report_analyticaccountbudget', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -47,6 +47,6 @@ class account_budget_crossvered_report(osv.osv_memory):
|
||||||
}
|
}
|
||||||
datas['form']['ids'] = datas['ids']
|
datas['form']['ids'] = datas['ids']
|
||||||
datas['form']['report'] = 'analytic-full'
|
datas['form']['report'] = 'analytic-full'
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account_budget.report_crossoveredbudget', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account_budget.report_crossoveredbudget', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -49,6 +49,6 @@ class account_budget_crossvered_summary_report(osv.osv_memory):
|
||||||
}
|
}
|
||||||
datas['form']['ids'] = datas['ids']
|
datas['form']['ids'] = datas['ids']
|
||||||
datas['form']['report'] = 'analytic-one'
|
datas['form']['report'] = 'analytic-one'
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account_budget.report_crossoveredbudget', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account_budget.report_crossoveredbudget', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -47,6 +47,6 @@ class account_budget_report(osv.osv_memory):
|
||||||
}
|
}
|
||||||
datas['form']['ids'] = datas['ids']
|
datas['form']['ids'] = datas['ids']
|
||||||
datas['form']['report'] = 'analytic-full'
|
datas['form']['report'] = 'analytic-full'
|
||||||
return self.pool['report'].get_action(cr, uid, ids, 'account_budget.report_budget', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account_budget.report_budget', data=datas, context=context)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -74,26 +74,17 @@ class account_voucher(osv.osv):
|
||||||
|
|
||||||
def print_check(self, cr, uid, ids, context=None):
|
def print_check(self, cr, uid, ids, context=None):
|
||||||
if not ids:
|
if not ids:
|
||||||
return {}
|
raise osv.except_osv(_('Printing error'), _('No check selected '))
|
||||||
|
|
||||||
check_layout_report = {
|
data = {
|
||||||
'top' : 'account.print.check.top',
|
'id': ids and ids[0],
|
||||||
'middle' : 'account.print.check.middle',
|
'ids': ids,
|
||||||
'bottom' : 'account.print.check.bottom',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_layout = self.browse(cr, uid, ids[0], context=context).company_id.check_layout
|
return self.pool['report'].get_action(
|
||||||
return {
|
cr, uid, [], 'account_check_writing.report_check', data=data, context=context
|
||||||
'type': 'ir.actions.report.xml',
|
)
|
||||||
'report_name':check_layout_report[check_layout],
|
|
||||||
'datas': {
|
|
||||||
'model':'account.voucher',
|
|
||||||
'id': ids and ids[0] or False,
|
|
||||||
'ids': ids and ids or [],
|
|
||||||
'report_type': 'pdf'
|
|
||||||
},
|
|
||||||
'nodestroy': True
|
|
||||||
}
|
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
if vals.get('amount') and vals.get('journal_id') and 'amount_in_word' not in vals:
|
if vals.get('amount') and vals.get('journal_id') and 'amount_in_word' not in vals:
|
||||||
vals['amount_in_word'] = self._amount_to_text(cr, uid, vals['amount'], vals.get('currency_id') or \
|
vals['amount_in_word'] = self._amount_to_text(cr, uid, vals['amount'], vals.get('currency_id') or \
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
|
||||||
|
|
||||||
class account_check_write(osv.osv_memory):
|
class account_check_write(osv.osv_memory):
|
||||||
_name = 'account.check.write'
|
_name = 'account.check.write'
|
||||||
_description = 'Prin Check in Batch'
|
_description = 'Prin Check in Batch'
|
||||||
|
@ -64,23 +64,11 @@ class account_check_write(osv.osv_memory):
|
||||||
ir_sequence_obj.write(cr, uid, sequence_id, {'number_next': new_value})
|
ir_sequence_obj.write(cr, uid, sequence_id, {'number_next': new_value})
|
||||||
|
|
||||||
#print the checks
|
#print the checks
|
||||||
check_layout_report = {
|
data = {
|
||||||
'top' : 'account.print.check.top',
|
'id': voucher_ids and voucher_ids[0],
|
||||||
'middle' : 'account.print.check.middle',
|
'ids': voucher_ids,
|
||||||
'bottom' : 'account.print.check.bottom',
|
|
||||||
}
|
}
|
||||||
check_layout = voucher_obj.browse(cr, uid, voucher_ids[0], context=context).company_id.check_layout
|
|
||||||
if not check_layout:
|
|
||||||
check_layout = 'top'
|
|
||||||
return {
|
|
||||||
'type': 'ir.actions.report.xml',
|
|
||||||
'report_name':check_layout_report[check_layout],
|
|
||||||
'datas': {
|
|
||||||
'model':'account.voucher',
|
|
||||||
'ids': voucher_ids,
|
|
||||||
'report_type': 'pdf'
|
|
||||||
},
|
|
||||||
'nodestroy': True
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
return self.pool['report'].get_action(
|
||||||
|
cr, uid, [], 'account_check_writing.report_check', data=data, context=context
|
||||||
|
)
|
||||||
|
|
|
@ -188,7 +188,7 @@ class res_partner(osv.osv):
|
||||||
'model': 'account_followup.followup',
|
'model': 'account_followup.followup',
|
||||||
'form': data
|
'form': data
|
||||||
}
|
}
|
||||||
return self.pool['report'].get_action(cr, uid, wizard_partner_ids, 'account_followup.report_followup', data=datas, context=context)
|
return self.pool['report'].get_action(cr, uid, [], 'account_followup.report_followup', data=datas, context=context)
|
||||||
|
|
||||||
def do_partner_mail(self, cr, uid, partner_ids, context=None):
|
def do_partner_mail(self, cr, uid, partner_ids, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<field name="name" />
|
<field name="name" />
|
||||||
<field name="client_id" />
|
<field name="client_id" />
|
||||||
<field name="enabled" />
|
<field name="enabled" />
|
||||||
|
<field name="body" />
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="auth_endpoint" />
|
<field name="auth_endpoint" />
|
||||||
|
|
|
@ -977,7 +977,7 @@ class crm_lead(format_address, osv.osv):
|
||||||
if obj.type == 'opportunity':
|
if obj.type == 'opportunity':
|
||||||
model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
|
model, view_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||||
else:
|
else:
|
||||||
view_id = super(crm_lead, self).get_formview_id(cr, uid, id, model=model, context=context)
|
view_id = super(crm_lead, self).get_formview_id(cr, uid, id, model='crm.lead', context=context)
|
||||||
return view_id
|
return view_id
|
||||||
|
|
||||||
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
|
def message_get_suggested_recipients(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<record model="crm.case.stage" id="stage_lead2">
|
<record model="crm.case.stage" id="stage_lead2">
|
||||||
<field name="name">Dead</field>
|
<field name="name">Dead</field>
|
||||||
<field name="case_default">1</field>
|
<field name="case_default">1</field>
|
||||||
|
<field name="fold">1</field>
|
||||||
<field name="probability">0</field>
|
<field name="probability">0</field>
|
||||||
<field name="on_change">1</field>
|
<field name="on_change">1</field>
|
||||||
<field name="sequence">30</field>
|
<field name="sequence">30</field>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<graph string="Leads Analysis" type="pivot" stacked="True">
|
<graph string="Leads Analysis" type="pivot" stacked="True">
|
||||||
<field name="user_id" type="row"/>
|
<field name="user_id" type="row"/>
|
||||||
<field name="create_date" interval="week" type="col"/>
|
<field name="create_date" interval="year" type="col"/>
|
||||||
</graph>
|
</graph>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
@ -32,7 +32,6 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<graph string="Leads Analysis" type="pivot" stacked="True">
|
<graph string="Leads Analysis" type="pivot" stacked="True">
|
||||||
<field name="date_deadline" type="row"/>
|
<field name="date_deadline" type="row"/>
|
||||||
<field name="user_id" type="col"/>
|
|
||||||
<field name="stage_id" type="col"/>
|
<field name="stage_id" type="col"/>
|
||||||
<field name="planned_revenue" type="measure"/>
|
<field name="planned_revenue" type="measure"/>
|
||||||
</graph>
|
</graph>
|
||||||
|
@ -46,6 +45,9 @@
|
||||||
<field name="model">crm.lead.report</field>
|
<field name="model">crm.lead.report</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Leads Analysis">
|
<search string="Leads Analysis">
|
||||||
|
<filter name="lead" string="Lead" domain="[('type','=', 'lead')]" help="Show only lead"/>
|
||||||
|
<filter name="opportunity" string="Opportunity" domain="[('type','=','opportunity')]" help="Show only opportunity"/>
|
||||||
|
<separator/>
|
||||||
<filter string="New" name="new"
|
<filter string="New" name="new"
|
||||||
domain="[('probability', '=', 0), ('stage_id.sequence', '=', 1)]"/>
|
domain="[('probability', '=', 0), ('stage_id.sequence', '=', 1)]"/>
|
||||||
<filter string="Won" name="won"
|
<filter string="Won" name="won"
|
||||||
|
@ -78,43 +80,37 @@
|
||||||
<field name="date_closed"/>
|
<field name="date_closed"/>
|
||||||
</group>
|
</group>
|
||||||
<group expand="1" string="Group By...">
|
<group expand="1" string="Group By...">
|
||||||
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
|
<filter string="Salesperson" domain="[]" context="{'group_by':'user_id'}" />
|
||||||
<filter string="Sales Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}" />
|
<filter string="Sales Team" domain="[]" context="{'group_by':'section_id'}" />
|
||||||
<filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />
|
<filter string="Partner" context="{'group_by':'partner_id'}" />
|
||||||
<filter string="Country" icon="terp-go-home" context="{'group_by':'country_id'}" />
|
<filter string="Country" context="{'group_by':'country_id'}" />
|
||||||
<filter string="Company" icon="terp-go-home" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
<filter string="Company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||||
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
<filter string="Type" domain="[]" context="{'group_by':'type'}"/>
|
||||||
<filter string="Priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}" />
|
<filter string="Stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||||
<filter string="Campaign" icon="terp-gtk-jump-to-rtl"
|
<filter string="Priority" domain="[]" context="{'group_by':'priority'}" />
|
||||||
domain="[]" context="{'group_by':'type_id'}" />
|
<filter string="Campaign" domain="[]" context="{'group_by':'type_id'}" />
|
||||||
<filter string="Channel" icon="terp-call-start"
|
<filter string="Channel" domain="[]" context="{'group_by':'channel_id'}" />
|
||||||
domain="[]" context="{'group_by':'channel_id'}" />
|
|
||||||
<separator orientation="vertical" />
|
<separator orientation="vertical" />
|
||||||
<filter string="Creation date (day)" icon="terp-go-year"
|
<filter string="Creation date (day)" domain="[]" context="{'group_by':'create_date:day'}"/>
|
||||||
domain="[]" context="{'group_by':'create_date:day'}"/>
|
<filter string="Creation date (week)" domain="[]" context="{'group_by':'create_date:week'}"/>
|
||||||
<filter string="Creation date (week)" icon="terp-go-year"
|
<filter string="Creation date (month)" domain="[]" context="{'group_by':'create_date:month'}" name="month"/>
|
||||||
domain="[]" context="{'group_by':'create_date:week'}"/>
|
<filter string="Creation date (year)" domain="[]" context="{'group_by':'create_date:year'}"/>
|
||||||
<filter string="Creation date (month)" icon="terp-go-year"
|
|
||||||
domain="[]" context="{'group_by':'create_date:month'}" name="month"/>
|
|
||||||
<filter string="Creation date (year)" icon="terp-go-year"
|
|
||||||
domain="[]" context="{'group_by':'create_date:year'}"/>
|
|
||||||
<separator orientation="vertical" />
|
<separator orientation="vertical" />
|
||||||
<filter string="Exp. Closing" icon="terp-go-month"
|
<filter string="Exp. Closing" domain="[]" context="{'group_by':'date_deadline'}"/>
|
||||||
domain="[]" context="{'group_by':'date_deadline'}"/>
|
|
||||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}" />
|
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}" />
|
||||||
</group>
|
</group>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Leads by user and section Action -->
|
<!-- Leads by user and section Action -->
|
||||||
|
|
||||||
<record id="action_report_crm_lead" model="ir.actions.act_window">
|
<record id="action_report_crm_lead" model="ir.actions.act_window">
|
||||||
<field name="name">Leads Analysis</field>
|
<field name="name">Leads Analysis</field>
|
||||||
<field name="res_model">crm.lead.report</field>
|
<field name="res_model">crm.lead.report</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">graph</field>
|
<field name="view_mode">graph</field>
|
||||||
<field name="domain">[('type','=', 'lead')]</field>
|
<field name="context">{'search_default_lead': 1}</field>
|
||||||
|
<field name="domain">[]</field>
|
||||||
<field name="help">Leads Analysis allows you to check different CRM related information like the treatment delays or number of leads per state. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>
|
<field name="help">Leads Analysis allows you to check different CRM related information like the treatment delays or number of leads per state. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="ir.actions.act_window.view" id="action_report_crm_lead_graph">
|
<record model="ir.actions.act_window.view" id="action_report_crm_lead_graph">
|
||||||
|
@ -123,27 +119,25 @@
|
||||||
<field name="view_id" ref="view_report_crm_lead_graph"/>
|
<field name="view_id" ref="view_report_crm_lead_graph"/>
|
||||||
<field name="act_window_id" ref="action_report_crm_lead"/>
|
<field name="act_window_id" ref="action_report_crm_lead"/>
|
||||||
</record>
|
</record>
|
||||||
|
<menuitem name="Leads Analysis" id="menu_report_crm_leads_tree"
|
||||||
|
groups="base.group_sale_manager"
|
||||||
|
parent="base.next_id_64" action="action_report_crm_lead" sequence="1"/>
|
||||||
|
|
||||||
<record id="action_report_crm_opportunity" model="ir.actions.act_window">
|
<record id="action_report_crm_opportunity" model="ir.actions.act_window">
|
||||||
<field name="name">Opportunities Analysis</field>
|
<field name="name">Opportunities Analysis</field>
|
||||||
<field name="res_model">crm.lead.report</field>
|
<field name="res_model">crm.lead.report</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">graph</field>
|
<field name="view_mode">graph</field>
|
||||||
<field name="domain">[('type','=', 'opportunity')]</field>
|
<field name="context">{'search_default_opportunity': 1}</field>
|
||||||
|
<field name="domain">[]</field>
|
||||||
<field name="help">Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline.</field>
|
<field name="help">Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline.</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.actions.act_window.view" id="action_report_crm_opportunity_graph">
|
<record model="ir.actions.act_window.view" id="action_report_crm_opportunity_graph">
|
||||||
<field name="sequence" eval="2"/>
|
<field name="sequence" eval="2"/>
|
||||||
<field name="view_mode">graph</field>
|
<field name="view_mode">graph</field>
|
||||||
<field name="view_id" ref="view_report_crm_opportunity_graph"/>
|
<field name="view_id" ref="view_report_crm_opportunity_graph"/>
|
||||||
<field name="act_window_id" ref="action_report_crm_opportunity"/>
|
<field name="act_window_id" ref="action_report_crm_opportunity"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem name="Leads Analysis" id="menu_report_crm_leads_tree"
|
|
||||||
groups="base.group_sale_manager"
|
|
||||||
parent="base.next_id_64" action="action_report_crm_lead" sequence="1"/>
|
|
||||||
|
|
||||||
<menuitem name="Opportunities Analysis" id="menu_report_crm_opportunities_tree"
|
<menuitem name="Opportunities Analysis" id="menu_report_crm_opportunities_tree"
|
||||||
parent="base.next_id_64" action="action_report_crm_opportunity" sequence="5"/>
|
parent="base.next_id_64" action="action_report_crm_opportunity" sequence="5"/>
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ Find duplicates, merge leads and assign them to the right salesperson in one ope
|
||||||
<p class="oe_mt32">
|
<p class="oe_mt32">
|
||||||
Get your opportunities organized to stay focused on the best deals. Manage all your customer interactions from the opportunity like emails, phone calls, internal notes, meetings and quotations.
|
Get your opportunities organized to stay focused on the best deals. Manage all your customer interactions from the opportunity like emails, phone calls, internal notes, meetings and quotations.
|
||||||
</p><p>
|
</p><p>
|
||||||
Follow opportunities that interrests you to get notified upon specific events: deal won or lost, stage changed, new customer demand, etc.
|
Follow opportunities that interest you to get notified upon specific events: deal won or lost, stage changed, new customer demand, etc.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -194,9 +194,9 @@ class delivery_grid(osv.osv):
|
||||||
for line in order.order_line:
|
for line in order.order_line:
|
||||||
if not line.product_id or line.is_delivery:
|
if not line.product_id or line.is_delivery:
|
||||||
continue
|
continue
|
||||||
total += line.price_subtotal or 0.0
|
|
||||||
weight += (line.product_id.weight or 0.0) * line.product_uom_qty
|
weight += (line.product_id.weight or 0.0) * line.product_uom_qty
|
||||||
volume += (line.product_id.volume or 0.0) * line.product_uom_qty
|
volume += (line.product_id.volume or 0.0) * line.product_uom_qty
|
||||||
|
total = order.amount_total or 0.0
|
||||||
|
|
||||||
|
|
||||||
return self.get_price_from_picking(cr, uid, id, total,weight, volume, context=context)
|
return self.get_price_from_picking(cr, uid, id, total,weight, volume, context=context)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<field name="subject">Your registration at ${object.event_id.name}</field>
|
<field name="subject">Your registration at ${object.event_id.name}</field>
|
||||||
<field name="body_html"><![CDATA[
|
<field name="body_html"><![CDATA[
|
||||||
<p>Hello ${object.name},</p>
|
<p>Hello ${object.name},</p>
|
||||||
<p>The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin} to ${object.event_id.date_end}.
|
<p>The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')} to ${object.event_id.date_end_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')}.
|
||||||
For any further information please contact our event department.</p>
|
For any further information please contact our event department.</p>
|
||||||
<p>Thank you for your participation!</p>
|
<p>Thank you for your participation!</p>
|
||||||
<p>Best regards</p>]]></field>
|
<p>Best regards</p>]]></field>
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
import pytz
|
||||||
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
@ -131,7 +132,7 @@ class event_event(osv.osv):
|
||||||
@return: Dictionary of function field values.
|
@return: Dictionary of function field values.
|
||||||
"""
|
"""
|
||||||
event_ids=set()
|
event_ids=set()
|
||||||
for registration in self.browse(cr, uid, ids, context=context):
|
for registration in self.pool['event.registration'].browse(cr, uid, ids, context=context):
|
||||||
event_ids.add(registration.event_id.id)
|
event_ids.add(registration.event_id.id)
|
||||||
return list(event_ids)
|
return list(event_ids)
|
||||||
|
|
||||||
|
@ -150,6 +151,22 @@ class event_event(osv.osv):
|
||||||
continue
|
continue
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def _compute_date_tz(self, cr, uid, ids, fld, arg, context=None):
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
res = {}
|
||||||
|
for event in self.browse(cr, uid, ids, context=context):
|
||||||
|
ctx = dict(context, tz=(event.date_tz or 'UTC'))
|
||||||
|
if fld == 'date_begin_located':
|
||||||
|
date_to_convert = event.date_begin
|
||||||
|
elif fld == 'date_end_located':
|
||||||
|
date_to_convert = event.date_end
|
||||||
|
res[event.id] = fields.datetime.context_timestamp(cr, uid, datetime.strptime(date_to_convert, DEFAULT_SERVER_DATETIME_FORMAT), context=ctx)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _tz_get(self, cr, uid, context=None):
|
||||||
|
return [(x, x) for x in pytz.all_timezones]
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Event Name', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}),
|
'name': fields.char('Event 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)]}),
|
'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}),
|
||||||
|
@ -169,8 +186,11 @@ class event_event(osv.osv):
|
||||||
store={'event.registration': (_get_events_from_registrations, ['state'], 10),
|
store={'event.registration': (_get_events_from_registrations, ['state'], 10),
|
||||||
'event.event': (lambda self, cr, uid, ids, c = {}: ids, ['seats_max', 'registration_ids'], 20)}),
|
'event.event': (lambda self, cr, uid, ids, c = {}: ids, ['seats_max', 'registration_ids'], 20)}),
|
||||||
'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
|
'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
|
||||||
|
'date_tz': fields.selection(_tz_get, string='Timezone'),
|
||||||
'date_begin': fields.datetime('Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
'date_begin': fields.datetime('Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||||
'date_end': fields.datetime('End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
'date_end': fields.datetime('End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
|
||||||
|
'date_begin_located': fields.function(_compute_date_tz, string='Start Date Located', type="datetime"),
|
||||||
|
'date_end_located': fields.function(_compute_date_tz, string='End Date Located', type="datetime"),
|
||||||
'state': fields.selection([
|
'state': fields.selection([
|
||||||
('draft', 'Unconfirmed'),
|
('draft', 'Unconfirmed'),
|
||||||
('cancel', 'Cancelled'),
|
('cancel', 'Cancelled'),
|
||||||
|
@ -197,7 +217,8 @@ class event_event(osv.osv):
|
||||||
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
|
'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,
|
'user_id': lambda obj, cr, uid, context: uid,
|
||||||
'organizer_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id,
|
'organizer_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id,
|
||||||
'address_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id
|
'address_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, context=c).company_id.partner_id.id,
|
||||||
|
'date_tz': lambda self, cr, uid, ctx: ctx.get('tz', "UTC"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _check_seats_limit(self, cr, uid, ids, context=None):
|
def _check_seats_limit(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
<field name="type" on_change="onchange_event_type(type,context)" />
|
<field name="type" on_change="onchange_event_type(type,context)" />
|
||||||
<field name="date_begin" on_change="onchange_start_date(date_begin,date_end)"/>
|
<field name="date_begin" on_change="onchange_start_date(date_begin,date_end)"/>
|
||||||
<field name="date_end"/>
|
<field name="date_end"/>
|
||||||
|
<field name="date_tz" />
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
|
|
|
@ -139,10 +139,16 @@ class event_event(osv.osv):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _get_ticket_events(self, cr, uid, ids, context=None):
|
def _get_ticket_events(self, cr, uid, ids, context=None):
|
||||||
# `self` is the event.event.ticket model here!
|
# `self` is the event.event.ticket model when called by ORM!
|
||||||
return list(set(ticket.event_id.id
|
return list(set(ticket.event_id.id
|
||||||
for ticket in self.browse(cr, uid, ids, context)))
|
for ticket in self.browse(cr, uid, ids, context)))
|
||||||
|
|
||||||
|
# proxy method, can't import parent method directly as unbound_method: it would receive
|
||||||
|
# an invalid `self` <event_registration> when called by ORM
|
||||||
|
def _events_from_registrations(self, cr, uid, ids, context=None):
|
||||||
|
# `self` is the event.registration model when called by ORM
|
||||||
|
return self.pool['event.event']._get_events_from_registrations(cr, uid, ids, context=context)
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'event_ticket_ids': fields.one2many('event.event.ticket', "event_id", "Event Ticket"),
|
'event_ticket_ids': fields.one2many('event.event.ticket', "event_id", "Event Ticket"),
|
||||||
'seats_max': fields.function(_get_seats_max,
|
'seats_max': fields.function(_get_seats_max,
|
||||||
|
@ -154,7 +160,7 @@ class event_event(osv.osv):
|
||||||
'seats_available': fields.function(Event._get_seats, oldname='register_avail', string='Available Seats',
|
'seats_available': fields.function(Event._get_seats, oldname='register_avail', string='Available Seats',
|
||||||
type='integer', multi='seats_reserved',
|
type='integer', multi='seats_reserved',
|
||||||
store={
|
store={
|
||||||
'event.registration': (Event._get_events_from_registrations, ['state'], 10),
|
'event.registration': (_events_from_registrations, ['state'], 10),
|
||||||
'event.event': (lambda self, cr, uid, ids, c = {}: ids,
|
'event.event': (lambda self, cr, uid, ids, c = {}: ids,
|
||||||
['seats_max', 'registration_ids'], 20),
|
['seats_max', 'registration_ids'], 20),
|
||||||
'event.event.ticket': (_get_ticket_events, ['seats_max'], 10),
|
'event.event.ticket': (_get_ticket_events, ['seats_max'], 10),
|
||||||
|
|
|
@ -217,15 +217,7 @@ class gamification_challenge(osv.Model):
|
||||||
vals['user_ids'] = []
|
vals['user_ids'] = []
|
||||||
vals['user_ids'] += [(4, user_id) for user_id in user_ids]
|
vals['user_ids'] += [(4, user_id) for user_id in user_ids]
|
||||||
|
|
||||||
create_res = super(gamification_challenge, self).create(cr, uid, vals, context=context)
|
return super(gamification_challenge, self).create(cr, uid, vals, context=context)
|
||||||
|
|
||||||
# subscribe new users to the challenge
|
|
||||||
if vals.get('user_ids'):
|
|
||||||
# done with browse after super to be sure catch all after orm process
|
|
||||||
challenge = self.browse(cr, uid, create_res, context=context)
|
|
||||||
self.message_subscribe_users(cr, uid, [challenge.id], [user.id for user in challenge.user_ids], context=context)
|
|
||||||
|
|
||||||
return create_res
|
|
||||||
|
|
||||||
def write(self, cr, uid, ids, vals, context=None):
|
def write(self, cr, uid, ids, vals, context=None):
|
||||||
if isinstance(ids, (int,long)):
|
if isinstance(ids, (int,long)):
|
||||||
|
@ -240,6 +232,11 @@ class gamification_challenge(osv.Model):
|
||||||
|
|
||||||
write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context)
|
write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context)
|
||||||
|
|
||||||
|
if vals.get('report_message_frequency', 'never') != 'never':
|
||||||
|
# _recompute_challenge_users do not set users for challenges with no reports, subscribing them now
|
||||||
|
for challenge in self.browse(cr, uid, ids, context=context):
|
||||||
|
self.message_subscribe(cr, uid, [challenge.id], [user.partner_id.id for user in challenge.user_ids], context=context)
|
||||||
|
|
||||||
if vals.get('state') == 'inprogress':
|
if vals.get('state') == 'inprogress':
|
||||||
self._recompute_challenge_users(cr, uid, ids, context=context)
|
self._recompute_challenge_users(cr, uid, ids, context=context)
|
||||||
self._generate_goals_from_challenge(cr, uid, ids, context=context)
|
self._generate_goals_from_challenge(cr, uid, ids, context=context)
|
||||||
|
@ -264,6 +261,9 @@ class gamification_challenge(osv.Model):
|
||||||
- Create the missing goals (eg: modified the challenge to add lines)
|
- Create the missing goals (eg: modified the challenge to add lines)
|
||||||
- Update every running challenge
|
- Update every running challenge
|
||||||
"""
|
"""
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
|
||||||
# start scheduled challenges
|
# start scheduled challenges
|
||||||
planned_challenge_ids = self.search(cr, uid, [
|
planned_challenge_ids = self.search(cr, uid, [
|
||||||
('state', '=', 'draft'),
|
('state', '=', 'draft'),
|
||||||
|
@ -281,6 +281,9 @@ class gamification_challenge(osv.Model):
|
||||||
if not ids:
|
if not ids:
|
||||||
ids = self.search(cr, uid, [('state', '=', 'inprogress')], context=context)
|
ids = self.search(cr, uid, [('state', '=', 'inprogress')], context=context)
|
||||||
|
|
||||||
|
# in cron mode, will do intermediate commits
|
||||||
|
# TODO in trunk: replace by parameter
|
||||||
|
context.update({'commit_gamification': True})
|
||||||
return self._update_all(cr, uid, ids, context=context)
|
return self._update_all(cr, uid, ids, context=context)
|
||||||
|
|
||||||
def _update_all(self, cr, uid, ids, context=None):
|
def _update_all(self, cr, uid, ids, context=None):
|
||||||
|
@ -355,11 +358,6 @@ class gamification_challenge(osv.Model):
|
||||||
if write_op:
|
if write_op:
|
||||||
self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context)
|
self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context)
|
||||||
|
|
||||||
if to_remove_ids:
|
|
||||||
self.message_unsubscribe_users(cr, uid, [challenge.id], to_remove_ids, context=None)
|
|
||||||
if to_add_ids:
|
|
||||||
self.message_subscribe_users(cr, uid, [challenge.id], to_add_ids, context=context)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -393,9 +391,9 @@ class gamification_challenge(osv.Model):
|
||||||
:param list(int) ids: the list of challenge concerned"""
|
:param list(int) ids: the list of challenge concerned"""
|
||||||
|
|
||||||
goal_obj = self.pool.get('gamification.goal')
|
goal_obj = self.pool.get('gamification.goal')
|
||||||
to_update = []
|
|
||||||
for challenge in self.browse(cr, uid, ids, context=context):
|
for challenge in self.browse(cr, uid, ids, context=context):
|
||||||
(start_date, end_date) = start_end_date_for_period(challenge.period)
|
(start_date, end_date) = start_end_date_for_period(challenge.period)
|
||||||
|
to_update = []
|
||||||
|
|
||||||
# if no periodicity, use challenge dates
|
# if no periodicity, use challenge dates
|
||||||
if not start_date and challenge.start_date:
|
if not start_date and challenge.start_date:
|
||||||
|
@ -426,7 +424,15 @@ class gamification_challenge(osv.Model):
|
||||||
|
|
||||||
cr.execute(query, query_params)
|
cr.execute(query, query_params)
|
||||||
user_with_goal_ids = cr.dictfetchall()
|
user_with_goal_ids = cr.dictfetchall()
|
||||||
user_without_goal_ids = list(set([user.id for user in challenge.user_ids]) - set([user['user_id'] for user in user_with_goal_ids]))
|
|
||||||
|
participant_user_ids = [user.id for user in challenge.user_ids]
|
||||||
|
user_without_goal_ids = list(set(participant_user_ids) - set([user['user_id'] for user in user_with_goal_ids]))
|
||||||
|
user_squating_challenge_ids = list(set([user['user_id'] for user in user_with_goal_ids]) - set(participant_user_ids))
|
||||||
|
if user_squating_challenge_ids:
|
||||||
|
# users that used to match the challenge
|
||||||
|
goal_to_remove_ids = goal_obj.search(cr, uid, [('challenge_id', '=', challenge.id), ('user_id', 'in', user_squating_challenge_ids)], context=context)
|
||||||
|
goal_obj.unlink(cr, uid, goal_to_remove_ids, context=context)
|
||||||
|
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
'definition_id': line.definition_id.id,
|
'definition_id': line.definition_id.id,
|
||||||
|
@ -614,9 +620,10 @@ class gamification_challenge(osv.Model):
|
||||||
ctx.update({'challenge_lines': lines_boards})
|
ctx.update({'challenge_lines': lines_boards})
|
||||||
body_html = temp_obj.render_template(cr, uid, challenge.report_template_id.body_html, 'gamification.challenge', challenge.id, context=ctx)
|
body_html = temp_obj.render_template(cr, uid, challenge.report_template_id.body_html, 'gamification.challenge', challenge.id, context=ctx)
|
||||||
|
|
||||||
# send to every follower of the challenge
|
# send to every follower and participant of the challenge
|
||||||
self.message_post(cr, uid, challenge.id,
|
self.message_post(cr, uid, challenge.id,
|
||||||
body=body_html,
|
body=body_html,
|
||||||
|
partner_ids=[user.partner_id.id for user in challenge.user_ids],
|
||||||
context=context,
|
context=context,
|
||||||
subtype='mail.mt_comment')
|
subtype='mail.mt_comment')
|
||||||
if challenge.report_message_group_id:
|
if challenge.report_message_group_id:
|
||||||
|
@ -698,34 +705,35 @@ class gamification_challenge(osv.Model):
|
||||||
rewarded_users = []
|
rewarded_users = []
|
||||||
challenge_ended = end_date == yesterday.strftime(DF) or force
|
challenge_ended = end_date == yesterday.strftime(DF) or force
|
||||||
if challenge.reward_id and challenge_ended or challenge.reward_realtime:
|
if challenge.reward_id and challenge_ended or challenge.reward_realtime:
|
||||||
for user in challenge.user_ids:
|
# not using start_date as intemportal goals have a start date but no end_date
|
||||||
reached_goal_ids = self.pool.get('gamification.goal').search(cr, uid, [
|
reached_goals = self.pool.get('gamification.goal').read_group(cr, uid, [
|
||||||
('challenge_id', '=', challenge.id),
|
('challenge_id', '=', challenge.id),
|
||||||
('user_id', '=', user.id),
|
('end_date', '=', end_date),
|
||||||
('start_date', '=', start_date),
|
('state', '=', 'reached')
|
||||||
('end_date', '=', end_date),
|
], fields=['user_id'], groupby=['user_id'], context=context)
|
||||||
('state', '=', 'reached')
|
for reach_goals_user in reached_goals:
|
||||||
], context=context)
|
if reach_goals_user['user_id_count'] == len(challenge.line_ids):
|
||||||
if len(reached_goal_ids) == len(challenge.line_ids):
|
|
||||||
# the user has succeeded every assigned goal
|
# the user has succeeded every assigned goal
|
||||||
|
user_id = reach_goals_user['user_id'][0]
|
||||||
if challenge.reward_realtime:
|
if challenge.reward_realtime:
|
||||||
badges = self.pool['gamification.badge.user'].search(cr, uid, [
|
badges = self.pool['gamification.badge.user'].search(cr, uid, [
|
||||||
('challenge_id', '=', challenge.id),
|
('challenge_id', '=', challenge.id),
|
||||||
('badge_id', '=', challenge.reward_id.id),
|
('badge_id', '=', challenge.reward_id.id),
|
||||||
('user_id', '=', user.id),
|
('user_id', '=', user_id),
|
||||||
], count=True, context=context)
|
], count=True, context=context)
|
||||||
if badges > 0:
|
if badges > 0:
|
||||||
# has already recieved the badge for this challenge
|
# has already recieved the badge for this challenge
|
||||||
continue
|
continue
|
||||||
self.reward_user(cr, uid, user.id, challenge.reward_id.id, challenge.id, context=context)
|
self.reward_user(cr, uid, user_id, challenge.reward_id.id, challenge.id, context=context)
|
||||||
rewarded_users.append(user)
|
rewarded_users.append(user_id)
|
||||||
|
|
||||||
if challenge_ended:
|
if challenge_ended:
|
||||||
# open chatter message
|
# open chatter message
|
||||||
message_body = _("The challenge %s is finished." % challenge.name)
|
message_body = _("The challenge %s is finished." % challenge.name)
|
||||||
|
|
||||||
if rewarded_users:
|
if rewarded_users:
|
||||||
message_body += _("<br/>Reward (badge %s) for every succeeding user was sent to %s." % (challenge.reward_id.name, ", ".join([user.name for user in rewarded_users])))
|
user_names = self.pool['res.users'].name_get(cr, uid, rewarded_users, context=context)
|
||||||
|
message_body += _("<br/>Reward (badge %s) for every succeeding user was sent to %s." % (challenge.reward_id.name, ", ".join([name for (user_id, name) in user_names])))
|
||||||
else:
|
else:
|
||||||
message_body += _("<br/>Nobody has succeeded to reach every goal, no badge is rewared for this challenge.")
|
message_body += _("<br/>Nobody has succeeded to reach every goal, no badge is rewared for this challenge.")
|
||||||
|
|
||||||
|
@ -746,7 +754,10 @@ class gamification_challenge(osv.Model):
|
||||||
self.reward_user(cr, uid, third_user.id, challenge.reward_second_id.id, challenge.id, context=context)
|
self.reward_user(cr, uid, third_user.id, challenge.reward_second_id.id, challenge.id, context=context)
|
||||||
message_body += "<br/> 3. %s - %s" % (third_user.name, challenge.reward_third_id.name)
|
message_body += "<br/> 3. %s - %s" % (third_user.name, challenge.reward_third_id.name)
|
||||||
|
|
||||||
self.message_post(cr, uid, challenge.id, body=message_body, context=context)
|
self.message_post(cr, uid, challenge.id,
|
||||||
|
partner_ids=[user.partner_id.id for user in challenge.user_ids],
|
||||||
|
body=message_body,
|
||||||
|
context=context)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,6 @@ class gamification_goal(osv.Model):
|
||||||
|
|
||||||
_name = 'gamification.goal'
|
_name = 'gamification.goal'
|
||||||
_description = 'Gamification goal instance'
|
_description = 'Gamification goal instance'
|
||||||
_inherit = 'mail.thread'
|
|
||||||
|
|
||||||
def _get_completion(self, cr, uid, ids, field_name, arg, context=None):
|
def _get_completion(self, cr, uid, ids, field_name, arg, context=None):
|
||||||
"""Return the percentage of completeness of the goal, between 0 and 100"""
|
"""Return the percentage of completeness of the goal, between 0 and 100"""
|
||||||
|
@ -226,8 +225,7 @@ class gamification_goal(osv.Model):
|
||||||
temp_obj = self.pool.get('email.template')
|
temp_obj = self.pool.get('email.template')
|
||||||
template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_goal_reminder', context)
|
template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_goal_reminder', context)
|
||||||
body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.goal', goal.id, context=context)
|
body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.goal', goal.id, context=context)
|
||||||
|
self.pool['mail.thread'].message_post(cr, uid, 0, body=body_html, partner_ids=[goal.user_id.partner_id.id], context=context, subtype='mail.mt_comment')
|
||||||
self.message_post(cr, uid, goal.id, body=body_html, partner_ids=[goal.user_id.partner_id.id], context=context, subtype='mail.mt_comment')
|
|
||||||
return {'to_update': True}
|
return {'to_update': True}
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -241,9 +239,9 @@ class gamification_goal(osv.Model):
|
||||||
the target value being reached, the goal is set as failed."""
|
the target value being reached, the goal is set as failed."""
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
commit = context.get('commit_gamification', False)
|
||||||
|
|
||||||
goals_by_definition = {}
|
goals_by_definition = {}
|
||||||
goals_to_write = {}
|
|
||||||
all_goals = {}
|
all_goals = {}
|
||||||
for goal in self.browse(cr, uid, ids, context=context):
|
for goal in self.browse(cr, uid, ids, context=context):
|
||||||
if goal.state in ('draft', 'canceled'):
|
if goal.state in ('draft', 'canceled'):
|
||||||
|
@ -251,10 +249,10 @@ class gamification_goal(osv.Model):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
goals_by_definition.setdefault(goal.definition_id, []).append(goal)
|
goals_by_definition.setdefault(goal.definition_id, []).append(goal)
|
||||||
goals_to_write[goal.id] = {}
|
|
||||||
all_goals[goal.id] = goal
|
all_goals[goal.id] = goal
|
||||||
|
|
||||||
for definition, goals in goals_by_definition.items():
|
for definition, goals in goals_by_definition.items():
|
||||||
|
goals_to_write = dict((goal.id, {}) for goal in goals)
|
||||||
if definition.computation_mode == 'manually':
|
if definition.computation_mode == 'manually':
|
||||||
for goal in goals:
|
for goal in goals:
|
||||||
goals_to_write[goal.id].update(self._check_remind_delay(cr, uid, goal, context))
|
goals_to_write[goal.id].update(self._check_remind_delay(cr, uid, goal, context))
|
||||||
|
@ -345,22 +343,24 @@ class gamification_goal(osv.Model):
|
||||||
if new_value != goal.current:
|
if new_value != goal.current:
|
||||||
goals_to_write[goal.id]['current'] = new_value
|
goals_to_write[goal.id]['current'] = new_value
|
||||||
|
|
||||||
for goal_id, value in goals_to_write.items():
|
for goal_id, value in goals_to_write.items():
|
||||||
if not value:
|
if not value:
|
||||||
continue
|
continue
|
||||||
goal = all_goals[goal_id]
|
goal = all_goals[goal_id]
|
||||||
|
|
||||||
# check goal target reached
|
# check goal target reached
|
||||||
if (goal.definition_condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
|
if (goal.definition_condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
|
||||||
or (goal.definition_condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
|
or (goal.definition_condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
|
||||||
value['state'] = 'reached'
|
value['state'] = 'reached'
|
||||||
|
|
||||||
# check goal failure
|
# check goal failure
|
||||||
elif goal.end_date and fields.date.today() > goal.end_date:
|
elif goal.end_date and fields.date.today() > goal.end_date:
|
||||||
value['state'] = 'failed'
|
value['state'] = 'failed'
|
||||||
value['closed'] = True
|
value['closed'] = True
|
||||||
if value:
|
if value:
|
||||||
self.write(cr, uid, [goal.id], value, context=context)
|
self.write(cr, uid, [goal.id], value, context=context)
|
||||||
|
if commit:
|
||||||
|
cr.commit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def action_start(self, cr, uid, ids, context=None):
|
def action_start(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -118,7 +118,7 @@ openerp.gamification = function(instance) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.mail.Widget.include({
|
instance.mail.Wall.include({
|
||||||
start: function() {
|
start: function() {
|
||||||
this._super();
|
this._super();
|
||||||
var sidebar = new instance.gamification.Sidebar(this);
|
var sidebar = new instance.gamification.Sidebar(this);
|
||||||
|
|
|
@ -86,10 +86,6 @@
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<div class="oe_chatter">
|
|
||||||
<field name="message_follower_ids" widget="mail_followers"/>
|
|
||||||
<field name="message_ids" widget="mail_thread"/>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -4,18 +4,6 @@
|
||||||
|
|
||||||
<!-- challenges -->
|
<!-- challenges -->
|
||||||
<record model="gamification.challenge" id="challenge_crm_sale">
|
<record model="gamification.challenge" id="challenge_crm_sale">
|
||||||
<field name="user_ids" eval="[(4,ref('base.user_demo'))]" />
|
|
||||||
<field name="state">inprogress</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- goals -->
|
|
||||||
<record model="gamification.goal" id="goal_crm_sale1">
|
|
||||||
<field name="definition_id" eval="ref('definition_crm_tot_invoices')" />
|
|
||||||
<field name="user_id" eval="ref('base.user_demo')" />
|
|
||||||
<field name="line_id" eval="ref('line_crm_sale1')" />
|
|
||||||
<field name="start_date" eval="time.strftime('%Y-%m-01')" />
|
|
||||||
<field name="end_date" eval="(DateTime.today().replace(day=1)+relativedelta(months=1, days=-1)).strftime('%Y-%m-%d')" />
|
|
||||||
<field name="target_goal">2000</field>
|
|
||||||
<field name="state">inprogress</field>
|
<field name="state">inprogress</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
|
@ -248,7 +248,13 @@ class hr_employee(osv.osv):
|
||||||
'image': _get_default_image,
|
'image': _get_default_image,
|
||||||
'color': 0,
|
'color': 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def copy_data(self, cr, uid, ids, default=None, context=None):
|
||||||
|
if default is None:
|
||||||
|
default = {}
|
||||||
|
default.update({'child_ids': False})
|
||||||
|
return super(hr_employee, self).copy_data(cr, uid, ids, default, context=context)
|
||||||
|
|
||||||
def _broadcast_welcome(self, cr, uid, employee_id, context=None):
|
def _broadcast_welcome(self, cr, uid, employee_id, context=None):
|
||||||
""" Broadcast the welcome message to all users in the employee company. """
|
""" Broadcast the welcome message to all users in the employee company. """
|
||||||
employee = self.browse(cr, uid, employee_id, context=context)
|
employee = self.browse(cr, uid, employee_id, context=context)
|
||||||
|
@ -421,18 +427,23 @@ class hr_department(osv.osv):
|
||||||
res.append((record['id'], name))
|
res.append((record['id'], name))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def copy(self, cr, uid, ids, default=None, context=None):
|
def copy_data(self, cr, uid, ids, default=None, context=None):
|
||||||
if default is None:
|
if default is None:
|
||||||
default = {}
|
default = {}
|
||||||
default = default.copy()
|
|
||||||
default['member_ids'] = []
|
default['member_ids'] = []
|
||||||
return super(hr_department, self).copy(cr, uid, ids, default, context=context)
|
return super(hr_department, self).copy_data(cr, uid, ids, default, context=context)
|
||||||
|
|
||||||
|
|
||||||
class res_users(osv.osv):
|
class res_users(osv.osv):
|
||||||
_name = 'res.users'
|
_name = 'res.users'
|
||||||
_inherit = 'res.users'
|
_inherit = 'res.users'
|
||||||
|
|
||||||
|
def copy_data(self, cr, uid, ids, default=None, context=None):
|
||||||
|
if default is None:
|
||||||
|
default = {}
|
||||||
|
default.update({'employee_ids': False})
|
||||||
|
return super(res_users, self).copy_data(cr, uid, ids, default, context=context)
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'employee_ids': fields.one2many('hr.employee', 'user_id', 'Related employees'),
|
'employee_ids': fields.one2many('hr.employee', 'user_id', 'Related employees'),
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,13 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from pytz import timezone
|
||||||
|
import pytz
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
class hr_timesheet_sheet(osv.osv):
|
class hr_timesheet_sheet(osv.osv):
|
||||||
|
@ -396,18 +399,56 @@ class hr_attendance(osv.osv):
|
||||||
attendance_ids.extend([row[0] for row in cr.fetchall()])
|
attendance_ids.extend([row[0] for row in cr.fetchall()])
|
||||||
return attendance_ids
|
return attendance_ids
|
||||||
|
|
||||||
|
def _get_attendance_employee_tz(self, cr, uid, employee_id, date, context=None):
|
||||||
|
""" Simulate timesheet in employee timezone
|
||||||
|
|
||||||
|
Return the attendance date in string format in the employee
|
||||||
|
tz converted from utc timezone as we consider date of employee
|
||||||
|
timesheet is in employee timezone
|
||||||
|
"""
|
||||||
|
employee_obj = self.pool['hr.employee']
|
||||||
|
|
||||||
|
tz = False
|
||||||
|
if employee_id:
|
||||||
|
employee = employee_obj.browse(cr, uid, employee_id, context=context)
|
||||||
|
tz = employee.user_id.partner_id.tz
|
||||||
|
|
||||||
|
if not date:
|
||||||
|
date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
|
||||||
|
att_tz = timezone(tz or 'utc')
|
||||||
|
|
||||||
|
attendance_dt = datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
att_tz_dt = pytz.utc.localize(attendance_dt)
|
||||||
|
att_tz_dt = att_tz_dt.astimezone(att_tz)
|
||||||
|
# We take only the date omiting the hours as we compare with timesheet
|
||||||
|
# date_from which is a date format thus using hours would lead to
|
||||||
|
# be out of scope of timesheet
|
||||||
|
att_tz_date_str = datetime.strftime(att_tz_dt, DEFAULT_SERVER_DATE_FORMAT)
|
||||||
|
return att_tz_date_str
|
||||||
|
|
||||||
|
def _get_current_sheet(self, cr, uid, employee_id, date=False, context=None):
|
||||||
|
|
||||||
|
sheet_obj = self.pool['hr_timesheet_sheet.sheet']
|
||||||
|
if not date:
|
||||||
|
date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
|
||||||
|
att_tz_date_str = self._get_attendance_employee_tz(
|
||||||
|
cr, uid, employee_id,
|
||||||
|
date=date, context=context)
|
||||||
|
sheet_ids = sheet_obj.search(cr, uid,
|
||||||
|
[('date_from', '<=', att_tz_date_str),
|
||||||
|
('date_to', '>=', att_tz_date_str),
|
||||||
|
('employee_id', '=', employee_id)],
|
||||||
|
limit=1, context=context)
|
||||||
|
return sheet_ids and sheet_ids[0] or False
|
||||||
|
|
||||||
def _sheet(self, cursor, user, ids, name, args, context=None):
|
def _sheet(self, cursor, user, ids, name, args, context=None):
|
||||||
sheet_obj = self.pool.get('hr_timesheet_sheet.sheet')
|
|
||||||
res = {}.fromkeys(ids, False)
|
res = {}.fromkeys(ids, False)
|
||||||
for attendance in self.browse(cursor, user, ids, context=context):
|
for attendance in self.browse(cursor, user, ids, context=context):
|
||||||
date_to = datetime.strftime(datetime.strptime(attendance.name[0:10], '%Y-%m-%d'), '%Y-%m-%d %H:%M:%S')
|
res[attendance.id] = self._get_current_sheet(
|
||||||
sheet_ids = sheet_obj.search(cursor, user,
|
cursor, user, attendance.employee_id.id, attendance.name,
|
||||||
[('date_to', '>=', date_to), ('date_from', '<=', attendance.name),
|
context=context)
|
||||||
('employee_id', '=', attendance.employee_id.id)],
|
|
||||||
context=context)
|
|
||||||
if sheet_ids:
|
|
||||||
# [0] because only one sheet possible for an employee between 2 dates
|
|
||||||
res[attendance.id] = sheet_obj.name_get(cursor, user, sheet_ids, context=context)[0]
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
|
@ -426,16 +467,18 @@ class hr_attendance(osv.osv):
|
||||||
def create(self, cr, uid, vals, context=None):
|
def create(self, cr, uid, vals, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
if 'sheet_id' in context:
|
|
||||||
ts = self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, context['sheet_id'], context=context)
|
sheet_id = context.get('sheet_id') or self._get_current_sheet(cr, uid, vals.get('employee_id'), vals.get('name'), context=context)
|
||||||
|
if sheet_id:
|
||||||
|
att_tz_date_str = self._get_attendance_employee_tz(
|
||||||
|
cr, uid, vals.get('employee_id'),
|
||||||
|
date=vals.get('name'), context=context)
|
||||||
|
ts = self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, sheet_id, context=context)
|
||||||
if ts.state not in ('draft', 'new'):
|
if ts.state not in ('draft', 'new'):
|
||||||
raise osv.except_osv(_('Error!'), _('You cannot modify an entry in a confirmed timesheet.'))
|
raise osv.except_osv(_('Error!'), _('You can not enter an attendance in a submitted timesheet. Ask your manager to reset it before adding attendance.'))
|
||||||
res = super(hr_attendance,self).create(cr, uid, vals, context=context)
|
elif ts.date_from > att_tz_date_str or ts.date_to < att_tz_date_str:
|
||||||
if 'sheet_id' in context:
|
raise osv.except_osv(_('User Error!'), _('You can not enter an attendance date outside the current timesheet dates.'))
|
||||||
if context['sheet_id'] != self.browse(cr, uid, res, context=context).sheet_id.id:
|
return super(hr_attendance,self).create(cr, uid, vals, context=context)
|
||||||
raise osv.except_osv(_('User Error!'), _('You cannot enter an attendance ' \
|
|
||||||
'date outside the current timesheet dates.'))
|
|
||||||
return res
|
|
||||||
|
|
||||||
def unlink(self, cr, uid, ids, *args, **kwargs):
|
def unlink(self, cr, uid, ids, *args, **kwargs):
|
||||||
if isinstance(ids, (int, long)):
|
if isinstance(ids, (int, long)):
|
||||||
|
@ -585,4 +628,3 @@ class res_company(osv.osv):
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from openerp import SUPERUSER_ID
|
||||||
from openerp import http
|
from openerp import http
|
||||||
from openerp.http import request
|
from openerp.http import request
|
||||||
from openerp.addons.web.controllers.main import content_disposition
|
from openerp.addons.web.controllers.main import content_disposition
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
|
|
||||||
class MailController(http.Controller):
|
class MailController(http.Controller):
|
||||||
|
@ -19,10 +20,11 @@ class MailController(http.Controller):
|
||||||
if res:
|
if res:
|
||||||
filecontent = base64.b64decode(res.get('base64'))
|
filecontent = base64.b64decode(res.get('base64'))
|
||||||
filename = res.get('filename')
|
filename = res.get('filename')
|
||||||
|
content_type = mimetypes.guess_type(filename)
|
||||||
if filecontent and filename:
|
if filecontent and filename:
|
||||||
return request.make_response(
|
return request.make_response(
|
||||||
filecontent,
|
filecontent,
|
||||||
headers=[('Content-Type', 'application/octet-stream'),
|
headers=[('Content-Type', content_type[0] or 'application/octet-stream'),
|
||||||
('Content-Disposition', content_disposition(filename))])
|
('Content-Disposition', content_disposition(filename))])
|
||||||
return request.not_found()
|
return request.not_found()
|
||||||
|
|
||||||
|
|
|
@ -234,13 +234,17 @@ class mail_mail(osv.Model):
|
||||||
:return: True
|
:return: True
|
||||||
"""
|
"""
|
||||||
ir_mail_server = self.pool.get('ir.mail_server')
|
ir_mail_server = self.pool.get('ir.mail_server')
|
||||||
|
ir_attachment = self.pool['ir.attachment']
|
||||||
|
|
||||||
for mail in self.browse(cr, SUPERUSER_ID, ids, context=context):
|
for mail in self.browse(cr, SUPERUSER_ID, ids, context=context):
|
||||||
try:
|
try:
|
||||||
# handle attachments
|
# load attachment binary data with a separate read(), as prefetching all
|
||||||
attachments = []
|
# `datas` (binary field) could bloat the browse cache, triggerring
|
||||||
for attach in mail.attachment_ids:
|
# soft/hard mem limits with temporary data.
|
||||||
attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
|
attachment_ids = [a.id for a in mail.attachment_ids]
|
||||||
|
attachments = [(a['datas_fname'], base64.b64decode(a['datas']))
|
||||||
|
for a in ir_attachment.read(cr, SUPERUSER_ID, attachment_ids,
|
||||||
|
['datas_fname', 'datas'])]
|
||||||
# specific behavior to customize the send email for notified partners
|
# specific behavior to customize the send email for notified partners
|
||||||
email_list = []
|
email_list = []
|
||||||
if mail.email_to:
|
if mail.email_to:
|
||||||
|
@ -289,6 +293,14 @@ class mail_mail(osv.Model):
|
||||||
# /!\ can't use mail.state here, as mail.refresh() will cause an error
|
# /!\ can't use mail.state here, as mail.refresh() will cause an error
|
||||||
# see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1
|
# see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1
|
||||||
self._postprocess_sent_message(cr, uid, mail, context=context, mail_sent=mail_sent)
|
self._postprocess_sent_message(cr, uid, mail, context=context, mail_sent=mail_sent)
|
||||||
|
_logger.info('Mail with ID %r and Message-Id %r successfully sent', mail.id, mail.message_id)
|
||||||
|
except MemoryError:
|
||||||
|
# prevent catching transient MemoryErrors, bubble up to notify user or abort cron job
|
||||||
|
# instead of marking the mail as failed
|
||||||
|
_logger.exception('MemoryError while processing mail with ID %r and Msg-Id %r. '\
|
||||||
|
'Consider raising the --limit-memory-hard startup option',
|
||||||
|
mail.id, mail.message_id)
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.exception('failed sending mail.mail %s', mail.id)
|
_logger.exception('failed sending mail.mail %s', mail.id)
|
||||||
mail.write({'state': 'exception'})
|
mail.write({'state': 'exception'})
|
||||||
|
|
|
@ -434,14 +434,14 @@ class mail_thread(osv.AbstractModel):
|
||||||
fol_obj.unlink(cr, SUPERUSER_ID, fol_ids, context=context)
|
fol_obj.unlink(cr, SUPERUSER_ID, fol_ids, context=context)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def copy(self, cr, uid, id, default=None, context=None):
|
def copy_data(self, cr, uid, id, default=None, context=None):
|
||||||
# avoid tracking multiple temporary changes during copy
|
# avoid tracking multiple temporary changes during copy
|
||||||
context = dict(context or {}, mail_notrack=True)
|
context = dict(context or {}, mail_notrack=True)
|
||||||
|
|
||||||
default = default or {}
|
default = default or {}
|
||||||
default['message_ids'] = []
|
default['message_ids'] = []
|
||||||
default['message_follower_ids'] = []
|
default['message_follower_ids'] = []
|
||||||
return super(mail_thread, self).copy(cr, uid, id, default=default, context=context)
|
return super(mail_thread, self).copy_data(cr, uid, id, default=default, context=context)
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Automatically log tracked fields
|
# Automatically log tracked fields
|
||||||
|
|
|
@ -34,14 +34,14 @@ class project_configuration(osv.TransientModel):
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_default_alias_domain(self, cr, uid, ids, context=None):
|
def get_default_alias_domain(self, cr, uid, ids, context=None):
|
||||||
alias_domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "mail.catchall.domain", context=context)
|
alias_domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "mail.catchall.domain", default=None, context=context)
|
||||||
if not alias_domain:
|
if alias_domain is None:
|
||||||
domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "web.base.url", context=context)
|
domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "web.base.url", context=context)
|
||||||
try:
|
try:
|
||||||
alias_domain = urlparse.urlsplit(domain).netloc.split(':')[0]
|
alias_domain = urlparse.urlsplit(domain).netloc.split(':')[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
return {'alias_domain': alias_domain}
|
return {'alias_domain': alias_domain or False}
|
||||||
|
|
||||||
def set_alias_domain(self, cr, uid, ids, context=None):
|
def set_alias_domain(self, cr, uid, ids, context=None):
|
||||||
config_parameters = self.pool.get("ir.config_parameter")
|
config_parameters = self.pool.get("ir.config_parameter")
|
||||||
|
|
|
@ -48,6 +48,8 @@ professional emails and reuse templates in a few clicks.
|
||||||
'views/res_config.xml',
|
'views/res_config.xml',
|
||||||
'views/res_partner.xml',
|
'views/res_partner.xml',
|
||||||
'views/email_template.xml',
|
'views/email_template.xml',
|
||||||
|
'views/website_mass_mailing.xml',
|
||||||
|
'views/snippets.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
],
|
],
|
||||||
'js': [
|
'js': [
|
||||||
|
|
|
@ -40,3 +40,35 @@ class MassMailController(http.Controller):
|
||||||
if 'opt_out' in request.registry[mailing.mailing_model]._all_columns:
|
if 'opt_out' in request.registry[mailing.mailing_model]._all_columns:
|
||||||
request.registry[mailing.mailing_model].write(cr, SUPERUSER_ID, record_ids, {'opt_out': True}, context=context)
|
request.registry[mailing.mailing_model].write(cr, SUPERUSER_ID, record_ids, {'opt_out': True}, context=context)
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
||||||
|
@http.route(['/website_mass_mailing/is_subscriber'], type='json', auth="public", website=True)
|
||||||
|
def is_subscriber(self, list_id, **post):
|
||||||
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
|
Contacts = request.registry['mail.mass_mailing.contact']
|
||||||
|
Users = request.registry['res.users']
|
||||||
|
|
||||||
|
public_id = request.registry['website'].get_public_user(cr, uid, context)
|
||||||
|
is_subscriber = False
|
||||||
|
email = None
|
||||||
|
if uid != public_id:
|
||||||
|
email = Users.browse(cr, SUPERUSER_ID, uid, context).email
|
||||||
|
elif request.session.get('mass_mailing_email'):
|
||||||
|
email = request.session['mass_mailing_email']
|
||||||
|
|
||||||
|
if email:
|
||||||
|
contact_ids = Contacts.search(cr, SUPERUSER_ID, [('list_id', '=', int(list_id)), ('email', '=', email)], context=context)
|
||||||
|
is_subscriber = len(contact_ids) > 0
|
||||||
|
|
||||||
|
return {'is_subscriber': is_subscriber, 'email': email}
|
||||||
|
|
||||||
|
@http.route(['/website_mass_mailing/subscribe'], type='json', auth="public", website=True)
|
||||||
|
def subscribe(self, list_id, email, **post):
|
||||||
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
|
Contacts = request.registry['mail.mass_mailing.contact']
|
||||||
|
|
||||||
|
contact_ids = Contacts.search(cr, SUPERUSER_ID, [('list_id', '=', int(list_id)), ('email', '=', email)], context=context)
|
||||||
|
if not contact_ids:
|
||||||
|
Contacts.name_create(cr, SUPERUSER_ID, email, context=context)
|
||||||
|
# add email to session
|
||||||
|
request.session['mass_mailing_email'] = email
|
||||||
|
return True
|
||||||
|
|
|
@ -33,5 +33,10 @@
|
||||||
<field name="sequence">30</field>
|
<field name="sequence">30</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- Create mailing lists -->
|
||||||
|
<record id="mass_mail_list_1" model="mail.mass_mailing.list">
|
||||||
|
<field name="name">Newsletter</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
|
@ -9,7 +9,7 @@
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Create mailing lists -->
|
<!-- Create mailing lists -->
|
||||||
<record id="mass_mail_list_1" model="mail.mass_mailing.list">
|
<record id="mass_mail_list_2" model="mail.mass_mailing.list">
|
||||||
<field name="name">Imported Contacts</field>
|
<field name="name">Imported Contacts</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
@ -17,17 +17,17 @@
|
||||||
<record id="mass_mail_contact_1" model="mail.mass_mailing.contact">
|
<record id="mass_mail_contact_1" model="mail.mass_mailing.contact">
|
||||||
<field name="name">Aristide Antario</field>
|
<field name="name">Aristide Antario</field>
|
||||||
<field name="email">aa@example.com</field>
|
<field name="email">aa@example.com</field>
|
||||||
<field name="list_id" ref="mass_mailing.mass_mail_list_1"/>
|
<field name="list_id" ref="mass_mailing.mass_mail_list_2"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="mass_mail_contact_2" model="mail.mass_mailing.contact">
|
<record id="mass_mail_contact_2" model="mail.mass_mailing.contact">
|
||||||
<field name="name">Beverly Bridge</field>
|
<field name="name">Beverly Bridge</field>
|
||||||
<field name="email">bb@example.com</field>
|
<field name="email">bb@example.com</field>
|
||||||
<field name="list_id" ref="mass_mailing.mass_mail_list_1"/>
|
<field name="list_id" ref="mass_mailing.mass_mail_list_2"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="mass_mail_contact_3" model="mail.mass_mailing.contact">
|
<record id="mass_mail_contact_3" model="mail.mass_mailing.contact">
|
||||||
<field name="name">Carol Cartridge</field>
|
<field name="name">Carol Cartridge</field>
|
||||||
<field name="email">cc@example.com</field>
|
<field name="email">cc@example.com</field>
|
||||||
<field name="list_id" ref="mass_mailing.mass_mail_list_1"/>
|
<field name="list_id" ref="mass_mailing.mass_mail_list_2"/>
|
||||||
<field name="opt_out" eval="True"/>
|
<field name="opt_out" eval="True"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
|
@ -271,9 +271,9 @@ class MassMailing(osv.Model):
|
||||||
date_begin_str = date_begin.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
date_begin_str = date_begin.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
date_end_str = date_end.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
date_end_str = date_end.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
domain = [('mass_mailing_id', '=', mailing.id), ('opened', '>=', date_begin_str), ('opened', '<=', date_end_str)]
|
domain = [('mass_mailing_id', '=', mailing.id), ('opened', '>=', date_begin_str), ('opened', '<=', date_end_str)]
|
||||||
res[mailing.id]['opened_dayly'] = json.dumps(self.__get_bar_values(cr, uid, obj, domain, ['opened'], 'opened_count', 'opened:day', date_begin, context=context))
|
res[mailing.id]['opened_daily'] = json.dumps(self.__get_bar_values(cr, uid, obj, domain, ['opened'], 'opened_count', 'opened:day', date_begin, context=context))
|
||||||
domain = [('mass_mailing_id', '=', mailing.id), ('replied', '>=', date_begin_str), ('replied', '<=', date_end_str)]
|
domain = [('mass_mailing_id', '=', mailing.id), ('replied', '>=', date_begin_str), ('replied', '<=', date_end_str)]
|
||||||
res[mailing.id]['replied_dayly'] = json.dumps(self.__get_bar_values(cr, uid, obj, domain, ['replied'], 'replied_count', 'replied:day', date_begin, context=context))
|
res[mailing.id]['replied_daily'] = json.dumps(self.__get_bar_values(cr, uid, obj, domain, ['replied'], 'replied_count', 'replied:day', date_begin, context=context))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
|
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
|
||||||
|
@ -314,7 +314,7 @@ class MassMailing(osv.Model):
|
||||||
'name': fields.char('Subject', required=True),
|
'name': fields.char('Subject', required=True),
|
||||||
'email_from': fields.char('From', required=True),
|
'email_from': fields.char('From', required=True),
|
||||||
'create_date': fields.datetime('Creation Date'),
|
'create_date': fields.datetime('Creation Date'),
|
||||||
'sent_date': fields.datetime('Sent Date'),
|
'sent_date': fields.datetime('Sent Date', oldname='date'),
|
||||||
'body_html': fields.html('Body'),
|
'body_html': fields.html('Body'),
|
||||||
'attachment_ids': fields.many2many(
|
'attachment_ids': fields.many2many(
|
||||||
'ir.attachment', 'mass_mailing_ir_attachments_rel',
|
'ir.attachment', 'mass_mailing_ir_attachments_rel',
|
||||||
|
@ -340,7 +340,7 @@ class MassMailing(osv.Model):
|
||||||
'reply_to': fields.char('Reply To', help='Preferred Reply-To Address'),
|
'reply_to': fields.char('Reply To', help='Preferred Reply-To Address'),
|
||||||
# recipients
|
# recipients
|
||||||
'mailing_model': fields.selection(_mailing_model, string='Recipients Model', required=True),
|
'mailing_model': fields.selection(_mailing_model, string='Recipients Model', required=True),
|
||||||
'mailing_domain': fields.char('Domain'),
|
'mailing_domain': fields.char('Domain', oldname='domain'),
|
||||||
'contact_list_ids': fields.many2many(
|
'contact_list_ids': fields.many2many(
|
||||||
'mail.mass_mailing.list', 'mail_mass_mailing_list_rel',
|
'mail.mass_mailing.list', 'mail_mass_mailing_list_rel',
|
||||||
string='Mailing Lists',
|
string='Mailing Lists',
|
||||||
|
@ -398,16 +398,14 @@ class MassMailing(osv.Model):
|
||||||
_get_statistics, string='Replied Ratio',
|
_get_statistics, string='Replied Ratio',
|
||||||
type='integer', multi='_get_statistics',
|
type='integer', multi='_get_statistics',
|
||||||
),
|
),
|
||||||
# dayly ratio
|
# daily ratio
|
||||||
'opened_dayly': fields.function(
|
'opened_daily': fields.function(
|
||||||
_get_daily_statistics, string='Opened',
|
_get_daily_statistics, string='Opened',
|
||||||
type='char', multi='_get_daily_statistics',
|
type='char', multi='_get_daily_statistics',
|
||||||
oldname='opened_monthly',
|
|
||||||
),
|
),
|
||||||
'replied_dayly': fields.function(
|
'replied_daily': fields.function(
|
||||||
_get_daily_statistics, string='Replied',
|
_get_daily_statistics, string='Replied',
|
||||||
type='char', multi='_get_daily_statistics',
|
type='char', multi='_get_daily_statistics',
|
||||||
oldname='replied_monthly',
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,23 +19,8 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
from dateutil import relativedelta
|
|
||||||
import random
|
|
||||||
try:
|
|
||||||
import simplejson as json
|
|
||||||
except ImportError:
|
|
||||||
import json
|
|
||||||
import urllib
|
|
||||||
import urlparse
|
|
||||||
|
|
||||||
from openerp import tools
|
|
||||||
from openerp.exceptions import Warning
|
|
||||||
from openerp.tools.safe_eval import safe_eval as eval
|
|
||||||
from openerp.tools.translate import _
|
|
||||||
from openerp.osv import osv, fields
|
from openerp.osv import osv, fields
|
||||||
|
|
||||||
|
|
||||||
class MailMailStats(osv.Model):
|
class MailMailStats(osv.Model):
|
||||||
""" MailMailStats models the statistics collected about emails. Those statistics
|
""" MailMailStats models the statistics collected about emails. Those statistics
|
||||||
are stored in a separated model and table to avoid bloating the mail_mail table
|
are stored in a separated model and table to avoid bloating the mail_mail table
|
||||||
|
@ -48,11 +33,7 @@ class MailMailStats(osv.Model):
|
||||||
_order = 'message_id'
|
_order = 'message_id'
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'mail_mail_id': fields.integer(
|
'mail_mail_id': fields.many2one('mail.mail', 'Mail ID', ondelete='set null'),
|
||||||
'Mail ID',
|
|
||||||
help='ID of the related mail_mail. This field is an integer field because'
|
|
||||||
'the related mail_mail can be deleted separately from its statistics.'
|
|
||||||
),
|
|
||||||
'message_id': fields.char('Message-ID'),
|
'message_id': fields.char('Message-ID'),
|
||||||
'model': fields.char('Document model'),
|
'model': fields.char('Document model'),
|
||||||
'res_id': fields.integer('Document ID'),
|
'res_id': fields.integer('Document ID'),
|
||||||
|
@ -106,4 +87,3 @@ class MailMailStats(osv.Model):
|
||||||
stat_ids = self._get_ids(cr, uid, ids, mail_mail_ids, mail_message_ids, [('bounced', '=', False)], context)
|
stat_ids = self._get_ids(cr, uid, ids, mail_mail_ids, mail_message_ids, [('bounced', '=', False)], context)
|
||||||
self.write(cr, uid, stat_ids, {'bounced': fields.datetime.now()}, context=context)
|
self.write(cr, uid, stat_ids, {'bounced': fields.datetime.now()}, context=context)
|
||||||
return stat_ids
|
return stat_ids
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
|
@ -0,0 +1,40 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var website = openerp.website;
|
||||||
|
var _t = openerp._t;
|
||||||
|
|
||||||
|
website.snippet.options.mailing_list_subscribe = website.snippet.Option.extend({
|
||||||
|
on_prompt: function () {
|
||||||
|
var self = this;
|
||||||
|
return website.prompt({
|
||||||
|
id: "editor_new_mailing_list_subscribe_button",
|
||||||
|
window_title: _t("Add a Newsletter Subscribe Button"),
|
||||||
|
select: _t("Newsletter"),
|
||||||
|
init: function (field) {
|
||||||
|
return website.session.model('mail.mass_mailing.list')
|
||||||
|
.call('name_search', ['', []], { context: website.get_context() });
|
||||||
|
},
|
||||||
|
}).then(function (mailing_list_id) {
|
||||||
|
self.$target.attr("data-list-id", mailing_list_id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
drop_and_build_snippet: function() {
|
||||||
|
var self = this;
|
||||||
|
this._super();
|
||||||
|
this.on_prompt().fail(function () {
|
||||||
|
self.editor.on_remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
start : function () {
|
||||||
|
var self = this;
|
||||||
|
this.$el.find(".js_mailing_list").on("click", _.bind(this.on_prompt, this));
|
||||||
|
this._super();
|
||||||
|
},
|
||||||
|
clean_for_save: function () {
|
||||||
|
this.$target.addClass("hidden");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var website = openerp.website;
|
||||||
|
|
||||||
|
website.snippet.animationRegistry.subscribe = website.snippet.Animation.extend({
|
||||||
|
selector: ".js_subscribe",
|
||||||
|
start: function (editable_mode) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// set value and display button
|
||||||
|
self.$target.find("input").removeClass("hidden");
|
||||||
|
openerp.jsonRpc('/website_mass_mailing/is_subscriber', 'call', {
|
||||||
|
list_id: this.$target.data('list-id'),
|
||||||
|
}).always(function (data) {
|
||||||
|
self.$target.find('input.js_subscribe_email')
|
||||||
|
.val(data.email ? data.email : "")
|
||||||
|
.attr("disabled", data.is_subscriber && data.email.length ? "disabled" : false);
|
||||||
|
self.$target.attr("data-subscribe", data.is_subscriber ? 'on' : 'off');
|
||||||
|
self.$target.find('a.js_subscribe_btn')
|
||||||
|
.val(data.email ? data.email : "")
|
||||||
|
.attr("disabled", data.is_subscriber && data.email.length ? "disabled" : false);
|
||||||
|
self.$target.removeClass("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
// not if editable mode to allow designer to edit alert field
|
||||||
|
if (!editable_mode) {
|
||||||
|
$('.js_subscribe > .alert').addClass("hidden");
|
||||||
|
$('.js_subscribe > .input-group-btn.hidden').removeClass("hidden");
|
||||||
|
this.$target.find('.js_subscribe_btn').on('click', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
self.on_click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
on_click: function () {
|
||||||
|
var self = this;
|
||||||
|
var $email = this.$target.find(".js_subscribe_email:visible");
|
||||||
|
|
||||||
|
if ($email.length && !$email.val().match(/.+@.+/)) {
|
||||||
|
this.$target.addClass('has-error');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.$target.removeClass('has-error');
|
||||||
|
|
||||||
|
openerp.jsonRpc('/website_mass_mailing/subscribe', 'call', {
|
||||||
|
'list_id': this.$target.data('list-id'),
|
||||||
|
'email': $email.length ? $email.val() : false,
|
||||||
|
}).then(function (subscribe) {
|
||||||
|
self.$target.find(".js_subscribe_email, .input-group-btn").addClass("hidden");
|
||||||
|
self.$target.find(".alert").removeClass("hidden");
|
||||||
|
self.$target.find('input.js_subscribe_email').attr("disabled", subscribe ? "disabled" : false);
|
||||||
|
self.$target.attr("data-subscribe", subscribe ? 'on' : 'off');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
|
@ -208,11 +208,11 @@
|
||||||
</button>
|
</button>
|
||||||
<button name="%(action_view_mass_mailing_contacts)d"
|
<button name="%(action_view_mass_mailing_contacts)d"
|
||||||
type="action" class="oe_stat_button oe_inline">
|
type="action" class="oe_stat_button oe_inline">
|
||||||
<field name="opened_dayly" string="Opened Daily" widget="barchart"/>
|
<field name="opened_daily" string="Opened Daily" widget="barchart"/>
|
||||||
</button>
|
</button>
|
||||||
<button name="%(action_view_mass_mailing_contacts)d"
|
<button name="%(action_view_mass_mailing_contacts)d"
|
||||||
type="action" class="oe_stat_button oe_inline">
|
type="action" class="oe_stat_button oe_inline">
|
||||||
<field name="replied_dayly" string="Replied Daily" widget="barchart"/>
|
<field name="replied_daily" string="Replied Daily" widget="barchart"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_button_box" attrs="{'invisible': [('total', '=', 0)]}" style="margin-bottom: 32px">
|
<div class="oe_button_box" attrs="{'invisible': [('total', '=', 0)]}" style="margin-bottom: 32px">
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<template id="mailing_list_subscribe" inherit_id="website.snippets" name="Subscribe to Newsletter">
|
||||||
|
|
||||||
|
<xpath expr="//div[@id='snippet_content']" position="inside">
|
||||||
|
<div>
|
||||||
|
<div class="oe_snippet_thumbnail">
|
||||||
|
<img class="oe_snippet_thumbnail_img" src="/mass_mailing/static/src/img/blocks/button_newsletter.png"/>
|
||||||
|
<span class="oe_snippet_thumbnail_title">Newsletter</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="oe_snippet_body input-group js_subscribe"
|
||||||
|
data-list-id="0">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
class="js_subscribe_email form-control"
|
||||||
|
placeholder="your email..."/>
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<a href="#" class="btn btn-primary js_subscribe_btn">Subscribe</a>
|
||||||
|
</span>
|
||||||
|
<div class="alert alert-success hidden">Thanks for your subscription!</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//div[@id='snippet_options']" position="inside">
|
||||||
|
<div data-snippet-option-id='mailing_list_subscribe'
|
||||||
|
data-selector=".js_subscribe"
|
||||||
|
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a href="#" class="button js_mailing_list">Change Newsletter</a>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<template id="head" inherit_id="website.layout" name="Mail customization">
|
||||||
|
<xpath expr="//head" position="inside">
|
||||||
|
<script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.editor.js" groups="base.group_website_publisher"></script>
|
||||||
|
<script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.js"></script>
|
||||||
|
<link rel='stylesheet' href='/website_mail/static/src/css/website_mail.css'/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</openerp>
|
|
@ -59,7 +59,7 @@
|
||||||
<record id="res_company_oerp_us" model="res.company">
|
<record id="res_company_oerp_us" model="res.company">
|
||||||
<field name="partner_id" ref="res_partner_oerp_us"/>
|
<field name="partner_id" ref="res_partner_oerp_us"/>
|
||||||
<field name="parent_id" ref="res_company_oerp_editor"/>
|
<field name="parent_id" ref="res_company_oerp_editor"/>
|
||||||
<field name="currency_id" ref="base.EUR"/>
|
<field name="currency_id" ref="base.USD"/>
|
||||||
<field name="name">OpenERP US</field>
|
<field name="name">OpenERP US</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="res_company_oerp_be" model="res.company">
|
<record id="res_company_oerp_be" model="res.company">
|
||||||
|
@ -400,7 +400,7 @@
|
||||||
</record>
|
</record>
|
||||||
<record id="project.project_project_3" model="project.project">
|
<record id="project.project_project_3" model="project.project">
|
||||||
<field name="company_id" ref="res_company_oerp_us"/>
|
<field name="company_id" ref="res_company_oerp_us"/>
|
||||||
<field name="currency_id" ref="base.EUR"/>
|
<field name="currency_id" ref="base.USD"/>
|
||||||
</record>
|
</record>
|
||||||
<record id="project.project_project_4" model="project.project">
|
<record id="project.project_project_4" model="project.project">
|
||||||
<field name="company_id" ref="res_company_oerp_be"/>
|
<field name="company_id" ref="res_company_oerp_be"/>
|
||||||
|
|
|
@ -1167,8 +1167,8 @@ class pos_order(osv.osv):
|
||||||
return self.write(cr, uid, ids, {'state': 'payment'}, context=context)
|
return self.write(cr, uid, ids, {'state': 'payment'}, context=context)
|
||||||
|
|
||||||
def action_paid(self, cr, uid, ids, context=None):
|
def action_paid(self, cr, uid, ids, context=None):
|
||||||
self.create_picking(cr, uid, ids, context=context)
|
|
||||||
self.write(cr, uid, ids, {'state': 'paid'}, context=context)
|
self.write(cr, uid, ids, {'state': 'paid'}, context=context)
|
||||||
|
self.create_picking(cr, uid, ids, context=context)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def action_cancel(self, cr, uid, ids, context=None):
|
def action_cancel(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -805,9 +805,17 @@ class product_product(osv.osv):
|
||||||
price_type_currency_id = pricetype_obj.browse(cr,uid,price_type_id).currency_id.id
|
price_type_currency_id = pricetype_obj.browse(cr,uid,price_type_id).currency_id.id
|
||||||
|
|
||||||
res = {}
|
res = {}
|
||||||
|
# standard_price field can only be seen by users in base.group_user
|
||||||
|
# Thus, in order to compute the sale price from the cost price for users not in this group
|
||||||
|
# We fetch the standard price as the superuser
|
||||||
|
for product in products:
|
||||||
|
if ptype != 'standard_price':
|
||||||
|
res[product.id] = product[ptype] or 0.0
|
||||||
|
else:
|
||||||
|
res[product.id] = self.read(cr, SUPERUSER_ID, product.id, [ptype], context=context)[ptype] or 0.0
|
||||||
|
|
||||||
product_uom_obj = self.pool.get('product.uom')
|
product_uom_obj = self.pool.get('product.uom')
|
||||||
for product in products:
|
for product in products:
|
||||||
res[product.id] = product[ptype] or 0.0
|
|
||||||
if ptype == 'list_price':
|
if ptype == 'list_price':
|
||||||
res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \
|
res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \
|
||||||
product.price_extra
|
product.price_extra
|
||||||
|
|
|
@ -260,11 +260,17 @@ class Report(osv.Model):
|
||||||
def get_action(self, cr, uid, ids, report_name, data=None, context=None):
|
def get_action(self, cr, uid, ids, report_name, data=None, context=None):
|
||||||
"""Return an action of type ir.actions.report.xml.
|
"""Return an action of type ir.actions.report.xml.
|
||||||
|
|
||||||
|
:param ids: Ids of the records to print (if not used, pass an empty list)
|
||||||
:param report_name: Name of the template to generate an action for
|
:param report_name: Name of the template to generate an action for
|
||||||
"""
|
"""
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
if not isinstance(ids, list):
|
||||||
|
ids = [ids]
|
||||||
|
context['active_ids'] = ids
|
||||||
|
|
||||||
report_obj = self.pool['ir.actions.report.xml']
|
report_obj = self.pool['ir.actions.report.xml']
|
||||||
idreport = report_obj.search(cr, uid, [('report_name', '=', report_name)], context=context)
|
idreport = report_obj.search(cr, uid, [('report_name', '=', report_name)], context=context)
|
||||||
try:
|
try:
|
||||||
|
@ -272,7 +278,7 @@ class Report(osv.Model):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise osv.except_osv(_('Bad Report'), _('This report is not loaded into the database.'))
|
raise osv.except_osv(_('Bad Report'), _('This report is not loaded into the database.'))
|
||||||
|
|
||||||
action = {
|
return {
|
||||||
'context': context,
|
'context': context,
|
||||||
'data': data,
|
'data': data,
|
||||||
'type': 'ir.actions.report.xml',
|
'type': 'ir.actions.report.xml',
|
||||||
|
@ -280,7 +286,6 @@ class Report(osv.Model):
|
||||||
'report_type': report.report_type,
|
'report_type': report.report_type,
|
||||||
'report_file': report.report_file,
|
'report_file': report.report_file,
|
||||||
}
|
}
|
||||||
return action
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
# Report generation helpers
|
# Report generation helpers
|
||||||
|
|
|
@ -79,7 +79,7 @@ TODO:
|
||||||
* Web client WYSIWYG
|
* Web client WYSIWYG
|
||||||
""",
|
""",
|
||||||
'version': '0.9',
|
'version': '0.9',
|
||||||
'depends': ['base'],
|
'depends': ['base','report'],
|
||||||
'author': 'Camptocamp',
|
'author': 'Camptocamp',
|
||||||
'category': 'Reporting', # i.e a technical module, not shown in Application install menu
|
'category': 'Reporting', # i.e a technical module, not shown in Application install menu
|
||||||
'url': 'http://http://www.camptocamp.com/',
|
'url': 'http://http://www.camptocamp.com/',
|
||||||
|
|
|
@ -356,7 +356,6 @@ class sale_order(osv.osv):
|
||||||
}
|
}
|
||||||
|
|
||||||
def ship_recreate(self, cr, uid, order, line, move_id, proc_id):
|
def ship_recreate(self, cr, uid, order, line, move_id, proc_id):
|
||||||
# FIXME: deals with potentially cancelled shipments, seems broken (specially if shipment has production lot)
|
|
||||||
"""
|
"""
|
||||||
Define ship_recreate for process after shipping exception
|
Define ship_recreate for process after shipping exception
|
||||||
param order: sales order to which the order lines belong
|
param order: sales order to which the order lines belong
|
||||||
|
@ -365,16 +364,25 @@ class sale_order(osv.osv):
|
||||||
param proc_id: the ID of procurement
|
param proc_id: the ID of procurement
|
||||||
"""
|
"""
|
||||||
move_obj = self.pool.get('stock.move')
|
move_obj = self.pool.get('stock.move')
|
||||||
if order.state == 'shipping_except':
|
proc_obj = self.pool.get('procurement.order')
|
||||||
for pick in order.picking_ids:
|
if move_id and order.state == 'shipping_except':
|
||||||
for move in pick.move_lines:
|
current_move = move_obj.browse(cr, uid, move_id)
|
||||||
if move.state == 'cancel':
|
moves = []
|
||||||
mov_ids = move_obj.search(cr, uid, [('state', '=', 'cancel'),('sale_line_id', '=', line.id),('picking_id', '=', pick.id)])
|
for picking in order.picking_ids:
|
||||||
if mov_ids:
|
if picking.id != current_move.picking_id.id and picking.state != 'cancel':
|
||||||
for mov in move_obj.browse(cr, uid, mov_ids):
|
moves.extend(move for move in picking.move_lines if move.state != 'cancel' and move.sale_line_id.id == line.id)
|
||||||
# FIXME: the following seems broken: what if move_id doesn't exist? What if there are several mov_ids? Shouldn't that be a sum?
|
if moves:
|
||||||
move_obj.write(cr, uid, [move_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
|
product_qty = current_move.product_qty
|
||||||
self.pool.get('procurement.order').write(cr, uid, [proc_id], {'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty})
|
product_uos_qty = current_move.product_uos_qty
|
||||||
|
for move in moves:
|
||||||
|
product_qty -= move.product_qty
|
||||||
|
product_uos_qty -= move.product_uos_qty
|
||||||
|
if product_qty > 0 or product_uos_qty > 0:
|
||||||
|
move_obj.write(cr, uid, [move_id], {'product_qty': product_qty, 'product_uos_qty': product_uos_qty})
|
||||||
|
proc_obj.write(cr, uid, [proc_id], {'product_qty': product_qty, 'product_uos_qty': product_uos_qty})
|
||||||
|
else:
|
||||||
|
current_move.unlink()
|
||||||
|
proc_obj.unlink(cr, uid, [proc_id])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
|
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
|
||||||
|
|
|
@ -105,7 +105,9 @@ class product_product(osv.osv):
|
||||||
'compute_child': False
|
'compute_child': False
|
||||||
})
|
})
|
||||||
|
|
||||||
qty = product.qty_available
|
# qty_available depends of the location in the context
|
||||||
|
qty = self.read(cr, uid, [product.id], ['qty_available'], context=c)[0]['qty_available']
|
||||||
|
|
||||||
diff = product.standard_price - new_price
|
diff = product.standard_price - new_price
|
||||||
if not diff: raise osv.except_osv(_('Error!'), _("No difference between standard price and new price!"))
|
if not diff: raise osv.except_osv(_('Error!'), _("No difference between standard price and new price!"))
|
||||||
if qty:
|
if qty:
|
||||||
|
|
|
@ -2307,7 +2307,9 @@ class stock_move(osv.osv):
|
||||||
|
|
||||||
# if product is set to average price and a specific value was entered in the picking wizard,
|
# if product is set to average price and a specific value was entered in the picking wizard,
|
||||||
# we use it
|
# we use it
|
||||||
if move.product_id.cost_method == 'average' and move.price_unit:
|
if move.location_dest_id.usage != 'internal' and move.product_id.cost_method == 'average':
|
||||||
|
reference_amount = qty * move.product_id.standard_price
|
||||||
|
elif move.product_id.cost_method == 'average' and move.price_unit:
|
||||||
reference_amount = qty * move.price_unit
|
reference_amount = qty * move.price_unit
|
||||||
reference_currency_id = move.price_currency_id.id or reference_currency_id
|
reference_currency_id = move.price_currency_id.id or reference_currency_id
|
||||||
|
|
||||||
|
|
|
@ -792,7 +792,7 @@
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="Products">
|
<page string="Products">
|
||||||
<field name="move_lines" context="{'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'picking_type': 'internal'}" options='{"reload_on_button": true}'/>
|
<field name="move_lines" string="Stock Move" context="{'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'picking_type': 'internal'}" options='{"reload_on_button": true}'/>
|
||||||
<field name="note" placeholder="Add an internal note..." class="oe_inline"/>
|
<field name="note" placeholder="Add an internal note..." class="oe_inline"/>
|
||||||
</page>
|
</page>
|
||||||
<page string="Additional Info">
|
<page string="Additional Info">
|
||||||
|
@ -926,7 +926,7 @@
|
||||||
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Customer" domain="[('customer','=',True)]" />
|
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Customer" domain="[('customer','=',True)]" />
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='move_lines']" position="replace">
|
<xpath expr="//field[@name='move_lines']" position="replace">
|
||||||
<field name="move_lines" context="{'address_out_id': partner_id, 'picking_type': 'out', 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree'}" options='{"reload_on_button": true}'/>
|
<field name="move_lines" string="Stock Move" context="{'address_out_id': partner_id, 'picking_type': 'out', 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree'}" options='{"reload_on_button": true}'/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/sheet" position="after">
|
<xpath expr="/form/sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
|
@ -1053,7 +1053,7 @@
|
||||||
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Supplier" domain="[('supplier','=',True)]" context="{'default_supplier':1,'default_customer':0}"/>
|
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Supplier" domain="[('supplier','=',True)]" context="{'default_supplier':1,'default_customer':0}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='move_lines']" position="replace">
|
<xpath expr="//field[@name='move_lines']" position="replace">
|
||||||
<field name="move_lines" context="{'address_in_id': partner_id, 'picking_type': 'in', 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree'}" options='{"reload_on_button": true}'/>
|
<field name="move_lines" string="Stock Move" context="{'address_in_id': partner_id, 'picking_type': 'in', 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree'}" options='{"reload_on_button": true}'/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="/form/sheet" position="after">
|
<xpath expr="/form/sheet" position="after">
|
||||||
<div class="oe_chatter">
|
<div class="oe_chatter">
|
||||||
|
@ -1271,7 +1271,7 @@
|
||||||
<field name="date" attrs="{'invisible': [('state', '!=', 'done')]}"/>
|
<field name="date" attrs="{'invisible': [('state', '!=', 'done')]}"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="Traceability"
|
<group string="Traceability"
|
||||||
groups="stock.group_tracking_lot">
|
groups="stock.group_tracking_lot,stock.group_production_lot">
|
||||||
<label for="tracking_id" groups="stock.group_tracking_lot"/>
|
<label for="tracking_id" groups="stock.group_tracking_lot"/>
|
||||||
<div groups="stock.group_tracking_lot">
|
<div groups="stock.group_tracking_lot">
|
||||||
<field name="tracking_id" class="oe_inline"/>
|
<field name="tracking_id" class="oe_inline"/>
|
||||||
|
@ -1340,7 +1340,7 @@
|
||||||
|
|
||||||
<group string="Locations" groups="stock.group_locations">
|
<group string="Locations" groups="stock.group_locations">
|
||||||
<field name="location_id" domain="[('usage','<>','view')]"/>
|
<field name="location_id" domain="[('usage','<>','view')]"/>
|
||||||
<field name="location_dest_id" domain="[('usage','=','internal')]" groups="stock.group_locations"/>
|
<field name="location_dest_id" domain="[('usage','in', ['internal', 'supplier', 'customer'])]" groups="stock.group_locations"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group groups="stock.group_tracking_lot" string="Traceability">
|
<group groups="stock.group_tracking_lot" string="Traceability">
|
||||||
|
|
|
@ -62,14 +62,14 @@ class sale_order(osv.osv):
|
||||||
message = False
|
message = False
|
||||||
partner = self.pool.get('res.partner').browse(cr, uid, part, context=context)
|
partner = self.pool.get('res.partner').browse(cr, uid, part, context=context)
|
||||||
if partner.sale_warn != 'no-message':
|
if partner.sale_warn != 'no-message':
|
||||||
if partner.sale_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (partner.name), partner.sale_warn_msg)
|
|
||||||
title = _("Warning for %s") % partner.name
|
title = _("Warning for %s") % partner.name
|
||||||
message = partner.sale_warn_msg
|
message = partner.sale_warn_msg
|
||||||
warning = {
|
warning = {
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': message,
|
'message': message,
|
||||||
}
|
}
|
||||||
|
if partner.sale_warn == 'block':
|
||||||
|
return {'value': {'partner_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(sale_order, self).onchange_partner_id(cr, uid, ids, part, context=context)
|
result = super(sale_order, self).onchange_partner_id(cr, uid, ids, part, context=context)
|
||||||
|
|
||||||
|
@ -90,14 +90,15 @@ class purchase_order(osv.osv):
|
||||||
message = False
|
message = False
|
||||||
partner = self.pool.get('res.partner').browse(cr, uid, part)
|
partner = self.pool.get('res.partner').browse(cr, uid, part)
|
||||||
if partner.purchase_warn != 'no-message':
|
if partner.purchase_warn != 'no-message':
|
||||||
if partner.purchase_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (partner.name), partner.purchase_warn_msg)
|
|
||||||
title = _("Warning for %s") % partner.name
|
title = _("Warning for %s") % partner.name
|
||||||
message = partner.purchase_warn_msg
|
message = partner.purchase_warn_msg
|
||||||
warning = {
|
warning = {
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
|
if partner.purchase_warn == 'block':
|
||||||
|
return {'value': {'partner_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(purchase_order, self).onchange_partner_id(cr, uid, ids, part)
|
result = super(purchase_order, self).onchange_partner_id(cr, uid, ids, part)
|
||||||
|
|
||||||
if result.get('warning',False):
|
if result.get('warning',False):
|
||||||
|
@ -123,15 +124,16 @@ class account_invoice(osv.osv):
|
||||||
message = False
|
message = False
|
||||||
partner = self.pool.get('res.partner').browse(cr, uid, partner_id)
|
partner = self.pool.get('res.partner').browse(cr, uid, partner_id)
|
||||||
if partner.invoice_warn != 'no-message':
|
if partner.invoice_warn != 'no-message':
|
||||||
if partner.invoice_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (partner.name), partner.invoice_warn_msg)
|
|
||||||
|
|
||||||
title = _("Warning for %s") % partner.name
|
title = _("Warning for %s") % partner.name
|
||||||
message = partner.invoice_warn_msg
|
message = partner.invoice_warn_msg
|
||||||
warning = {
|
warning = {
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if partner.invoice_warn == 'block':
|
||||||
|
return {'value': {'partner_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id,
|
result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id,
|
||||||
date_invoice=date_invoice, payment_term=payment_term,
|
date_invoice=date_invoice, payment_term=payment_term,
|
||||||
partner_bank_id=partner_bank_id, company_id=company_id)
|
partner_bank_id=partner_bank_id, company_id=company_id)
|
||||||
|
@ -154,14 +156,15 @@ class stock_picking(osv.osv):
|
||||||
title = False
|
title = False
|
||||||
message = False
|
message = False
|
||||||
if partner.picking_warn != 'no-message':
|
if partner.picking_warn != 'no-message':
|
||||||
if partner.picking_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (partner.name), partner.picking_warn_msg)
|
|
||||||
title = _("Warning for %s") % partner.name
|
title = _("Warning for %s") % partner.name
|
||||||
message = partner.picking_warn_msg
|
message = partner.picking_warn_msg
|
||||||
warning = {
|
warning = {
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
|
if partner.picking_warn == 'block':
|
||||||
|
return {'value': {'partner_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(stock_picking, self).onchange_partner_in(cr, uid, ids, partner_id, context)
|
result = super(stock_picking, self).onchange_partner_in(cr, uid, ids, partner_id, context)
|
||||||
if result.get('warning',False):
|
if result.get('warning',False):
|
||||||
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
|
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
|
||||||
|
@ -183,14 +186,15 @@ class stock_picking_in(osv.osv):
|
||||||
title = False
|
title = False
|
||||||
message = False
|
message = False
|
||||||
if partner.picking_warn != 'no-message':
|
if partner.picking_warn != 'no-message':
|
||||||
if partner.picking_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (partner.name), partner.picking_warn_msg)
|
|
||||||
title = _("Warning for %s") % partner.name
|
title = _("Warning for %s") % partner.name
|
||||||
message = partner.picking_warn_msg
|
message = partner.picking_warn_msg
|
||||||
warning = {
|
warning = {
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
|
if partner.picking_warn == 'block':
|
||||||
|
return {'value': {'partner_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(stock_picking_in, self).onchange_partner_in(cr, uid, ids, partner_id, context)
|
result = super(stock_picking_in, self).onchange_partner_in(cr, uid, ids, partner_id, context)
|
||||||
if result.get('warning',False):
|
if result.get('warning',False):
|
||||||
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
|
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
|
||||||
|
@ -209,14 +213,15 @@ class stock_picking_out(osv.osv):
|
||||||
title = False
|
title = False
|
||||||
message = False
|
message = False
|
||||||
if partner.picking_warn != 'no-message':
|
if partner.picking_warn != 'no-message':
|
||||||
if partner.picking_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (partner.name), partner.picking_warn_msg)
|
|
||||||
title = _("Warning for %s") % partner.name
|
title = _("Warning for %s") % partner.name
|
||||||
message = partner.picking_warn_msg
|
message = partner.picking_warn_msg
|
||||||
warning = {
|
warning = {
|
||||||
'title': title,
|
'title': title,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
|
if partner.picking_warn == 'block':
|
||||||
|
return {'value': {'partner_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(stock_picking_out, self).onchange_partner_in(cr, uid, ids, partner_id, context)
|
result = super(stock_picking_out, self).onchange_partner_in(cr, uid, ids, partner_id, context)
|
||||||
if result.get('warning',False):
|
if result.get('warning',False):
|
||||||
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
|
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
|
||||||
|
@ -256,12 +261,12 @@ class sale_order_line(osv.osv):
|
||||||
message = False
|
message = False
|
||||||
|
|
||||||
if product_info.sale_line_warn != 'no-message':
|
if product_info.sale_line_warn != 'no-message':
|
||||||
if product_info.sale_line_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (product_info.name), product_info.sale_line_warn_msg)
|
|
||||||
title = _("Warning for %s") % product_info.name
|
title = _("Warning for %s") % product_info.name
|
||||||
message = product_info.sale_line_warn_msg
|
message = product_info.sale_line_warn_msg
|
||||||
warning['title'] = title
|
warning['title'] = title
|
||||||
warning['message'] = message
|
warning['message'] = message
|
||||||
|
if product_info.sale_line_warn == 'block':
|
||||||
|
return {'value': {'product_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(sale_order_line, self).product_id_change( cr, uid, ids, pricelist, product, qty,
|
result = super(sale_order_line, self).product_id_change( cr, uid, ids, pricelist, product, qty,
|
||||||
uom, qty_uos, uos, name, partner_id,
|
uom, qty_uos, uos, name, partner_id,
|
||||||
|
@ -288,12 +293,12 @@ class purchase_order_line(osv.osv):
|
||||||
message = False
|
message = False
|
||||||
|
|
||||||
if product_info.purchase_line_warn != 'no-message':
|
if product_info.purchase_line_warn != 'no-message':
|
||||||
if product_info.purchase_line_warn == 'block':
|
|
||||||
raise osv.except_osv(_('Alert for %s!') % (product_info.name), product_info.purchase_line_warn_msg)
|
|
||||||
title = _("Warning for %s") % product_info.name
|
title = _("Warning for %s") % product_info.name
|
||||||
message = product_info.purchase_line_warn_msg
|
message = product_info.purchase_line_warn_msg
|
||||||
warning['title'] = title
|
warning['title'] = title
|
||||||
warning['message'] = message
|
warning['message'] = message
|
||||||
|
if product_info.purchase_line_warn == 'block':
|
||||||
|
return {'value': {'product_id': False}, 'warning': warning}
|
||||||
|
|
||||||
result = super(purchase_order_line, self).onchange_product_id(cr, uid, ids, pricelist, product, qty, uom,
|
result = super(purchase_order_line, self).onchange_product_id(cr, uid, ids, pricelist, product, qty, uom,
|
||||||
partner_id, date_order, fiscal_position_id)
|
partner_id, date_order, fiscal_position_id)
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_website_public,website,website.model_website,,1,0,0,0
|
access_website_public,website,website.model_website,,1,0,0,0
|
||||||
access_website,website,website.model_website,base.group_user,1,0,0,0
|
access_website,website,website.model_website,base.group_website_designer,1,1,1,1
|
||||||
access_website_menu,access_website_menu,model_website_menu,,1,0,0,0
|
access_website_menu,access_website_menu,model_website_menu,,1,0,0,0
|
||||||
|
access_website_menu_designer,Web Menu Manager,model_website_menu,base.group_website_designer,1,1,1,1
|
||||||
|
access_website,web menu manager,website.model_website,base.group_website_designer,1,1,1,1
|
||||||
access_website_converter_test,access_website_converter_test,model_website_converter_test,,1,1,1,1
|
access_website_converter_test,access_website_converter_test,model_website_converter_test,,1,1,1,1
|
||||||
access_website_converter_test_sub,access_website_converter_test_sub,model_website_converter_test_sub,,1,1,1,1
|
access_website_converter_test_sub,access_website_converter_test_sub,model_website_converter_test_sub,,1,1,1,1
|
||||||
access_website_ir_ui_view,access_website_ir_ui_view,model_ir_ui_view,base.group_website_designer,1,1,1,1
|
access_website_ir_ui_view,access_website_ir_ui_view,model_ir_ui_view,base.group_website_designer,1,1,1,1
|
||||||
access_seo_public,access_seo_public,model_website_seo_metadata,,1,0,0,0
|
access_seo_public,access_seo_public,model_website_seo_metadata,,1,0,0,0
|
||||||
|
access_seo_public,access_seo_manager,model_website_seo_metadata,base.group_website_designer,1,1,1,1
|
||||||
access_seo_designer,access_seo_designer,model_website_seo_metadata,base.group_website_designer,1,1,1,1
|
access_seo_designer,access_seo_designer,model_website_seo_metadata,base.group_website_designer,1,1,1,1
|
||||||
|
|
|
|
@ -1056,6 +1056,7 @@
|
||||||
this.trigger("saved");
|
this.trigger("saved");
|
||||||
},
|
},
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
|
this.trigger("cancel");
|
||||||
},
|
},
|
||||||
close: function () {
|
close: function () {
|
||||||
this.$el.modal('hide');
|
this.$el.modal('hide');
|
||||||
|
|
|
@ -362,7 +362,7 @@
|
||||||
},
|
},
|
||||||
clean_for_save: function () {
|
clean_for_save: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
$(website.snippet.globalSelector).each(function () {
|
this.dom_filter(website.snippet.globalSelector).each(function () {
|
||||||
var $snippet = $(this);
|
var $snippet = $(this);
|
||||||
self.make_active($snippet);
|
self.make_active($snippet);
|
||||||
self.make_active(false);
|
self.make_active(false);
|
||||||
|
@ -875,20 +875,29 @@
|
||||||
this._super(np);
|
this._super(np);
|
||||||
if (np.$next) {
|
if (np.$next) {
|
||||||
if (np.$next.hasClass("oe_custom_bg")) {
|
if (np.$next.hasClass("oe_custom_bg")) {
|
||||||
var editor = new website.editor.ImageDialog();
|
var $image = $('<img class="hidden"/>');
|
||||||
editor.on('start', self, function (o) {o.url = np.$prev && np.$prev.data("src") || np.$next && np.$next.data("src") || "";});
|
$image.attr("src", np.$prev ? np.$prev.data("src") : '');
|
||||||
editor.on('save', self, function (o) {
|
$image.appendTo(self.$target);
|
||||||
self._set_bg(o.url);
|
|
||||||
np.$next.data("src", o.url);
|
self.element = new CKEDITOR.dom.element($image[0]);
|
||||||
|
var editor = new website.editor.MediaDialog(self, self.element);
|
||||||
|
editor.appendTo(document.body);
|
||||||
|
editor.$('[href="#editor-media-video"], [href="#editor-media-icon"]').addClass('hidden');
|
||||||
|
|
||||||
|
$image.on('saved', self, function (o) {
|
||||||
|
var src = $image.attr("src");
|
||||||
|
self._set_bg(src);
|
||||||
|
np.$next.data("src", src);
|
||||||
self.$target.trigger("snippet-style-change", [self, np]);
|
self.$target.trigger("snippet-style-change", [self, np]);
|
||||||
|
$image.remove();
|
||||||
});
|
});
|
||||||
editor.on('cancel', self, function () {
|
editor.on('cancel', self, function () {
|
||||||
if (!np.$prev || np.$prev.data("src") === "") {
|
if (!np.$prev || np.$prev.data("src") === "") {
|
||||||
self.$target.removeClass(np.$next.data("value"));
|
self.$target.removeClass(np.$next.data("value"));
|
||||||
self.$target.trigger("snippet-style-change", [self, np]);
|
self.$target.trigger("snippet-style-change", [self, np]);
|
||||||
}
|
}
|
||||||
|
$image.remove();
|
||||||
});
|
});
|
||||||
editor.appendTo($('body'));
|
|
||||||
} else {
|
} else {
|
||||||
this._set_bg(np.$next.data("src"));
|
this._set_bg(np.$next.data("src"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
<section class="oe_container">
|
<section class="oe_container">
|
||||||
<div class="oe_row">
|
<div class="oe_row">
|
||||||
<h2 class="oe_slogan">Automated Translation by Professionals</h2>
|
<h2 class="oe_slogan">Automated Translation by Professionals</h2>
|
||||||
<h3 class="oe_slogan">Reach multi-languages audiences without Pain</h3>
|
<h3 class="oe_slogan">Reach multi-language audiences without pain</h3>
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<div class="oe_bg_img">
|
<div class="oe_bg_img">
|
||||||
<img class="oe_picture" src="openerp_translation_tool.png">
|
<img class="oe_picture" src="openerp_translation_tool.png">
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
<h3 class="oe_slogan">Live chat with your visitors in one click</h3>
|
<h3 class="oe_slogan">Live chat with your visitors in one click</h3>
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<p class='oe_mt32'>
|
<p class='oe_mt32'>
|
||||||
The integrated live chat features allows you to start chatting in
|
The integrated live chat feature allows you to start chatting in
|
||||||
real time with your visitors to get feedback on your recent posts
|
real time with your visitors to get feedback on your recent posts
|
||||||
or get ideas to write new posts.
|
or get ideas to write new posts.
|
||||||
</p><p>
|
</p><p>
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
|
|
||||||
<section class="oe_container">
|
<section class="oe_container">
|
||||||
<div class="oe_row">
|
<div class="oe_row">
|
||||||
<h2 class="oe_slogan">Build Visitors Loyalty</h2>
|
<h2 class="oe_slogan">Build Visitor Loyalty</h2>
|
||||||
<h3 class="oe_slogan">Social Media Integration and Easy Following</h3>
|
<h3 class="oe_slogan">Social Media Integration and Easy Following</h3>
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<img class="oe_picture oe_screenshot" src="social.png">
|
<img class="oe_picture oe_screenshot" src="social.png">
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
<p class='oe_mt32'>
|
<p class='oe_mt32'>
|
||||||
The one click <em>follow</em> button will allow visitors
|
The one click <em>follow</em> button will allow visitors
|
||||||
to receive your blog posts by email with no effort, without
|
to receive your blog posts by email with no effort, without
|
||||||
having to register. Social media icons allows visitors to share
|
having to register. Social media icons allow visitors to share
|
||||||
your best blog posts easily.
|
your best blog posts easily.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<p class='oe_mt32'>
|
<p class='oe_mt32'>
|
||||||
Get a clear visibility of your sales funnel. OpenERP's Google
|
Get a clear visibility of your sales funnel. OpenERP's Google
|
||||||
Analytics trackers are configured by default to track all kind of
|
Analytics trackers are configured by default to track all kinds of
|
||||||
events related to shopping carts, call-to-actions, etc.
|
events related to shopping carts, call-to-actions, etc.
|
||||||
</p><p>
|
</p><p>
|
||||||
As OpenERP marketing tools (mass mailing, campaigns, etc) are also
|
As OpenERP marketing tools (mass mailing, campaigns, etc) are also
|
||||||
|
@ -141,13 +141,13 @@
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<p class='oe_mt32'>
|
<p class='oe_mt32'>
|
||||||
SEO tools are ready to use, with no configuration required.
|
SEO tools are ready to use, with no configuration required.
|
||||||
OpenERP suggests keywords for your titles according to Google
|
OpenERP suggests keywords for your titles according to Google's
|
||||||
most searched terms, Google Analytics tracks interrests of your
|
most searched terms, Google Analytics tracks interests of your
|
||||||
visitors, sitemap are created automatically for Google
|
visitors, sitemaps are created automatically for quick Google
|
||||||
indexation, etc.
|
indexing, etc.
|
||||||
</p><p>
|
</p><p>
|
||||||
We even do structured content automatically to promote your
|
The system even creates structured content automatically to promote your
|
||||||
product and events efficiently in Google.
|
products and events effectively in Google.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -162,10 +162,10 @@
|
||||||
Themes are awesome and easy to design. You don't need to develop
|
Themes are awesome and easy to design. You don't need to develop
|
||||||
to create new pages, themes or building blocks. We use a clean
|
to create new pages, themes or building blocks. We use a clean
|
||||||
HTML structure, a <a href="http://getbootstrap.com/">bootstrap</a>
|
HTML structure, a <a href="http://getbootstrap.com/">bootstrap</a>
|
||||||
CSS and our modularity allows to distribute your themes easily.
|
CSS and our modularity allows you to distribute your themes easily.
|
||||||
</p><p>
|
</p><p>
|
||||||
The building block approach allows the website to remain clean
|
The building block approach allows the website to remain clean
|
||||||
after the end-users start creating new contents.
|
after end-users start creating new contents.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
|
@ -178,7 +178,7 @@
|
||||||
<section class="oe_container">
|
<section class="oe_container">
|
||||||
<div class="oe_row">
|
<div class="oe_row">
|
||||||
<h2 class="oe_slogan">Easy Access Rights</h2>
|
<h2 class="oe_slogan">Easy Access Rights</h2>
|
||||||
<h3 class="oe_slogan">Adapt your publishing process to your own need</h3>
|
<h3 class="oe_slogan">A publishing process that meets your own needs</h3>
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<div class="oe_bg_img">
|
<div class="oe_bg_img">
|
||||||
<img class="oe_picture oe_screenshot" src="blog_create.png">
|
<img class="oe_picture oe_screenshot" src="blog_create.png">
|
||||||
|
@ -187,13 +187,13 @@
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<p class='oe_mt32'>
|
<p class='oe_mt32'>
|
||||||
Not everyone requires the same access to your website.
|
Not everyone requires the same access to your website.
|
||||||
Designers manage the layout of the site, editors approves content and
|
Designers manage the layout of the site, editors approve content and
|
||||||
authors write that content. This lets you organize your publishing
|
authors write that content. This lets you organize your publishing
|
||||||
process according to your needs.
|
process according to your needs.
|
||||||
</p><p>
|
</p><p>
|
||||||
Others access rights related to business objects (products, people,
|
Other access rights are related to business objects (products, people,
|
||||||
events, etc) directly follows OpenERP's standard access right allowing
|
events, etc) and directly following OpenERP's standard access rights
|
||||||
you to not have to configure them twice.
|
management, so you do not have to configure things twice.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -381,7 +381,7 @@
|
||||||
</div>
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//div[@id='snippet_options']" position="inside">
|
<xpath expr="//div[@id='snippet_options']" position="inside">
|
||||||
<div data-snippet-option-id='content'
|
<div data-snippet-option-id='country_events'
|
||||||
data-selector=".oe_country_events"
|
data-selector=".oe_country_events"
|
||||||
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
||||||
data-selector-children=".content"
|
data-selector-children=".content"
|
||||||
|
|
|
@ -7,15 +7,15 @@ from openerp.addons.web.http import request
|
||||||
class sale_order_line(osv.osv):
|
class sale_order_line(osv.osv):
|
||||||
_inherit = "sale.order.line"
|
_inherit = "sale.order.line"
|
||||||
|
|
||||||
def _recalculate_product_values(self, cr, uid, ids, product_id=0, context=None):
|
def _recalculate_product_values(self, cr, uid, ids, product_id=0, fiscal_position=False, context=None):
|
||||||
if not ids:
|
if not ids:
|
||||||
return super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product_id, context=context)
|
return super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product_id, fiscal_position=fiscal_position, context=context)
|
||||||
|
|
||||||
order_line = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
|
order_line = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
|
||||||
assert order_line.order_id.website_session_id == request.session['website_session_id']
|
assert order_line.order_id.website_session_id == request.session['website_session_id']
|
||||||
|
|
||||||
product = product_id and self.pool.get('product.product').browse(cr, uid, product_id, context=context) or order_line.product_id
|
product = product_id and self.pool.get('product.product').browse(cr, uid, product_id, context=context) or order_line.product_id
|
||||||
res = super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product.id, context=context)
|
res = super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product.id, fiscal_position=fiscal_position, context=context)
|
||||||
if product.event_type_id and order_line.event_ticket_id and order_line.event_ticket_id.price != product.lst_price:
|
if product.event_type_id and order_line.event_ticket_id and order_line.event_ticket_id.price != product.lst_price:
|
||||||
res.update({'price_unit': order_line.event_ticket_id.price})
|
res.update({'price_unit': order_line.event_ticket_id.price})
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,7 @@ class WebsiteForum(http.Controller):
|
||||||
values.update({
|
values.update({
|
||||||
'main_object': tag or forum,
|
'main_object': tag or forum,
|
||||||
'question_ids': question_ids,
|
'question_ids': question_ids,
|
||||||
|
'question_count': question_count,
|
||||||
'pager': pager,
|
'pager': pager,
|
||||||
'tag': tag,
|
'tag': tag,
|
||||||
'filters': filters,
|
'filters': filters,
|
||||||
|
@ -134,7 +135,7 @@ class WebsiteForum(http.Controller):
|
||||||
|
|
||||||
@http.route(['/forum/<model("forum.forum"):forum>/faq'], type='http', auth="public", website=True, multilang=True)
|
@http.route(['/forum/<model("forum.forum"):forum>/faq'], type='http', auth="public", website=True, multilang=True)
|
||||||
def forum_faq(self, forum, **post):
|
def forum_faq(self, forum, **post):
|
||||||
values = self._prepare_forum_values(forum=forum, searches=dict(), **post)
|
values = self._prepare_forum_values(forum=forum, searches=dict(), header={'is_guidelines': True}, **post)
|
||||||
return request.website.render("website_forum.faq", values)
|
return request.website.render("website_forum.faq", values)
|
||||||
|
|
||||||
@http.route('/forum/get_tags', type='http', auth="public", multilang=True, methods=['GET'], website=True)
|
@http.route('/forum/get_tags', type='http', auth="public", multilang=True, methods=['GET'], website=True)
|
||||||
|
@ -147,7 +148,7 @@ class WebsiteForum(http.Controller):
|
||||||
def tags(self, forum, page=1, **post):
|
def tags(self, forum, page=1, **post):
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
Tag = request.registry['forum.tag']
|
Tag = request.registry['forum.tag']
|
||||||
obj_ids = Tag.search(cr, uid, [('forum_id', '=', forum.id)], limit=None, context=context)
|
obj_ids = Tag.search(cr, uid, [('forum_id', '=', forum.id), ('posts_count', '>', 0)], limit=None, order='posts_count DESC', context=context)
|
||||||
tags = Tag.browse(cr, uid, obj_ids, context=context)
|
tags = Tag.browse(cr, uid, obj_ids, context=context)
|
||||||
values = self._prepare_forum_values(forum=forum, searches={'tags': True}, **post)
|
values = self._prepare_forum_values(forum=forum, searches={'tags': True}, **post)
|
||||||
values.update({
|
values.update({
|
||||||
|
@ -426,7 +427,7 @@ class WebsiteForum(http.Controller):
|
||||||
tag_count = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], count=True, context=context)
|
tag_count = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], count=True, context=context)
|
||||||
pager = request.website.pager(url="/forum/users", total=tag_count, page=page, step=step, scope=30)
|
pager = request.website.pager(url="/forum/users", total=tag_count, page=page, step=step, scope=30)
|
||||||
|
|
||||||
obj_ids = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], limit=step, offset=pager['offset'], context=context)
|
obj_ids = User.search(cr, SUPERUSER_ID, [('karma', '>', 1)], limit=step, offset=pager['offset'], order='karma DESC', context=context)
|
||||||
users = User.browse(cr, SUPERUSER_ID, obj_ids, context=context)
|
users = User.browse(cr, SUPERUSER_ID, obj_ids, context=context)
|
||||||
searches['users'] = 'True'
|
searches['users'] = 'True'
|
||||||
|
|
||||||
|
@ -590,12 +591,13 @@ class WebsiteForum(http.Controller):
|
||||||
|
|
||||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="public", multilang=True, website=True)
|
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="public", multilang=True, website=True)
|
||||||
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
|
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
|
||||||
values = {
|
body = comment.body
|
||||||
'content': comment.body,
|
|
||||||
}
|
|
||||||
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
|
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
|
||||||
question = post.parent_id if post.parent_id else post
|
question = post.parent_id if post.parent_id else post
|
||||||
return self.post_new(forum, question, **values)
|
for answer in question.child_ids:
|
||||||
|
if answer.create_uid.id == request.uid:
|
||||||
|
return self.post_comment(forum, answer, comment=html2plaintext(body))
|
||||||
|
return self.post_new(forum, question, content=body)
|
||||||
|
|
||||||
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", multilang=True, website=True)
|
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", multilang=True, website=True)
|
||||||
def convert_answer_to_comment(self, forum, post, **kwarg):
|
def convert_answer_to_comment(self, forum, post, **kwarg):
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
<field name="domain" eval="[('model', '=', 'forum.post'), ('subtype_id', 'in', [ref('website_forum.mt_answer_edit'), ref('website_forum.mt_question_edit')])]"/>
|
<field name="domain" eval="[('model', '=', 'forum.post'), ('subtype_id', 'in', [ref('website_forum.mt_answer_edit'), ref('website_forum.mt_question_edit')])]"/>
|
||||||
<field name="batch_mode">True</field>
|
<field name="batch_mode">True</field>
|
||||||
<field name="batch_distinctive_field" eval="ref('mail.field_mail_message_author_id')" />
|
<field name="batch_distinctive_field" eval="ref('mail.field_mail_message_author_id')" />
|
||||||
<field name="batch_user_expression">user.id</field>
|
<field name="batch_user_expression">user.partner_id.id</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="gamification.challenge" id="challenge_editor">
|
<record model="gamification.challenge" id="challenge_editor">
|
||||||
<field name="name">Editor</field>
|
<field name="name">Editor</field>
|
||||||
|
|
|
@ -13,10 +13,7 @@
|
||||||
<field name="sequence" type="int">35</field>
|
<field name="sequence" type="int">35</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="default_allow_auth_signup" model="ir.config_parameter">
|
<function model="ir.config_parameter" name="set_param" eval="('auth_signup.allow_uninvited', True)" />
|
||||||
<field name="key">auth_signup.allow_uninvited</field>
|
|
||||||
<field name="value" eval="True"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- JUMP TO FORUM AT INSTALL -->
|
<!-- JUMP TO FORUM AT INSTALL -->
|
||||||
<record id="action_open_forum" model="ir.actions.act_url">
|
<record id="action_open_forum" model="ir.actions.act_url">
|
||||||
|
|
|
@ -70,6 +70,7 @@ class Post(osv.Model):
|
||||||
_name = 'forum.post'
|
_name = 'forum.post'
|
||||||
_description = 'Forum Post'
|
_description = 'Forum Post'
|
||||||
_inherit = ['mail.thread', 'website.seo.metadata']
|
_inherit = ['mail.thread', 'website.seo.metadata']
|
||||||
|
_order = "is_correct DESC, vote_count DESC"
|
||||||
|
|
||||||
def _get_user_vote(self, cr, uid, ids, field_name, arg, context):
|
def _get_user_vote(self, cr, uid, ids, field_name, arg, context):
|
||||||
res = dict.fromkeys(ids, 0)
|
res = dict.fromkeys(ids, 0)
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
background-color: #cccccc;
|
background-color: #cccccc;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
|
.question .badge-active {
|
||||||
|
background-color: #428bca;
|
||||||
|
}
|
||||||
|
|
||||||
.oe_grey {
|
.oe_grey {
|
||||||
background-color: #eeeeee;
|
background-color: #eeeeee;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
.badge
|
.badge
|
||||||
background-color: #ccc
|
background-color: #ccc
|
||||||
margin-left: 4px
|
margin-left: 4px
|
||||||
|
.badge-active
|
||||||
|
background-color: #428bca
|
||||||
|
|
||||||
.oe_grey
|
.oe_grey
|
||||||
background-color: #eeeeee
|
background-color: #eeeeee
|
||||||
|
|
|
@ -92,7 +92,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<t t-raw="forum.description"/><br/>
|
<t t-raw="forum.description"/><br/>
|
||||||
<a t-attf-href="/forum/#{slug(forum)}/faq" class="fa fa-arrow-right"> Read Guidelines</a>
|
<a t-if="not header.get('is_guidelines')" t-attf-href="/forum/#{slug(forum)}/faq" class="fa fa-arrow-right"> Read Guidelines</a>
|
||||||
|
<a t-if="header.get('is_guidelines')" t-attf-href="/forum/#{slug(forum)}" class="fa fa-arrow-right"> Back to <span t-field="forum.name"/></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div t-if="header.get('question_data')">
|
<div t-if="header.get('question_data')">
|
||||||
|
@ -144,8 +145,11 @@
|
||||||
<span t-if="not question.active"><b> [Deleted]</b></span>
|
<span t-if="not question.active"><b> [Deleted]</b></span>
|
||||||
<span t-if="question.state == 'close'"><b> [Closed]</b></span>
|
<span t-if="question.state == 'close'"><b> [Closed]</b></span>
|
||||||
</div>
|
</div>
|
||||||
<t t-foreach="question.tag_ids" t-as="tag">
|
<t t-foreach="question.tag_ids" t-as="question_tag">
|
||||||
<a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="badge pull-right" t-field="tag.name"/>
|
<a t-attf-href="/forum/#{ slug(forum) }/tag/#{slug(question_tag)}/questions">
|
||||||
|
<span t-attf-class="pull-right badge #{tag and tag.name == question_tag.name and 'badge-active' ''}" t-field="question_tag.name"
|
||||||
|
style="margin-right: 4px;"/>
|
||||||
|
</a>
|
||||||
</t>
|
</t>
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
|
by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
|
||||||
|
@ -208,14 +212,14 @@
|
||||||
<template id="forum_index" name="Forum">
|
<template id="forum_index" name="Forum">
|
||||||
<t t-call="website_forum.header">
|
<t t-call="website_forum.header">
|
||||||
<h1 class="page-header mt0">
|
<h1 class="page-header mt0">
|
||||||
<t t-esc="len(question_ids)"/> <span>Questions</span>
|
<t t-esc="question_count"/> <span>Questions</span>
|
||||||
<t t-esc="search"/>
|
<t t-esc="search"/>
|
||||||
<small class="dropdown" t-if="filters in ('all', 'unanswered','followed', 'tag')">
|
<small class="dropdown" t-if="filters in ('all', 'unanswered','followed', 'tag')">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||||
<t t-if="filters == 'all'">All</t>
|
<t t-if="filters == 'all'">All</t>
|
||||||
<t t-if="filters == 'unanswered'">Unanswered</t>
|
<t t-if="filters == 'unanswered'">Unanswered</t>
|
||||||
<t t-if="filters == 'followed'">Followed</t>
|
<t t-if="filters == 'followed'">Followed</t>
|
||||||
<t t-if="filters == 'tag'">Tag</t>
|
<t t-if="tag"><span t-field="tag.name"/></t>
|
||||||
<t t-if="sorting == 'date'"> by activity date</t>
|
<t t-if="sorting == 'date'"> by activity date</t>
|
||||||
<t t-if="sorting == 'answered'"> by most answered</t>
|
<t t-if="sorting == 'answered'"> by most answered</t>
|
||||||
<t t-if="sorting == 'vote'"> by most voted</t>
|
<t t-if="sorting == 'vote'"> by most voted</t>
|
||||||
|
@ -332,12 +336,12 @@
|
||||||
users having a high karma can see closed questions to moderate
|
users having a high karma can see closed questions to moderate
|
||||||
them.
|
them.
|
||||||
</p>
|
</p>
|
||||||
<form t-attf-action="/forum/#{ slug(forum) }/question/#{slug(post)}/close" method="post" role="form" class="form-horizontal mt32 mb64">
|
<form t-attf-action="/forum/#{ slug(forum) }/question/#{slug(question)}/close" method="post" role="form" class="form-horizontal mt32 mb64">
|
||||||
<input name="post_id" t-att-value="question.id" type="hidden"/>
|
<input name="post_id" t-att-value="question.id" type="hidden"/>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label" for="reason">Question:</label>
|
<label class="col-md-3 control-label" for="reason">Question:</label>
|
||||||
<div class="col-md-8 mt8">
|
<div class="col-md-8 mt8">
|
||||||
<span t-field="post.name"/>
|
<span t-field="question.name"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -354,7 +358,7 @@
|
||||||
<div class="col-md-offset-3 col-md-8">
|
<div class="col-md-offset-3 col-md-8">
|
||||||
<button class="btn btn-primary">Close question</button>
|
<button class="btn btn-primary">Close question</button>
|
||||||
<span class="text-muted">or</span>
|
<span class="text-muted">or</span>
|
||||||
<a class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(post) }">back to question</a>
|
<a class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">back to question</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -451,7 +455,7 @@
|
||||||
<a class="text-muted fa fa-times" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/ask_for_close"> Close</a>
|
<a class="text-muted fa fa-times" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/ask_for_close"> Close</a>
|
||||||
</li>
|
</li>
|
||||||
<li t-if="question.state == 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
|
<li t-if="question.state == 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
|
||||||
<a class="text-muted fa fa-undo" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)/reopen">reopen</a>
|
<a class="text-muted fa fa-undo" t-attf-href="/forum/#{ slug(forum) }/question/#{slug(question)}/reopen"> Reopen</a>
|
||||||
</li>
|
</li>
|
||||||
<li t-if="(user.id == question.create_uid.id and can_edit_own) or can_edit_all">
|
<li t-if="(user.id == question.create_uid.id and can_edit_own) or can_edit_all">
|
||||||
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{ slug(forum) }/post/#{slug(question)}/edit"> Edit</a>
|
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{ slug(forum) }/post/#{slug(question)}/edit"> Edit</a>
|
||||||
|
@ -467,7 +471,7 @@
|
||||||
<div>
|
<div>
|
||||||
<span t-field="question.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
|
<span t-field="question.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
|
||||||
<div>
|
<div>
|
||||||
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ user.id }"
|
<a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
|
||||||
t-field="question.create_uid"
|
t-field="question.create_uid"
|
||||||
t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
|
t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
|
||||||
style="display: inline-block;"/>
|
style="display: inline-block;"/>
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>var partner_url = '<t t-raw="partner_url or ''"/>';</script>
|
<script>var partner_url = '<t t-raw="partner_url or ''"/>';</script>
|
||||||
<script src="http://maps.google.com/maps/api/js?sensor=false"></script>
|
<script src="//maps.google.com/maps/api/js?sensor=false"></script>
|
||||||
<script type="text/javascript" t-attf-src="/google_map/partners.json?partner_ids=#{ partner_ids }"></script>
|
<script type="text/javascript" t-attf-src="/google_map/partners.json?partner_ids=#{ partner_ids }"></script>
|
||||||
<script type="text/javascript" src="/website_google_map/static/src/js/markerclusterer_compiled.js"></script>
|
<script type="text/javascript" src="/website_google_map/static/src/js/markerclusterer_compiled.js"></script>
|
||||||
<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
|
<script src="//code.jquery.com/jquery-1.6.1.min.js"></script>
|
||||||
<script type="text/javascript" src="/website_google_map/static/src/js/google_map.js"></script>
|
<script type="text/javascript" src="/website_google_map/static/src/js/google_map.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
<data noupdate="1">
|
<data noupdate="1">
|
||||||
|
|
||||||
<record model="mail.group" id="group_all_employees">
|
<record model="mail.group" id="group_all_employees">
|
||||||
<field name="name">Newsletter</field>
|
<field name="name">Discussion Group</field>
|
||||||
<field name="public">public</field>
|
<field name="public">public</field>
|
||||||
<field name="description">Public Newsletter.</field>
|
<field name="description">Public Discussion Group</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -10,7 +10,7 @@
|
||||||
return website.prompt({
|
return website.prompt({
|
||||||
id: "editor_new_subscribe_button",
|
id: "editor_new_subscribe_button",
|
||||||
window_title: _t("Add a Subscribe Button"),
|
window_title: _t("Add a Subscribe Button"),
|
||||||
select: _t("Mailing List"),
|
select: _t("Discussion List"),
|
||||||
init: function (field) {
|
init: function (field) {
|
||||||
return website.session.model('mail.group')
|
return website.session.model('mail.group')
|
||||||
.call('name_search', ['', [['public','=','public']]], { context: website.get_context() });
|
.call('name_search', ['', [['public','=','public']]], { context: website.get_context() });
|
||||||
|
|
|
@ -499,8 +499,8 @@
|
||||||
<xpath expr="//div[@id='snippet_content']" position="inside">
|
<xpath expr="//div[@id='snippet_content']" position="inside">
|
||||||
<div>
|
<div>
|
||||||
<div class="oe_snippet_thumbnail">
|
<div class="oe_snippet_thumbnail">
|
||||||
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_button.png"/>
|
<img class="oe_snippet_thumbnail_img" src="/website_mail/static/src/img/blocks/button_group_subscribe.png"/>
|
||||||
<span class="oe_snippet_thumbnail_title">Subscribe Button</span>
|
<span class="oe_snippet_thumbnail_title">Discussion Group</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="oe_snippet_body input-group js_follow"
|
<div class="oe_snippet_body input-group js_follow"
|
||||||
|
@ -516,7 +516,7 @@
|
||||||
<a href="#" class="btn btn-default js_unfollow_btn">Unsubscribe</a>
|
<a href="#" class="btn btn-default js_unfollow_btn">Unsubscribe</a>
|
||||||
<a href="#" class="btn btn-primary js_follow_btn">Subscribe</a>
|
<a href="#" class="btn btn-primary js_follow_btn">Subscribe</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="alert alert-success hidden">thanks for your subscription!</div>
|
<div class="alert alert-success hidden">Thanks for your subscription!</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -529,7 +529,7 @@
|
||||||
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel"
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<a href="#" class="button js_mailing_list">Change mailing list</a>
|
<a href="#" class="button js_mailing_list">Change Discussion List</a>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
|
@ -406,14 +406,16 @@ class Ecommerce(http.Controller):
|
||||||
order.amount_total,
|
order.amount_total,
|
||||||
request.website._render("website_sale.total", {'website_sale_order': order})]
|
request.website._render("website_sale.total", {'website_sale_order': order})]
|
||||||
|
|
||||||
@http.route(['/shop/set_cart_json'], type='json', auth="public")
|
@http.route(['/shop/set_cart_json'], type='json', auth="public", website=True, multilang=True)
|
||||||
def set_cart_json(self, path=None, product_id=None, order_line_id=None, set_number=0, json=None):
|
def set_cart_json(self, path=None, product_id=None, order_line_id=None, set_number=0, json=None):
|
||||||
quantity = request.registry['website']._ecommerce_add_product_to_cart(request.cr, request.uid,
|
quantity = request.registry['website']._ecommerce_add_product_to_cart(request.cr, request.uid,
|
||||||
product_id=product_id, order_line_id=order_line_id, set_number=set_number,
|
product_id=product_id, order_line_id=order_line_id, set_number=set_number,
|
||||||
context=request.context)
|
context=request.context)
|
||||||
order = self.get_order()
|
order = self.get_order()
|
||||||
return [quantity,
|
return [quantity,
|
||||||
order.get_number_of_products()]
|
order.get_number_of_products(),
|
||||||
|
order.amount_total,
|
||||||
|
request.website._render("website_sale.total", {'website_sale_order': order})]
|
||||||
|
|
||||||
@http.route(['/shop/checkout'], type='http', auth="public", website=True, multilang=True)
|
@http.route(['/shop/checkout'], type='http', auth="public", website=True, multilang=True)
|
||||||
def checkout(self, **post):
|
def checkout(self, **post):
|
||||||
|
|
|
@ -33,7 +33,7 @@ class SaleOrder(osv.Model):
|
||||||
class SaleOrderLine(osv.Model):
|
class SaleOrderLine(osv.Model):
|
||||||
_inherit = "sale.order.line"
|
_inherit = "sale.order.line"
|
||||||
|
|
||||||
def _recalculate_product_values(self, cr, uid, ids, product_id=0, context=None):
|
def _recalculate_product_values(self, cr, uid, ids, product_id=0, fiscal_position=False, context=None):
|
||||||
# TDE FIXME: seems to be defined several times -> fix me ?
|
# TDE FIXME: seems to be defined several times -> fix me ?
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
@ -49,5 +49,6 @@ class SaleOrderLine(osv.Model):
|
||||||
pricelist=context.pop('pricelist'),
|
pricelist=context.pop('pricelist'),
|
||||||
product=product_id,
|
product=product_id,
|
||||||
partner_id=user_obj.browse(cr, SUPERUSER_ID, uid).partner_id.id,
|
partner_id=user_obj.browse(cr, SUPERUSER_ID, uid).partner_id.id,
|
||||||
|
fiscal_position=fiscal_position,
|
||||||
context=context
|
context=context
|
||||||
)['value']
|
)['value']
|
||||||
|
|
|
@ -111,7 +111,7 @@ class Website(orm.Model):
|
||||||
|
|
||||||
# change and record value
|
# change and record value
|
||||||
if quantity:
|
if quantity:
|
||||||
vals = order_line_obj._recalculate_product_values(cr, uid, order_line_ids, product_id, context=context)
|
vals = order_line_obj._recalculate_product_values(cr, uid, order_line_ids, product_id, fiscal_position=order.fiscal_position.id, context=context)
|
||||||
values.update(vals)
|
values.update(vals)
|
||||||
values['product_uom_qty'] = quantity
|
values['product_uom_qty'] = quantity
|
||||||
values['product_id'] = product_id
|
values['product_id'] = product_id
|
||||||
|
@ -119,12 +119,11 @@ class Website(orm.Model):
|
||||||
|
|
||||||
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
|
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
|
||||||
values['name'] = "%s: %s" % (product.name, product.variants) if product.variants else product.name
|
values['name'] = "%s: %s" % (product.name, product.variants) if product.variants else product.name
|
||||||
values['tax_id'] = [(6, 0, [tax.id for tax in product.taxes_id])]
|
if values.get('tax_id'):
|
||||||
if order_line_id:
|
values['tax_id'] = [(6, 0, values['tax_id'])]
|
||||||
order_line_obj.write(cr, SUPERUSER_ID, order_line_ids, values, context=context)
|
|
||||||
else:
|
order_obj.write(cr, SUPERUSER_ID, [order.id], {'order_line': [(1, order_line_id, values) if order_line_id else (0, 0, values)]}, context=context)
|
||||||
order_line_id = order_line_obj.create(cr, SUPERUSER_ID, values, context=context)
|
|
||||||
order_obj.write(cr, SUPERUSER_ID, [order.id], {'order_line': [(4, order_line_id)]}, context=context)
|
|
||||||
elif order_line_ids:
|
elif order_line_ids:
|
||||||
order_line_obj.unlink(cr, SUPERUSER_ID, order_line_ids, context=context)
|
order_line_obj.unlink(cr, SUPERUSER_ID, order_line_ids, context=context)
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
<section class="oe_container oe_dark">
|
<section class="oe_container oe_dark">
|
||||||
<div class="oe_row">
|
<div class="oe_row">
|
||||||
<h2 class="oe_slogan">Fine Tune Your Catalog</h2>
|
<h2 class="oe_slogan">Fine Tune Your Catalog</h2>
|
||||||
<h3 class="oe_slogan">Boost Sales by Emphasazing Best Products</h3>
|
<h3 class="oe_slogan">Boost Sales by Emphasizing Best Products</h3>
|
||||||
<div class="oe_span6">
|
<div class="oe_span6">
|
||||||
<p class='oe_mt32'>
|
<p class='oe_mt32'>
|
||||||
Get a full control on how you display your products in
|
Get a full control on how you display your products in
|
||||||
|
|
|
@ -20,18 +20,20 @@ $(document).ready(function () {
|
||||||
.fadeIn(600);
|
.fadeIn(600);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".oe_website_sale .oe_mycart input.js_quantity").change(function () {
|
$(".oe_website_sale .oe_mycart input.js_quantity").change(function (ev) {
|
||||||
var $input = $(this);
|
var $input = $(this);
|
||||||
|
var $link = $(ev.currentTarget);
|
||||||
var value = parseInt($input.val(), 10);
|
var value = parseInt($input.val(), 10);
|
||||||
if (isNaN(value)) value = 0;
|
if (isNaN(value)) value = 0;
|
||||||
openerp.jsonRpc("/shop/set_cart_json", 'call', {'order_line_id': $input.data('id'), 'set_number': value})
|
openerp.jsonRpc("/shop/set_cart_json", 'call', {'order_line_id': $input.data('id'), 'set_number': value})
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
if (!data) {
|
if (!data[0]) {
|
||||||
location.reload();
|
location.reload();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
set_my_cart_quantity(data[1]);
|
set_my_cart_quantity(data[1]);
|
||||||
$input.val(data[0]);
|
$link.parents(".input-group:first").find(".js_quantity").val(data[0]);
|
||||||
|
$('#mycart_total').replaceWith(data[3]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -82,10 +82,10 @@ class SaleOrder(orm.Model):
|
||||||
carrier_id = delivery_id
|
carrier_id = delivery_id
|
||||||
break
|
break
|
||||||
order.write({'carrier_id': carrier_id}, context=context)
|
order.write({'carrier_id': carrier_id}, context=context)
|
||||||
if carrier_id:
|
if carrier_id:
|
||||||
order.delivery_set(context=context)
|
order.delivery_set(context=context)
|
||||||
else:
|
else:
|
||||||
order._delivery_unset(context=context)
|
order._delivery_unset(context=context)
|
||||||
|
|
||||||
return bool(carrier_id)
|
return bool(carrier_id)
|
||||||
|
|
||||||
|
|
|
@ -17,4 +17,5 @@ class Website(orm.Model):
|
||||||
product_id=product_id, order_line_id=order_line_id, number=number, set_number=set_number,
|
product_id=product_id, order_line_id=order_line_id, number=number, set_number=set_number,
|
||||||
context=context)
|
context=context)
|
||||||
order = self.ecommerce_get_current_order(cr, uid, context=context)
|
order = self.ecommerce_get_current_order(cr, uid, context=context)
|
||||||
return self.pool['sale.order']._check_carrier_quotation(cr, uid, order, force_carrier_id=None, context=context) and quantity or None
|
self.pool['sale.order']._check_carrier_quotation(cr, uid, order, force_carrier_id=None, context=context) and quantity or None
|
||||||
|
return quantity
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_website_twitter_tweet_public,access of twitter snippet,website_twitter.model_website_twitter_tweet,,1,0,0,0
|
access_website_twitter_tweet_public,access of twitter snippet,website_twitter.model_website_twitter_tweet,,1,0,0,0
|
||||||
|
access_website_twitter_tweet_manage,manage tweets,website_twitter.model_website_twitter_tweet,base.group_website_publisher,1,1,1,1
|
||||||
|
|
|
Loading…
Reference in New Issue