[MERGE] forward port of branch saas-4 up to revid 9410 chs@openerp.com-20140507164207-kmme4tsrd4w1m7l1

bzr revid: chs@openerp.com-20140507170112-bjeltv2b0coy60am
This commit is contained in:
Christophe Simonis 2014-05-07 19:01:12 +02:00
commit b8089a1521
57 changed files with 318 additions and 223 deletions

View File

@ -409,7 +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)
return self.pool['report'].get_action(cr, uid, [], 'account.report_invoice', context=context) return self.pool['report'].get_action(cr, uid, ids, 'account.report_invoice', context=context)
def action_invoice_sent(self, cr, uid, ids, context=None): def action_invoice_sent(self, cr, uid, ids, context=None):
''' '''

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -652,12 +652,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 )
@ -678,33 +676,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,
@ -712,13 +713,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)
@ -728,6 +730,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
@ -735,8 +738,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':
@ -754,7 +757,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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,9 +22,11 @@
import time import time
from datetime import datetime 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_DATETIME_FORMAT 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):
@ -410,22 +412,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_current_sheet(self, cr, uid, employee_id, date=False, context=None): 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: if not date:
date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
# ending date with no time to avoid timesheet with early date_to
date_to = date[0:10]+' 00:00:00' att_tz = timezone(tz or 'utc')
# limit=1 because only one sheet possible for an employee between 2 dates
sheet_ids = self.pool.get('hr_timesheet_sheet.sheet').search(cr, uid, [ attendance_dt = datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT)
('date_to', '>=', date_to), ('date_from', '<=', date), att_tz_dt = pytz.utc.localize(attendance_dt)
('employee_id', '=', employee_id) att_tz_dt = att_tz_dt.astimezone(att_tz)
], limit=1, context=context) # 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 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):
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):
res[attendance.id] = self._get_current_sheet(cursor, user, attendance.employee_id.id, attendance.name, context=context) res[attendance.id] = self._get_current_sheet(
cursor, user, attendance.employee_id.id, attendance.name,
context=context)
return res return res
_columns = { _columns = {
@ -447,10 +483,13 @@ class hr_attendance(osv.osv):
sheet_id = context.get('sheet_id') or self._get_current_sheet(cr, uid, vals.get('employee_id'), vals.get('name'), 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: 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) 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 can not enter an attendance in a submitted timesheet. Ask your manager to reset it before adding attendance.')) raise osv.except_osv(_('Error!'), _('You can not enter an attendance in a submitted timesheet. Ask your manager to reset it before adding attendance.'))
elif ts.date_from > vals.get('name') or ts.date_to < vals.get('name'): elif ts.date_from > att_tz_date_str or ts.date_to < att_tz_date_str:
raise osv.except_osv(_('User Error!'), _('You can not enter an attendance date outside the current timesheet dates.')) raise osv.except_osv(_('User Error!'), _('You can not enter an attendance date outside the current timesheet dates.'))
return super(hr_attendance,self).create(cr, uid, vals, context=context) return super(hr_attendance,self).create(cr, uid, vals, context=context)
@ -619,4 +658,3 @@ class hr_employee(osv.osv):
'timesheet_count': fields.function(_timesheet_count, type='integer', string='Timesheets'), 'timesheet_count': fields.function(_timesheet_count, type='integer', string='Timesheets'),
} }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

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

View File

@ -238,6 +238,7 @@ class mail_mail(osv.Model):
if context is None: if context is None:
context = {} context = {}
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:
# TDE note: remove me when model_id field is present on mail.message - done here to avoid doing it multiple times in the sub method # TDE note: remove me when model_id field is present on mail.message - done here to avoid doing it multiple times in the sub method
@ -248,10 +249,15 @@ class mail_mail(osv.Model):
model = None model = None
if model: if model:
context['model_name'] = model.name context['model_name'] = model.name
# handle attachments
attachments = [] # load attachment binary data with a separate read(), as prefetching all
for attach in mail.attachment_ids: # `datas` (binary field) could bloat the browse cache, triggerring
attachments.append((attach.datas_fname, base64.b64decode(attach.datas))) # soft/hard mem limits with temporary data.
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:
@ -300,6 +306,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'})

View File

@ -433,14 +433,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

View File

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

View File

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

View File

@ -1162,8 +1162,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):

View File

@ -260,8 +260,14 @@ 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 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):
_('This report is not loaded into the database: %s.' % report_name) _('This report is not loaded into the database: %s.' % report_name)
) )
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

View File

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

View File

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

View File

@ -811,7 +811,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">
@ -945,7 +945,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">
@ -1072,7 +1072,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">
@ -1359,7 +1359,7 @@
<group string="Locations" groups="stock.group_locations"> <group string="Locations" groups="stock.group_locations">
<field name="location_id" domain="[('usage','&lt;&gt;','view')]"/> <field name="location_id" domain="[('usage','&lt;&gt;','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">

View File

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

View File

@ -2,6 +2,7 @@ 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_website_designer,1,1,1,1 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,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

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_website_public website website.model_website 1 0 0 0
3 access_website website website.model_website base.group_website_designer 1 1 1 1
4 access_website_menu access_website_menu model_website_menu 1 0 0 0
5 access_website_menu_designer Web Menu Manager model_website_menu base.group_website_designer 1 1 1 1
6 access_website web menu manager website.model_website base.group_website_designer 1 1 1 1
7 access_website_converter_test access_website_converter_test model_website_converter_test 1 1 1 1
8 access_website_converter_test_sub access_website_converter_test_sub model_website_converter_test_sub 1 1 1 1

View File

@ -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');

View File

@ -879,20 +879,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"));
} }

View File

@ -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({
@ -427,7 +428,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'
@ -591,12 +592,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):

View File

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

View File

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

View File

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

View File

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

View File

@ -94,7 +94,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')">
@ -146,8 +147,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 }"
@ -210,14 +214,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>
@ -334,12 +338,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">
@ -356,7 +360,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>
@ -453,7 +457,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>
@ -469,7 +473,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;"/>

View File

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

View File

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