[MERGE] Sync with trunk

bzr revid: tde@openerp.com-20140508123529-w91cb0e6ugzutqd1
This commit is contained in:
Thibault Delavallée 2014-05-08 14:35:29 +02:00
commit 400b194d60
122 changed files with 1510 additions and 1832 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.'
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):
'''

View File

@ -1040,7 +1040,7 @@ class account_move_line(osv.osv):
if opening_reconciliation:
obj_move_rec.write(cr, uid, unlink_ids, {'opening_reconciliation': False})
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)
return True

View File

@ -172,18 +172,15 @@ class res_partner(osv.osv):
return result
def _journal_item_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'journal_item_count': 0, 'contracts_count': 0 }), ids))
# the user may not have access rights
try:
for partner in self.browse(cr, uid, ids, context=context):
res[partner.id] = {
'journal_item_count': len(partner.journal_item_ids),
'contracts_count': len(partner.contract_ids)
}
except:
pass
return res
MoveLine = self.pool('account.move.line')
AnalyticAccount = self.pool('account.analytic.account')
return {
partner_id: {
'journal_item_count': MoveLine.search_count(cr, uid, [('partner_id', '=', partner_id)], context=context),
'contracts_count': AnalyticAccount.search_count(cr,uid, [('partner_id', '=', partner_id)], context=context)
}
for partner_id in ids
}
def has_something_to_reconcile(self, cr, uid, partner_id, context=None):
'''
@ -215,7 +212,6 @@ class res_partner(osv.osv):
'debit_limit': fields.float('Payable Limit'),
'total_invoiced': fields.function(_invoice_total, string="Total Invoiced", type='float'),
'contracts_count': fields.function(_journal_item_count, string="Contracts", type='integer', multi="invoice_journal"),
'journal_item_ids': fields.one2many('account.move.line', 'partner_id', 'Journal Items'),
'journal_item_count': fields.function(_journal_item_count, string="Journal Items", type="integer", multi="invoice_journal"),
'property_account_payable': fields.property(
type='many2one',

View File

@ -50,6 +50,6 @@ class account_analytic_balance(osv.osv_memory):
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:

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

View File

@ -49,6 +49,6 @@ class account_analytic_cost_ledger(osv.osv_memory):
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:

View File

@ -47,6 +47,6 @@ class account_analytic_inverted_balance(osv.osv_memory):
'form': data
}
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:

View File

@ -57,7 +57,7 @@ class account_analytic_journal_report(osv.osv_memory):
context2 = context.copy()
context2['active_model'] = 'account.analytic.journal'
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):
if context is None:

View File

@ -47,7 +47,6 @@
<tr>
<th>Description</th>
<th>Quantity</th>
<th groups="product.group_uom">Unit of measure</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">Taxes</th>
@ -57,8 +56,10 @@
<tbody class="invoice_tbody">
<tr t-foreach="o.invoice_line" t-as="l">
<td><span t-field="l.name"/></td>
<td><span t-field="l.quantity"/></td>
<td groups="product.group_uom"><span t-field="l.uos_id"/></td>
<td>
<span t-field="l.quantity"/>
<span t-field="l.uos_id" groups="product.group_uom"/>
</td>
<td class="text-right">
<span t-field="l.price_unit"/>
</td>
@ -100,7 +101,7 @@
</div>
<div class="row" t-if="o.tax_line">
<div class="col-xs-3">
<div class="col-xs-6">
<table class="table table-condensed">
<thead>
<tr>
@ -136,7 +137,7 @@
</p>
<p t-if="o.fiscal_position">
<strong>Fiscal Position:</strong>
<span t-field="o.fiscal_position.note"/>
<span t-field="o.fiscal_position"/>
</p>
</div>
</t>

View File

@ -89,6 +89,6 @@ class accounting_report(osv.osv_memory):
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])
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:

View File

@ -21,6 +21,7 @@
from openerp.osv import fields, osv
class account_balance_report(osv.osv_memory):
_inherit = "account.common.account.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):
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:

View File

@ -81,6 +81,6 @@ class account_aged_trial_balance(osv.osv_memory):
data['form'].update(res)
if data.get('form',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:

View File

@ -21,6 +21,7 @@
from openerp.osv import fields, osv
class account_central_journal(osv.osv_memory):
_name = '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):
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:

View File

@ -21,6 +21,7 @@
from openerp.osv import fields, osv
class account_general_journal(osv.osv_memory):
_inherit = "account.common.journal.report"
_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):
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:

View File

@ -59,6 +59,6 @@ class account_report_general_ledger(osv.osv_memory):
if data['form']['landscape'] is False:
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:

View File

@ -44,6 +44,6 @@ class account_partner_balance(osv.osv_memory):
context = {}
data = self.pre_print_report(cr, uid, ids, data, context=context)
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:

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['form'].update(self.read(cr, uid, ids, ['initial_balance', 'filter', 'page_split', 'amount_currency'])[0])
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, ids, 'account.report_partnerledger', 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, [], 'account.report_partnerledger', data=data, context=context)
# 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['form'].update(self.read(cr, uid, ids, ['sort_selection'], context=context)[0])
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:
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:

View File

@ -61,6 +61,6 @@ class account_vat_declaration(osv.osv_memory):
taxcode = taxcode_obj.browse(cr, uid, [taxcode_id], context=context)[0]
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:

View File

@ -652,12 +652,10 @@ class account_analytic_account(osv.osv):
'nodestroy': True,
}
def _prepare_invoice(self, cr, uid, contract, context=None):
def _prepare_invoice_data(self, cr, uid, contract, context=None):
context = context or {}
inv_obj = self.pool.get('account.invoice')
journal_obj = self.pool.get('account.journal')
fpos_obj = self.pool.get('account.fiscal.position')
if not contract.partner_id:
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:
currency_id = contract.company_id.currency_id.id
inv_data = {
'reference': contract.code or False,
invoice = {
'account_id': contract.partner_id.property_account_receivable.id,
'type': 'out_invoice',
'partner_id': contract.partner_id.id,
'currency_id': currency_id,
'journal_id': len(journal_ids) and journal_ids[0] or False,
'date_invoice': contract.recurring_next_date,
'origin': contract.name,
'origin': contract.code,
'fiscal_position': fpos and fpos.id,
'payment_term': partner_payment_term,
'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:
res = line.product_id
account_id = res.property_account_income.id
if not account_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
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,
'account_id': account_id,
'account_analytic_id': contract.id,
@ -712,13 +713,14 @@ class account_analytic_account(osv.osv):
'quantity': line.quantity,
'uos_id': line.uom_id.id or False,
'product_id': line.product_id.id or False,
'invoice_id' : invoice_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)
return invoice_id
def _prepare_invoice(self, cr, uid, contract, context=None):
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):
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):
context = context or {}
invoice_ids = []
current_date = time.strftime('%Y-%m-%d')
if 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')])
for contract in self.browse(cr, uid, contract_ids, context=context):
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")
interval = contract.recurring_interval
if contract.recurring_rule_type == 'daily':
@ -754,7 +757,7 @@ class account_analytic_account(osv.osv):
_logger.error(traceback.format_exc())
else:
raise
return True
return invoice_ids
class account_analytic_account_summary_user(osv.osv):
_name = "account_analytic_analysis.summary.user"

View File

@ -117,15 +117,12 @@ class sale_order_line(osv.osv):
class product_product(osv.Model):
_inherit = 'product.product'
def _rules_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for rule in self.browse(cr, uid, ids, context=context):
res[rule.id] = len(rule.rules_ids)
except:
pass
return res
Analytic = self.pool['account.analytic.default']
return {
product_id: Analytic.search_count(cr, uid, [('product_id', '=', product_id)], context=context)
for product_id in ids
}
_columns = {
'rules_ids': fields.one2many('account.analytic.default', 'product_id', 'Analytic Rules '),
'rules_count': fields.function(_rules_count, string='# Analytic Rules', type='integer'),
}

View File

@ -24,6 +24,7 @@ import time
from openerp.osv import fields, osv
from openerp.tools.translate import _
class account_crossovered_analytic(osv.osv_memory):
_name = "account.crossovered.analytic"
_description = "Print Crossovered Analytic"
@ -65,6 +66,6 @@ class account_crossovered_analytic(osv.osv_memory):
'model': 'account.analytic.account',
'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:

View File

@ -238,13 +238,11 @@ class account_asset_asset(osv.osv):
val['value_residual'] = purchase_value - salvage_value
return {'value': val}
def _entry_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for entry in self.browse(cr, uid, ids, context=context):
res[entry.id] = len(entry.account_move_line_ids)
except:
pass
return res
MoveLine = self.pool('account.move.line')
return {
asset_id: MoveLine.search_count(cr, uid, [('asset_id', '=', asset_id)], context=context)
for asset_id in ids
}
_columns = {
'account_move_line_ids': fields.one2many('account.move.line', 'asset_id', 'Entries', readonly=True, states={'draft':[('readonly',False)]}),
'entry_count': fields.function(_entry_count, string='# Asset Entries', type='integer'),

View File

@ -46,6 +46,6 @@ class account_budget_analytic(osv.osv_memory):
'form': data
}
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:

View File

@ -47,6 +47,6 @@ class account_budget_crossvered_report(osv.osv_memory):
}
datas['form']['ids'] = datas['ids']
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:

View File

@ -49,6 +49,6 @@ class account_budget_crossvered_summary_report(osv.osv_memory):
}
datas['form']['ids'] = datas['ids']
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:

View File

@ -47,6 +47,6 @@ class account_budget_report(osv.osv_memory):
}
datas['form']['ids'] = datas['ids']
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:

View File

@ -74,26 +74,17 @@ class account_voucher(osv.osv):
def print_check(self, cr, uid, ids, context=None):
if not ids:
return {}
raise osv.except_osv(_('Printing error'), _('No check selected '))
check_layout_report = {
'top' : 'account.print.check.top',
'middle' : 'account.print.check.middle',
'bottom' : 'account.print.check.bottom',
data = {
'id': ids and ids[0],
'ids': ids,
}
check_layout = self.browse(cr, uid, ids[0], context=context).company_id.check_layout
return {
'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
}
return self.pool['report'].get_action(
cr, uid, [], 'account_check_writing.report_check', data=data, context=context
)
def create(self, cr, uid, vals, context=None):
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 \

View File

@ -20,9 +20,9 @@
##############################################################################
from openerp.tools.translate import _
from openerp.osv import fields, osv
class account_check_write(osv.osv_memory):
_name = 'account.check.write'
_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})
#print the checks
check_layout_report = {
'top' : 'account.print.check.top',
'middle' : 'account.print.check.middle',
'bottom' : 'account.print.check.bottom',
data = {
'id': voucher_ids and voucher_ids[0],
'ids': voucher_ids,
}
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',
'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):
if context is None:

View File

@ -11,6 +11,7 @@
<field name="name" />
<field name="client_id" />
<field name="enabled" />
<field name="body" />
</group>
<group>
<field name="auth_endpoint" />

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2014-05-07 06:27+0000\n"
"X-Launchpad-Export-Date: 2014-05-08 05:38+0000\n"
"X-Generator: Launchpad (build 16996)\n"
"Language: zh_CN\n"

View File

@ -18,6 +18,7 @@
#
##############################################################################
import stock_picking
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -18,7 +18,7 @@
<div class="oe_right oe_button_box">
<button class="oe_inline oe_stat_button" type="action"
name="%(action_claim_from_delivery)d" icon="fa-comments" >
<field string="Claims" name="claim_count" widget="statinfo"/>
<field string="Claims" name="claim_count_out" widget="statinfo"/>
</button>
</div>
</xpath>

View File

@ -0,0 +1,30 @@
from openerp.osv import fields, osv
class stock_picking(osv.osv):
_inherit = 'stock.picking'
def _claim_count_out(self, cr, uid, ids, field_name, arg, context=None):
Claim = self.pool['crm.claim']
return {
id: Claim.search_count(cr, uid, [('ref', '=',('stock.picking.out,' + str(ids[0])))], context=context)
for id in ids
}
_columns = {
'claim_count_out': fields.function(_claim_count_out, string='Claims', type='integer'),
}
# Because of the way inheritance works in the ORM (bug), and the way stock.picking.out
# is defined (inherit from stock.picking, dispatch read to stock.picking), it is necessary
# to add the field claim_count_out to this class, even though the _claim_count_out method
# in stock_picking_out will not be called (but its existence will be checked).
class stock_picking_out(osv.osv):
_inherit = 'stock.picking.out'
def _claim_count_out(self, cr, uid, ids, field_name, arg, context=None):
return super(stock_picking_out, self)._claim_count_out(cr, uid, ids, field_name, arg, context=context)
_columns = {
'claim_count_out': fields.function(_claim_count_out, string='Claims', type='integer'),
}

View File

@ -216,13 +216,11 @@ class crm_lead(format_address, osv.osv):
res[lead.id][field] = abs(int(duration))
return res
def _meeting_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for meeting in self.browse(cr, uid, ids, context=context):
res[meeting.id] = len(meeting.meeting_ids)
except:
pass
return res
Event = self.pool['calendar.event']
return {
opp_id: Event.search_count(cr,uid, [('opportunity_id', '=', opp_id)], context=context)
for opp_id in ids
}
_columns = {
'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null', track_visibility='onchange',
select=True, help="Linked partner (optional). Usually created when converting the lead."),
@ -297,7 +295,6 @@ class crm_lead(format_address, osv.osv):
'payment_mode': fields.many2one('crm.payment.mode', 'Payment Mode', \
domain="[('section_id','=',section_id)]"),
'planned_cost': fields.float('Planned Costs'),
'meeting_ids': fields.one2many('calendar.event', 'opportunity_id', 'Opportunities'),
'meeting_count': fields.function(_meeting_count, string='# Meetings', type='integer'),
}

View File

@ -14,6 +14,7 @@
<record model="crm.case.stage" id="stage_lead2">
<field name="name">Dead</field>
<field name="case_default">1</field>
<field name="fold">1</field>
<field name="probability">0</field>
<field name="on_change">1</field>
<field name="sequence">30</field>

View File

@ -32,14 +32,6 @@ class crm_phonecall(osv.osv):
_order = "id desc"
_inherit = ['mail.thread']
def _meeting_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for meeting in self.browse(cr, uid, ids, context=context):
res[meeting.id] = len(meeting.meeting_ids)
except:
pass
return res
_columns = {
'date_action_last': fields.datetime('Last Action', readonly=1),
'date_action_next': fields.datetime('Next Action', readonly=1),
@ -74,8 +66,6 @@ class crm_phonecall(osv.osv):
'date_closed': fields.datetime('Closed', readonly=True),
'date': fields.datetime('Date'),
'opportunity_id': fields.many2one ('crm.lead', 'Lead/Opportunity'),
'meeting_ids': fields.one2many('calendar.event', 'phonecall_id', 'Phonecalls'),
'meeting_count': fields.function(_meeting_count, string='# Meetings', type='integer'),
}
def _get_default_state(self, cr, uid, context=None):

View File

@ -33,10 +33,11 @@ class res_partner(osv.osv):
res[partner.id] = {
'opportunity_count': len(partner.opportunity_ids),
'meeting_count': len(partner.meeting_ids),
'phonecall_count': len(partner.meeting_ids),
}
except:
pass
for partner in self.browse(cr, uid, ids, context):
res[partner.id]['phonecall_count'] = len(partner.phonecall_ids)
return res
_columns = {

View File

@ -88,7 +88,7 @@ Find duplicates, merge leads and assign them to the right salesperson in one ope
<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.
</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>
</div>
</div>

View File

@ -191,15 +191,13 @@ class crm_claim(osv.osv):
class res_partner(osv.osv):
_inherit = 'res.partner'
def _claim_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for partner in self.browse(cr, uid, ids, context=context):
res[partner.id] = len(partner.claims_ids)
except:
pass
return res
Claim = self.pool['crm.claim']
return {
partner_id: Claim.search_count(cr,uid, [('partner_id', '=', partner_id)], context=context)
for partner_id in ids
}
_columns = {
'claims_ids': fields.one2many('crm.claim', 'partner_id', 'Claims'),
'claim_count': fields.function(_claim_count, string='# Claims', type='integer'),
}

View File

@ -37,6 +37,9 @@ class product_template(osv.osv):
class product(osv.osv):
_inherit = 'product.product'
_columns = {
'event_ticket_ids': fields.one2many('event.event.ticket', 'product_id', 'Event Tickets'),
}
def onchange_event_ok(self, cr, uid, ids, type, event_ok, context=None):
# cannot directly forward to product.template as the ids are theoretically different

View File

@ -315,18 +315,21 @@ class fleet_vehicle(osv.Model):
return model_id
def _count_all(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'odometer_count': 0, 'fuel_logs_count': 0, 'service_count': 0, 'contract_count': 0, 'cost_count': 0,}), ids))
try:
for costs in self.browse(cr, uid, ids, context=context):
res[costs.id] = {'odometer_count': len(costs.odometer_ids),
'fuel_logs_count': len(costs.log_fuel),
'service_count': len(costs.log_services),
'contract_count': len(costs.log_contracts),
'cost_count': len(costs.costs_ids)
}
except:
pass
return res
Odometer = self.pool['fleet.vehicle.odometer']
LogFuel = self.pool['fleet.vehicle.log.fuel']
LogService = self.pool['fleet.vehicle.log.services']
LogContract = self.pool['fleet.vehicle.log.contract']
Cost = self.pool['fleet.vehicle.cost']
return {
vehicle_id: {
'odometer_count': Odometer.search_count(cr, uid, [('vehicle_id', '=', vehicle_id)], context=context),
'fuel_logs_count': LogFuel.search_count(cr, uid, [('vehicle_id', '=', vehicle_id)], context=context),
'service_count': LogService.search_count(cr, uid, [('vehicle_id', '=', vehicle_id)], context=context),
'contract_count': LogContract.search_count(cr, uid, [('vehicle_id', '=', vehicle_id)], context=context),
'cost_count': Cost.search_count(cr, uid, [('vehicle_id', '=', vehicle_id), ('parent_id', '=', False)], context=context)
}
for vehicle_id in ids
}
_name = 'fleet.vehicle'
_description = 'Information on a vehicle'
@ -341,8 +344,6 @@ class fleet_vehicle(osv.Model):
'log_fuel': fields.one2many('fleet.vehicle.log.fuel', 'vehicle_id', 'Fuel Logs'),
'log_services': fields.one2many('fleet.vehicle.log.services', 'vehicle_id', 'Services Logs'),
'log_contracts': fields.one2many('fleet.vehicle.log.contract', 'vehicle_id', 'Contracts'),
'costs_ids': fields.one2many('fleet.vehicle.cost', 'vehicle_id', 'Costs'),
'odometer_ids': fields.one2many('fleet.vehicle.odometer', 'vehicle_id', 'Odometer'),
'cost_count': fields.function(_count_all, type='integer', string="Costs" , multi=True),
'contract_count': fields.function(_count_all, type='integer', string='Contracts', multi=True),
'service_count': fields.function(_count_all, type='integer', string='Services', multi=True),

View File

@ -217,15 +217,7 @@ class gamification_challenge(osv.Model):
vals['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)
# 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
return super(gamification_challenge, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
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)
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':
self._recompute_challenge_users(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)
- Update every running challenge
"""
if context is None:
context = {}
# start scheduled challenges
planned_challenge_ids = self.search(cr, uid, [
('state', '=', 'draft'),
@ -281,6 +281,9 @@ class gamification_challenge(osv.Model):
if not ids:
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)
def _update_all(self, cr, uid, ids, context=None):
@ -355,11 +358,6 @@ class gamification_challenge(osv.Model):
if write_op:
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
@ -393,9 +391,9 @@ class gamification_challenge(osv.Model):
:param list(int) ids: the list of challenge concerned"""
goal_obj = self.pool.get('gamification.goal')
to_update = []
for challenge in self.browse(cr, uid, ids, context=context):
(start_date, end_date) = start_end_date_for_period(challenge.period)
to_update = []
# if no periodicity, use challenge dates
if not start_date and challenge.start_date:
@ -426,7 +424,15 @@ class gamification_challenge(osv.Model):
cr.execute(query, query_params)
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 = {
'definition_id': line.definition_id.id,
@ -614,9 +620,10 @@ class gamification_challenge(osv.Model):
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)
# send to every follower of the challenge
# send to every follower and participant of the challenge
self.message_post(cr, uid, challenge.id,
body=body_html,
partner_ids=[user.partner_id.id for user in challenge.user_ids],
context=context,
subtype='mail.mt_comment')
if challenge.report_message_group_id:
@ -698,34 +705,35 @@ class gamification_challenge(osv.Model):
rewarded_users = []
challenge_ended = end_date == yesterday.strftime(DF) or force
if challenge.reward_id and challenge_ended or challenge.reward_realtime:
for user in challenge.user_ids:
reached_goal_ids = self.pool.get('gamification.goal').search(cr, uid, [
('challenge_id', '=', challenge.id),
('user_id', '=', user.id),
('start_date', '=', start_date),
('end_date', '=', end_date),
('state', '=', 'reached')
], context=context)
if len(reached_goal_ids) == len(challenge.line_ids):
# not using start_date as intemportal goals have a start date but no end_date
reached_goals = self.pool.get('gamification.goal').read_group(cr, uid, [
('challenge_id', '=', challenge.id),
('end_date', '=', end_date),
('state', '=', 'reached')
], fields=['user_id'], groupby=['user_id'], context=context)
for reach_goals_user in reached_goals:
if reach_goals_user['user_id_count'] == len(challenge.line_ids):
# the user has succeeded every assigned goal
user_id = reach_goals_user['user_id'][0]
if challenge.reward_realtime:
badges = self.pool['gamification.badge.user'].search(cr, uid, [
('challenge_id', '=', challenge.id),
('badge_id', '=', challenge.reward_id.id),
('user_id', '=', user.id),
('user_id', '=', user_id),
], count=True, context=context)
if badges > 0:
# has already recieved the badge for this challenge
continue
self.reward_user(cr, uid, user.id, challenge.reward_id.id, challenge.id, context=context)
rewarded_users.append(user)
self.reward_user(cr, uid, user_id, challenge.reward_id.id, challenge.id, context=context)
rewarded_users.append(user_id)
if challenge_ended:
# open chatter message
message_body = _("The challenge %s is finished." % challenge.name)
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:
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)
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

View File

@ -138,7 +138,6 @@ class gamification_goal(osv.Model):
_name = 'gamification.goal'
_description = 'Gamification goal instance'
_inherit = 'mail.thread'
def _get_completion(self, cr, uid, ids, field_name, arg, context=None):
"""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')
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)
self.message_post(cr, uid, goal.id, body=body_html, partner_ids=[goal.user_id.partner_id.id], context=context, subtype='mail.mt_comment')
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')
return {'to_update': True}
return {}
@ -241,9 +239,9 @@ class gamification_goal(osv.Model):
the target value being reached, the goal is set as failed."""
if context is None:
context = {}
commit = context.get('commit_gamification', False)
goals_by_definition = {}
goals_to_write = {}
all_goals = {}
for goal in self.browse(cr, uid, ids, context=context):
if goal.state in ('draft', 'canceled'):
@ -251,10 +249,10 @@ class gamification_goal(osv.Model):
continue
goals_by_definition.setdefault(goal.definition_id, []).append(goal)
goals_to_write[goal.id] = {}
all_goals[goal.id] = goal
for definition, goals in goals_by_definition.items():
goals_to_write = dict((goal.id, {}) for goal in goals)
if definition.computation_mode == 'manually':
for goal in goals:
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:
goals_to_write[goal.id]['current'] = new_value
for goal_id, value in goals_to_write.items():
if not value:
continue
goal = all_goals[goal_id]
for goal_id, value in goals_to_write.items():
if not value:
continue
goal = all_goals[goal_id]
# check goal target reached
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):
value['state'] = 'reached'
# check goal target reached
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):
value['state'] = 'reached'
# check goal failure
elif goal.end_date and fields.date.today() > goal.end_date:
value['state'] = 'failed'
value['closed'] = True
if value:
self.write(cr, uid, [goal.id], value, context=context)
# check goal failure
elif goal.end_date and fields.date.today() > goal.end_date:
value['state'] = 'failed'
value['closed'] = True
if value:
self.write(cr, uid, [goal.id], value, context=context)
if commit:
cr.commit()
return True
def action_start(self, cr, uid, ids, context=None):

View File

@ -86,10 +86,6 @@
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>

View File

@ -248,7 +248,13 @@ class hr_employee(osv.osv):
'image': _get_default_image,
'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):
""" Broadcast the welcome message to all users in the employee company. """
employee = self.browse(cr, uid, employee_id, context=context)
@ -421,18 +427,23 @@ class hr_department(osv.osv):
res.append((record['id'], name))
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:
default = {}
default = default.copy()
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):
_name = '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 = {
'employee_ids': fields.one2many('hr.employee', 'user_id', 'Related employees'),
}

View File

@ -39,13 +39,11 @@ class hr_employee(osv.osv):
return res
def _contracts_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for employee in self.browse(cr, uid, ids, context=context):
res[employee.id] = len(employee.contract_ids)
except:
pass
return res
Contract = self.pool['hr.contract']
return {
employee_id: Contract.search_count(cr,uid, [('employee_id', '=', employee_id)], context=context)
for employee_id in ids
}
_columns = {
'manager': fields.boolean('Is a Manager'),

View File

@ -104,19 +104,15 @@ class hr_employee(osv.Model):
_inherit="hr.employee"
def _appraisal_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for employee in self.browse(cr, uid, ids, context=context):
res[employee.id] = len(employee.appraisal_ids)
except:
pass
return res
Evaluation = self.pool['hr.evaluation.interview']
return {
employee_id: Evaluation.search_count(cr, uid, [('user_to_review_id', '=', employee_id)], context=context)
for employee_id in ids
}
_columns = {
'evaluation_plan_id': fields.many2one('hr_evaluation.plan', 'Appraisal Plan'),
'evaluation_date': fields.date('Next Appraisal Date', help="The date of the next appraisal is computed by the appraisal plan's dates (first appraisal + periodicity)."),
'appraisal_ids': fields.one2many('hr.evaluation.interview', 'user_to_review_id', 'Appraisal Interviews'),
'appraisal_count': fields.function(_appraisal_count, type='integer', string='Appraisal Interviews'),
}

View File

@ -550,13 +550,11 @@ class hr_employee(osv.osv):
return result
def _leaves_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for employee in self.browse(cr, uid, ids, context=context):
res[employee.id] = len(employee.leave_ids)
except:
pass
return res
Holidays = self.pool['hr.holidays']
return {
employee_id: Holidays.search_count(cr,uid, [('employee_id', '=', employee_id)], context=context)
for employee_id in ids
}
_columns = {
'remaining_leaves': fields.function(_get_remaining_days, string='Remaining Legal Leaves', fnct_inv=_set_remaining_days, type="float", help='Total number of legal leaves allocated to this employee, change this value to create allocation/leave request. Total based on all the leave types without overriding limit.'),
@ -566,7 +564,6 @@ class hr_employee(osv.osv):
'current_leave_id': fields.function(_get_leave_status, multi="leave_status", string="Current Leave Type",type='many2one', relation='hr.holidays.status'),
'leave_date_from': fields.function(_get_leave_status, multi='leave_status', type='date', string='From Date'),
'leave_date_to': fields.function(_get_leave_status, multi='leave_status', type='date', string='To Date'),
'leave_ids': fields.one2many('hr.holidays', 'employee_id', 'Leaves'),
'leaves_count': fields.function(_leaves_count, type='integer', string='Leaves'),
}

View File

@ -261,11 +261,8 @@ class hr_payslip(osv.osv):
def _count_detail_payslip(self, cr, uid, ids, field_name, arg, context=None):
res = {}
try:
for details in self.browse(cr, uid, ids, context=context):
res[details.id] = len(details.line_ids)
except:
pass
for details in self.browse(cr, uid, ids, context=context):
res[details.id] = len(details.line_ids)
return res
_columns = {
@ -285,7 +282,6 @@ class hr_payslip(osv.osv):
\n* If the payslip is under verification, the status is \'Waiting\'. \
\n* If the payslip is confirmed then status is set to \'Done\'.\
\n* When user cancel payslip the status is \'Rejected\'.'),
# 'line_ids': fields.one2many('hr.payslip.line', 'slip_id', 'Payslip Line', required=False, readonly=True, states={'draft': [('readonly', False)]}),
'line_ids': one2many_mod2('hr.payslip.line', 'slip_id', 'Payslip Lines', readonly=True, states={'draft':[('readonly',False)]}),
'company_id': fields.many2one('res.company', 'Company', required=False, readonly=True, states={'draft': [('readonly', False)]}),
'worked_days_line_ids': fields.one2many('hr.payslip.worked_days', 'payslip_id', 'Payslip Worked Days', required=False, readonly=True, states={'draft': [('readonly', False)]}),
@ -983,19 +979,16 @@ class hr_employee(osv.osv):
return res
def _payslip_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for employee in self.browse(cr, uid, ids, context=context):
res[employee.id] = len(employee.payslip_ids)
except:
pass
return res
Payslip = self.pool['hr.payslip']
return {
employee_id: Payslip.search_count(cr,uid, [('employee_id', '=', employee_id)], context=context)
for employee_id in ids
}
_columns = {
'slip_ids':fields.one2many('hr.payslip', 'employee_id', 'Payslips', required=False, readonly=True),
'total_wage': fields.function(_calculate_total_wage, method=True, type='float', string='Total Basic Salary', digits_compute=dp.get_precision('Payroll'), help="Sum of all current contract's wage of employee."),
'payslip_count': fields.function(_payslip_count, type='integer', string='Payslips'),
'payslip_ids': fields.one2many('hr.payslip', 'employee_id', 'Payslips'),
}

View File

@ -514,15 +514,14 @@ class hr_job(osv.osv):
return res
def _count_all(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'documents_count': 0, 'application_count': 0,}), ids))
try:
for job in self.browse(cr, uid, ids, context=context):
res[job.id] = {'documents_count': len(job.document_ids),
'application_count': len(job.applicant_ids),
}
except:
pass
return res
Applicant = self.pool['hr.applicant']
return {
job_id: {
'application_count': Applicant.search_count(cr,uid, [('job_id', '=', job_id)], context=context),
'documents_count': len(self._get_attached_docs(cr, uid, [job_id], field_name, arg, context=context)[job_id])
}
for job_id in ids
}
_columns = {
'survey_id': fields.many2one('survey.survey', 'Interview Form', help="Choose an interview form for this job position and you will be able to print/answer this interview from all applicants who apply for this job"),

View File

@ -22,9 +22,11 @@
import time
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pytz import timezone
import pytz
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 _
class hr_timesheet_sheet(osv.osv):
@ -134,15 +136,15 @@ class hr_timesheet_sheet(osv.osv):
return hr_employee.attendance_action_change(cr, uid, employee_ids, context=context)
def _count_all(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'timesheet_activity_count': 0, 'attendance_count': 0,}), ids))
try:
for datas in self.browse(cr, uid, ids, context=context):
res[datas.id] = {'timesheet_activity_count': len(datas.timesheet_activity_ids),
'attendance_count': len(datas.attendances_ids),
}
except:
pass
return res
Timesheet = self.pool['hr.analytic.timesheet']
Attendance = self.pool['hr.attendance']
return {
sheet_id: {
'timesheet_activity_count': Timesheet.search_count(cr,uid, [('sheet_id','=', sheet_id)], context=context),
'attendance_count': Attendance.search_count(cr,uid, [('sheed_id', '=', sheet_id)], context=context)
}
for sheet_id in ids
}
_columns = {
'name': fields.char('Note', size=64, select=1,
@ -174,7 +176,6 @@ class hr_timesheet_sheet(osv.osv):
'account_ids': fields.one2many('hr_timesheet_sheet.sheet.account', 'sheet_id', 'Analytic accounts', readonly=True),
'company_id': fields.many2one('res.company', 'Company'),
'department_id':fields.many2one('hr.department','Department'),
'timesheet_activity_ids': fields.one2many('hr.analytic.timesheet', 'sheet_id', 'Timesheet Activities'),
'timesheet_activity_count': fields.function(_count_all, type='integer', string='Timesheet Activities', multi=True),
'attendance_count': fields.function(_count_all, type='integer', string="Attendances", multi=True),
}
@ -411,22 +412,56 @@ class hr_attendance(osv.osv):
attendance_ids.extend([row[0] for row in cr.fetchall()])
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:
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'
# 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, [
('date_to', '>=', date_to), ('date_from', '<=', date),
('employee_id', '=', employee_id)
], limit=1, context=context)
att_tz = timezone(tz or 'utc')
attendance_dt = datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT)
att_tz_dt = pytz.utc.localize(attendance_dt)
att_tz_dt = att_tz_dt.astimezone(att_tz)
# We take only the date omiting the hours as we compare with timesheet
# date_from which is a date format thus using hours would lead to
# be out of scope of timesheet
att_tz_date_str = datetime.strftime(att_tz_dt, DEFAULT_SERVER_DATE_FORMAT)
return att_tz_date_str
def _get_current_sheet(self, cr, uid, employee_id, date=False, context=None):
sheet_obj = self.pool['hr_timesheet_sheet.sheet']
if not date:
date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
att_tz_date_str = self._get_attendance_employee_tz(
cr, uid, employee_id,
date=date, context=context)
sheet_ids = sheet_obj.search(cr, uid,
[('date_from', '<=', att_tz_date_str),
('date_to', '>=', att_tz_date_str),
('employee_id', '=', employee_id)],
limit=1, context=context)
return sheet_ids and sheet_ids[0] or False
def _sheet(self, cursor, user, ids, name, args, context=None):
res = {}.fromkeys(ids, False)
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
_columns = {
@ -448,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)
if sheet_id:
att_tz_date_str = self._get_attendance_employee_tz(
cr, uid, vals.get('employee_id'),
date=vals.get('name'), context=context)
ts = self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, sheet_id, context=context)
if ts.state not in ('draft', 'new'):
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.'))
return super(hr_attendance,self).create(cr, uid, vals, context=context)
@ -610,17 +648,13 @@ class hr_employee(osv.osv):
_description = 'Employee'
def _timesheet_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for employee in self.browse(cr, uid, ids, context=context):
res[employee.id] = len(employee.timesheet_ids)
except:
pass
return res
Sheet = self.pool['hr_timesheet_sheet.sheet']
return {
employee_id: Sheet.search_count(cr,uid, [('employee_id', '=', employee_id)], context=context)
for employee_id in ids
}
_columns = {
'timesheet_ids': fields.one2many('hr_timesheet_sheet.sheet', 'employee_id', 'Timesheets'),
'timesheet_count': fields.function(_timesheet_count, type='integer', string='Timsheets'),
'timesheet_count': fields.function(_timesheet_count, type='integer', string='Timesheets'),
}
# 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.http import request
from openerp.addons.web.controllers.main import content_disposition
import mimetypes
class MailController(http.Controller):
@ -19,10 +20,11 @@ class MailController(http.Controller):
if res:
filecontent = base64.b64decode(res.get('base64'))
filename = res.get('filename')
content_type = mimetypes.guess_type(filename)
if filecontent and filename:
return request.make_response(
filecontent,
headers=[('Content-Type', 'application/octet-stream'),
headers=[('Content-Type', content_type[0] or 'application/octet-stream'),
('Content-Disposition', content_disposition(filename))])
return request.not_found()

View File

@ -238,6 +238,7 @@ class mail_mail(osv.Model):
if context is None:
context = {}
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):
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
@ -248,10 +249,15 @@ class mail_mail(osv.Model):
model = None
if model:
context['model_name'] = model.name
# handle attachments
attachments = []
for attach in mail.attachment_ids:
attachments.append((attach.datas_fname, base64.b64decode(attach.datas)))
# load attachment binary data with a separate read(), as prefetching all
# `datas` (binary field) could bloat the browse cache, triggerring
# 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
email_list = []
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
# see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1
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:
_logger.exception('failed sending mail.mail %s', mail.id)
mail.write({'state': 'exception'})

View File

@ -385,7 +385,7 @@ class mail_thread(osv.AbstractModel):
if not context.get('mail_notrack'):
tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=track_ctx)
if tracked_fields:
initial_values = {thread_id: dict((item, False) for item in tracked_fields)}
initial_values = {thread_id: dict.fromkeys(tracked_fields, False)}
self.message_track(cr, uid, [thread_id], tracked_fields, initial_values, context=track_ctx)
return thread_id
@ -398,25 +398,24 @@ class mail_thread(osv.AbstractModel):
track_ctx = dict(context)
if 'lang' not in track_ctx:
track_ctx['lang'] = self.pool.get('res.users').browse(cr, uid, uid, context=context).lang
tracked_fields = None
if not context.get('mail_notrack'):
tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=track_ctx)
else:
tracked_fields = []
if tracked_fields:
records = self.browse(cr, uid, ids, context=track_ctx)
initial_values = dict((this.id, dict((key, getattr(this, key)) for key in tracked_fields.keys())) for this in records)
initial_values = dict((record.id, dict((key, getattr(record, key)) for key in tracked_fields))
for record in records)
# Perform write, update followers
result = super(mail_thread, self).write(cr, uid, ids, values, context=context)
self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context, values=values)
if not context.get('mail_notrack'):
# Perform the tracking
tracked_fields = self._get_tracked_fields(cr, uid, values.keys(), context=context)
else:
tracked_fields = None
# Perform the tracking
if tracked_fields:
self.message_track(cr, uid, ids, tracked_fields, initial_values, context=track_ctx)
return result
def unlink(self, cr, uid, ids, context=None):
@ -434,14 +433,14 @@ class mail_thread(osv.AbstractModel):
fol_obj.unlink(cr, SUPERUSER_ID, fol_ids, context=context)
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
context = dict(context or {}, mail_notrack=True)
default = default or {}
default['message_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
@ -453,14 +452,15 @@ class mail_thread(osv.AbstractModel):
:return list: a list of (field_name, column_info obj), containing
always tracked fields and modified on_change fields
"""
lst = []
tracked_fields = []
for name, column_info in self._all_columns.items():
visibility = getattr(column_info.column, 'track_visibility', False)
if visibility == 'always' or (visibility == 'onchange' and name in updated_fields) or name in self._track:
lst.append(name)
if not lst:
return lst
return self.fields_get(cr, uid, lst, context=context)
tracked_fields.append(name)
if tracked_fields:
return self.fields_get(cr, uid, tracked_fields, context=context)
return {}
def message_track(self, cr, uid, ids, tracked_fields, initial_values, context=None):
@ -1871,4 +1871,4 @@ class mail_thread(osv.AbstractModel):
message_obj.write(cr, uid, msg_ids_comment, {"res_id" : new_res_id, "model" : new_model}, context=context)
message_obj.write(cr, uid, msg_ids_not_comment, {"res_id" : new_res_id, "model" : new_model, "subtype_id" : None}, context=context)
return True
return True

View File

@ -34,14 +34,14 @@ class project_configuration(osv.TransientModel):
}
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)
if not alias_domain:
alias_domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "mail.catchall.domain", default=None, context=context)
if alias_domain is None:
domain = self.pool.get("ir.config_parameter").get_param(cr, uid, "web.base.url", context=context)
try:
alias_domain = urlparse.urlsplit(domain).netloc.split(':')[0]
except Exception:
pass
return {'alias_domain': alias_domain}
return {'alias_domain': alias_domain or False}
def set_alias_domain(self, cr, uid, ids, context=None):
config_parameters = self.pool.get("ir.config_parameter")

View File

@ -187,7 +187,7 @@
</span>
</t>
</td>
<td><div class="oe_view_manager_view_search" t-opentag="true"/></td>
<td><div class="oe_view_manager_view_search"/></td>
</tr>
</tbody>
</table>

View File

@ -1111,24 +1111,22 @@ class mrp_production_product_line(osv.osv):
class product_product(osv.osv):
_inherit = "product.product"
def _bom_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'bom_count': 0, 'mo_count': 0, 'bom_strct':0}), ids))
try:
for bom in self.browse(cr, uid, ids, context=context):
res[bom.id] = {
'bom_count': len(bom.bom_ids),
'mo_count': len(bom.mo_ids),
'bom_strct':len(bom.bom_ids),
}
except:
pass
return res
def _bom_orders_count(self, cr, uid, ids, field_name, arg, context=None):
Bom = self.pool('mrp.bom')
Production = self.pool('mrp.production')
return {
product_id: {
'bom_count': Bom.search_count(cr, uid, [('product_id', '=', product_id), ('bom_id', '=', False)], context=context),
'mo_count': Production.search_count(cr,uid, [('product_id', '=', product_id)], context=context),
'bom_strct': Bom.search_count(cr, uid, [('product_id', '=', product_id), ('bom_id', '=', False)], context=context),
}
for product_id in ids
}
_columns = {
'bom_ids': fields.one2many('mrp.bom', 'product_id', 'Bill of Materials'),
'mo_ids': fields.one2many('mrp.production', 'product_id', 'Manufacturing Orders'),
'bom_count': fields.function(_bom_count, string='# Bill of Material', type='integer', multi="bom_count"),
'bom_strct': fields.function(_bom_count, string='# Bill of Material Structure', type='integer', multi="bom_count"),
'mo_count': fields.function(_bom_count, string='# Manufacturing Orders', type='integer', multi="bom_count"),
'bom_count': fields.function(_bom_orders_count, string='# Bill of Material', type='integer', multi="_bom_order_count"),
'bom_strct': fields.function(_bom_orders_count, string='# Bill of Material Structure', type='integer', multi="_bom_order_count"),
'mo_count': fields.function(_bom_orders_count, string='# Manufacturing Orders', type='integer', multi="_bom_order_count"),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -59,7 +59,7 @@
<record id="res_company_oerp_us" model="res.company">
<field name="partner_id" ref="res_partner_oerp_us"/>
<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>
</record>
<record id="res_company_oerp_be" model="res.company">
@ -400,7 +400,7 @@
</record>
<record id="project.project_project_3" model="project.project">
<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 id="project.project_project_4" model="project.project">
<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)
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.create_picking(cr, uid, ids, context=context)
return True
def action_cancel(self, cr, uid, ids, context=None):

View File

@ -615,15 +615,12 @@ class product_template(osv.osv):
class product_product(osv.osv):
_inherit="product.product"
def _orderpoint_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for orderpoint in self.browse(cr, uid, ids, context=context):
res[orderpoint.id] = len(orderpoint.orderpoint_ids)
except:
pass
return res
OrderPoints = self.pool('stock.warehouse.orderpoint')
return {
product_id: OrderPoints.search_count(cr, uid, [('product_id', '=', product_id)], context=context)
for product_id in ids
}
_columns = {
'orderpoint_ids': fields.one2many('stock.warehouse.orderpoint', 'product_id', 'Minimum Stock Rules'),
'orderpoint_count': fields.function(_orderpoint_count, string='# Orderpoints', type='integer'),
}

View File

@ -23,13 +23,11 @@ from openerp.osv import fields,osv
class res_partner(osv.osv):
def _task_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for partner in self.browse(cr, uid, ids, context):
res[partner.id] = len(partner.task_ids)
except:
pass
return res
Task = self.pool['project.task']
return {
partner_id: Task.search_count(cr,uid, [('partner_id', '=', partner_id)], context=context)
for partner_id in ids
}
""" Inherits partner and adds Tasks information in the partner form """
_inherit = 'res.partner'
@ -46,6 +44,4 @@ class res_partner(osv.osv):
return super(res_partner, self).copy(
cr, uid, record_id, default=default, context=context)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -474,10 +474,11 @@ class project(osv.Model):
return [('project.task', "Tasks"), ("project.issue", "Issues")]
def _issue_count(self, cr, uid, ids, field_name, arg, context=None):
res={}
for issues in self.browse(cr, uid, ids, context):
res[issues.id] = len(issues.issue_ids)
return res
Issue = self.pool['project.issue']
return {
project_id: Issue.search_count(cr,uid, [('project_id', '=', project_id), ('stage_id.fold', '=', False)], context=context)
for project_id in ids
}
_columns = {
'project_escalation_id': fields.many2one('project.project', 'Project Escalation',
help='If any issue is escalated from the current Project, it will be listed under the project selected here.',
@ -554,18 +555,15 @@ class project_project(osv.Model):
class res_partner(osv.osv):
def _issue_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for partner in self.browse(cr, uid, ids, context=context):
res[partner.id] = len(partner.issue_ids)
except:
pass
return res
Issue = self.pool['project.issue']
return {
partner_id: Issue.search_count(cr,uid, [('partner_id', '=', partner_id)])
for partner_id in ids
}
""" Inherits partner and adds Issue information in the partner form """
_inherit = 'res.partner'
_columns = {
'issue_ids': fields.one2many('project.issue', 'partner_id', 'Issues'),
'issue_count': fields.function(_issue_count, string='# Issues', type='integer'),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -25,22 +25,16 @@ class res_partner(osv.osv):
_name = 'res.partner'
_inherit = 'res.partner'
def _purchase_order_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'purchase_order_count': 0, 'supplier_invoice_count': 0}), ids))
invoice_ids = self.pool.get('account.invoice').search(cr,uid, [('type', '=', 'in_invoice'), ('partner_id', '=', ids[0])])
for partner in self.browse(cr, uid, ids, context=context):
res[partner.id] = {
'purchase_order_count': len(partner.purchase_order_ids),
'supplier_invoice_count': len(invoice_ids),
}
return res
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
default.update({'purchase_order_ids': []})
return super(res_partner, self).copy(cr, uid, id, default=default, context=context)
def _purchase_invoice_count(self, cr, uid, ids, field_name, arg, context=None):
PurchaseOrder = self.pool['purchase.order']
Invoice = self.pool['account.invoice']
return {
partner_id: {
'purchase_order_count': PurchaseOrder.search_count(cr,uid, [('partner_id', '=', partner_id)], context=context),
'supplier_invoice_count': Invoice.search_count(cr,uid, [('partner_id', '=', partner_id), ('type','=','in_invoice')], context=context)
}
for partner_id in ids
}
def _commercial_fields(self, cr, uid, context=None):
return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['property_product_pricelist_purchase']
@ -52,13 +46,9 @@ class res_partner(osv.osv):
domain=[('type','=','purchase')],
string="Purchase Pricelist",
help="This pricelist will be used, instead of the default one, for purchases from the current partner"),
'purchase_order_count': fields.function(_purchase_order_count, string='# of Purchase Order', type='integer', multi="count"),
'purchase_order_ids': fields.one2many('purchase.order','partner_id','Purchase Order'),
'invoice_ids': fields.one2many('account.invoice','partner_id','Supplier Invoices'),
'supplier_invoice_count': fields.function(_purchase_order_count, string='# Supplier Invoices', type='integer', multi="count"),
'purchase_order_count': fields.function(_purchase_invoice_count, string='# of Purchase Order', type='integer', multi="count"),
'supplier_invoice_count': fields.function(_purchase_invoice_count, string='# Supplier Invoices', type='integer', multi="count"),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -148,15 +148,13 @@ class purchase_order(osv.osv):
return res and res[0] or False
def _count_all(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,{'shipment_count': 0, 'invoice_count': 0,}), ids))
try:
for data in self.browse(cr, uid, ids, context=context):
res[data.id] = {'shipment_count': len(data.picking_ids),
'invoice_count': len(data.invoice_ids),
}
except:
pass
return res
return {
purchase.id: {
'shipment_count': len(purchase.picking_ids),
'invoice_count': len(purchase.invoice_ids),
}
for purchase in self.browse(cr, uid, ids, context=context)
}
STATE_SELECTION = [
('draft', 'Draft PO'),
@ -1296,15 +1294,13 @@ class product_product(osv.Model):
_inherit = 'product.product'
def _purchase_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for purchase in self.browse(cr, uid, ids, context=context):
res[purchase.id] = len(purchase.purchase_ids)
except:
pass
return res
Purchase = self.pool['purchase.order']
return {
product_id: Purchase.search_count(cr,uid, [('order_line.product_id', '=', product_id)], context=context)
for product_id in ids
}
_columns = {
'purchase_ids': fields.one2many('purchase.order', 'product_id', 'Purchases'),
'purchase_count': fields.function(_purchase_count, string='# Purchases', type='integer'),
}

View File

@ -260,8 +260,14 @@ class Report(osv.Model):
def get_action(self, cr, uid, ids, report_name, data=None, context=None):
"""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
"""
if ids:
if not isinstance(ids, list):
ids = [ids]
context['active_ids'] = ids
report_obj = self.pool['ir.actions.report.xml']
idreport = report_obj.search(cr, uid, [('report_name', '=', report_name)], context=context)
try:
@ -272,7 +278,7 @@ class Report(osv.Model):
_('This report is not loaded into the database: %s.' % report_name)
)
action = {
return {
'context': context,
'data': data,
'type': 'ir.actions.report.xml',
@ -280,7 +286,6 @@ class Report(osv.Model):
'report_type': report.report_type,
'report_file': report.report_file,
}
return action
#--------------------------------------------------------------------------
# Report generation helpers

View File

@ -626,6 +626,48 @@ class sale_order(osv.osv):
def action_done(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
def onchange_fiscal_position(self, cr, uid, ids, fiscal_position, order_lines, context=None):
'''Update taxes of order lines for each line where a product is defined
:param list ids: not used
:param int fiscal_position: sale order fiscal position
:param list order_lines: command list for one2many write method
'''
order_line = []
fiscal_obj = self.pool.get('account.fiscal.position')
product_obj = self.pool.get('product.product')
line_obj = self.pool.get('sale.order.line')
fpos = False
if fiscal_position:
fpos = fiscal_obj.browse(cr, uid, fiscal_position, context=context)
for line in order_lines:
# create (0, 0, { fields })
# update (1, ID, { fields })
if line[0] in [0, 1]:
prod = None
if line[2].get('product_id'):
prod = product_obj.browse(cr, uid, line[2]['product_id'], context=context)
elif line[1]:
prod = line_obj.browse(cr, uid, line[1], context=context).product_id
if prod and prod.taxes_id:
line[2]['tax_id'] = [[6, 0, fiscal_obj.map_tax(cr, uid, fpos, prod.taxes_id)]]
order_line.append(line)
# link (4, ID)
# link all (6, 0, IDS)
elif line[0] in [4, 6]:
line_ids = line[0] == 4 and [line[1]] or line[2]
for line_id in line_ids:
prod = line_obj.browse(cr, uid, line_id, context=context).product_id
if prod and prod.taxes_id:
order_line.append([1, line_id, {'tax_id': [[6, 0, fiscal_obj.map_tax(cr, uid, fpos, prod.taxes_id)]]}])
else:
order_line.append([4, line_id])
else:
order_line.append(line)
return {'value': {'order_line': order_line}}
# TODO add a field price_unit_uos
@ -862,15 +904,15 @@ class sale_order_line(osv.osv):
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
context = context or {}
lang = lang or context.get('lang',False)
if not partner_id:
if not partner_id:
raise osv.except_osv(_('No Customer Defined!'), _('Before choosing a product,\n select a customer in the sales form.'))
warning = {}
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product')
context = {'lang': lang, 'partner_id': partner_id}
if partner_id:
lang = partner_obj.browse(cr, uid, partner_id).lang
partner = partner_obj.browse(cr, uid, partner_id)
lang = partner.lang
context_partner = {'lang': lang, 'partner_id': partner_id}
if not product:
@ -896,7 +938,12 @@ class sale_order_line(osv.osv):
uos = False
else:
uos = False
fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False
fpos = False
if not fiscal_position:
fpos = partner.property_account_position or False
else:
fpos = self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position)
if update_tax: #The quantity only have changed
result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id)
@ -1027,15 +1074,12 @@ class account_invoice(osv.Model):
class product_product(osv.Model):
_inherit = 'product.product'
def _sales_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for sale in self.browse(cr, uid, ids, context=context):
res[sale.id] = len(sale.sales_ids)
except:
pass
return res
SaleOrderLine = self.pool['sale.order.line']
return {
product_id: SaleOrderLine.search_count(cr,uid, [('product_id', '=', product_id)], context=context)
for product_id in ids
}
_columns = {
'sales_ids': fields.one2many('sale.order.line', 'product_id', 'Sales '),
'sales_count': fields.function(_sales_count, string='# Sales', type='integer'),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -206,7 +206,8 @@
</group>
<group name="sale_pay">
<field name="payment_term" options="{'no_create': True}"/>
<field name="fiscal_position" options="{'no_create': True}"/>
<field name="fiscal_position" options="{'no_create': True}"
on_change="onchange_fiscal_position(fiscal_position, order_line, context)"/>
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
</group>
<group>

View File

@ -105,7 +105,9 @@ class product_product(osv.osv):
'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
if not diff: raise osv.except_osv(_('Error!'), _("No difference between standard price and new price!"))
if qty:
@ -353,13 +355,11 @@ class product_product(osv.osv):
res[id][f] = stock.get(id, 0.0)
return res
def _move_count(self, cr, uid, ids, field_name, arg, context=None):
res = dict(map(lambda x: (x,0), ids))
try:
for move in self.browse(cr, uid, ids, context=context):
res[move.id] = len(move.move_ids)
except:
pass
return res
Move = self.pool['stock.move']
return {
product_id: Move.search_count(cr, uid, [('product_id', '=', product_id)], context=context)
for product_id in ids
}
_columns = {
'reception_count': fields.function(_stock_move_count, string="Reception", type='integer', multi='pickings'),
'delivery_count': fields.function(_stock_move_count, string="Delivery", type='integer', multi='pickings'),
@ -420,7 +420,6 @@ class product_product(osv.osv):
help="If real-time valuation is enabled for a product, the system will automatically write journal entries corresponding to stock moves." \
"The inventory variation account set on the product category will represent the current inventory value, and the stock input and stock output account will hold the counterpart moves for incoming and outgoing products."
, required=True),
'move_ids': fields.one2many('stock.move', 'product_id', 'Moves'),
'move_count': fields.function(_move_count, string='# Moves', type='integer'),
}

View File

@ -636,11 +636,7 @@ class stock_picking(osv.osv):
vals['name'] = self.pool.get('ir.sequence').get(cr, user, seq_obj_name)
new_id = super(stock_picking, self).create(cr, user, vals, context)
return new_id
def _claim_count(self, cr, uid, ids, field_name, arg, context=None):
res = {}
claim = self.pool.get('crm.claim').search(cr, uid, [('ref', '=',('stock.picking.out,' + str(ids[0])))], context=context)
res[ids[0]] = len(claim)
return res
_columns = {
'name': fields.char('Reference', size=64, select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'origin': fields.char('Source Document', size=64, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="Reference of the document", select=True),
@ -684,7 +680,6 @@ class stock_picking(osv.osv):
("none", "Not Applicable")], "Invoice Control",
select=True, required=True, readonly=True, track_visibility='onchange', states={'draft': [('readonly', False)]}),
'company_id': fields.many2one('res.company', 'Company', required=True, select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'claim_count': fields.function(_claim_count, string='Claims', type='integer'),
}
_defaults = {
'name': lambda self, cr, uid, context: '/',
@ -2312,7 +2307,9 @@ class stock_move(osv.osv):
# if product is set to average price and a specific value was entered in the picking wizard,
# 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_currency_id = move.price_currency_id.id or reference_currency_id
@ -3136,8 +3133,6 @@ class stock_picking_out(osv.osv):
out_defaults = super(stock_picking_out, self).default_get(cr, uid, fields_list, context=context)
defaults.update(out_defaults)
return defaults
def _claim_count(self, cr, uid, ids, field_name, arg, context=None):
return super(stock_picking_out, self)._claim_count(cr, uid, ids, field_name, arg, context=context)
_columns = {
'backorder_id': fields.many2one('stock.picking.out', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
@ -3155,7 +3150,6 @@ class stock_picking_out(osv.osv):
* Ready to Deliver: products reserved, simply waiting for confirmation.\n
* Delivered: has been processed, can't be modified or cancelled anymore\n
* Cancelled: has been cancelled, can't be confirmed anymore"""),
'claim_count': fields.function(_claim_count, string='Claims', type='integer'),
}
_defaults = {
'type': 'out',

View File

@ -811,7 +811,7 @@
</group>
<notebook>
<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"/>
</page>
<page string="Additional Info">
@ -945,7 +945,7 @@
<field name="partner_id" on_change="onchange_partner_in(partner_id)" string="Customer" domain="[('customer','=',True)]" />
</xpath>
<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 expr="/form/sheet" position="after">
<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}"/>
</xpath>
<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 expr="/form/sheet" position="after">
<div class="oe_chatter">
@ -1359,7 +1359,7 @@
<group string="Locations" groups="stock.group_locations">
<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 groups="stock.group_tracking_lot" string="Traceability">

View File

@ -62,14 +62,14 @@ class sale_order(osv.osv):
message = False
partner = self.pool.get('res.partner').browse(cr, uid, part, context=context)
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
message = partner.sale_warn_msg
warning = {
'title': title,
'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)
@ -90,14 +90,15 @@ class purchase_order(osv.osv):
message = False
partner = self.pool.get('res.partner').browse(cr, uid, part)
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
message = partner.purchase_warn_msg
warning = {
'title': title,
'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)
if result.get('warning',False):
@ -123,15 +124,16 @@ class account_invoice(osv.osv):
message = False
partner = self.pool.get('res.partner').browse(cr, uid, partner_id)
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
message = partner.invoice_warn_msg
warning = {
'title': title,
'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,
date_invoice=date_invoice, payment_term=payment_term,
partner_bank_id=partner_bank_id, company_id=company_id)
@ -154,14 +156,15 @@ class stock_picking(osv.osv):
title = False
message = False
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
message = partner.picking_warn_msg
warning = {
'title': title,
'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)
if result.get('warning',False):
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
@ -183,14 +186,15 @@ class stock_picking_in(osv.osv):
title = False
message = False
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
message = partner.picking_warn_msg
warning = {
'title': title,
'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)
if result.get('warning',False):
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
@ -209,14 +213,15 @@ class stock_picking_out(osv.osv):
title = False
message = False
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
message = partner.picking_warn_msg
warning = {
'title': title,
'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)
if result.get('warning',False):
warning['title'] = title and title +' & '+ result['warning']['title'] or result['warning']['title']
@ -256,12 +261,12 @@ class sale_order_line(osv.osv):
message = False
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
message = product_info.sale_line_warn_msg
warning['title'] = title
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,
uom, qty_uos, uos, name, partner_id,
@ -288,12 +293,12 @@ class purchase_order_line(osv.osv):
message = False
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
message = product_info.purchase_line_warn_msg
warning['title'] = title
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,
partner_id, date_order, fiscal_position_id)

View File

@ -12,7 +12,7 @@ OpenERP Website CMS
'depends': ['web', 'share', 'mail'],
'installable': True,
'data': [
'data/website_data.xml',
'data/data.xml',
'security/ir.model.access.csv',
'security/ir_ui_view.xml',
'views/website_templates.xml',
@ -23,7 +23,7 @@ OpenERP Website CMS
'views/ir_actions.xml',
],
'demo': [
'data/website_demo.xml',
'data/demo.xml',
],
'qweb': ['static/src/xml/website.backend.xml'],
'application': True,

View File

@ -32,6 +32,13 @@ class ir_http(orm.AbstractModel):
page=PageConverter,
)
def _auth_method_public(self):
# TODO: select user_id from matching website
if not request.session.uid:
request.uid = self.pool['ir.model.data'].xmlid_to_res_id(request.cr, openerp.SUPERUSER_ID, 'base.public_user')
else:
request.uid = request.session.uid
def _dispatch(self):
first_pass = not hasattr(request, 'website')
request.website = None
@ -54,7 +61,6 @@ class ir_http(orm.AbstractModel):
if first_pass:
request.lang = request.website.default_lang_code
request.context['lang'] = request.lang
request.website.preprocess_request(request)
if not func:
path = request.httprequest.path.split('/')
langs = [lg[0] for lg in request.website.get_languages()]

View File

@ -109,10 +109,6 @@ class website(osv.osv):
menu = menus and menus[0] or False
return dict( map(lambda x: (x, menu), ids) )
def _get_public_user(self, cr, uid, ids, name='public_user', arg=(), context=None):
ref = self.get_public_user(cr, uid, context=context)
return dict( map(lambda x: (x, ref), ids) )
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
_description = "Website"
_columns = {
@ -129,13 +125,17 @@ class website(osv.osv):
'social_googleplus': fields.char('Google+ Account'),
'google_analytics_key': fields.char('Google Analytics Key'),
'user_id': fields.many2one('res.users', string='Public User'),
'public_user': fields.function(_get_public_user, relation='res.users', type='many2one', string='Public User'),
'partner_id': fields.related('user_id','partner_id', type='many2one', relation='res.partner', string='Public Partner'),
'menu_id': fields.function(_get_menu, relation='website.menu', type='many2one', string='Main Menu',
store= {
'website.menu': (_get_menu_website, ['sequence','parent_id','website_id'], 10)
})
}
_defaults = {
'company_id': lambda self,cr,uid,c: self.pool['ir.model.data'].xmlid_to_res_id(cr, openerp.SUPERUSER_ID, 'base.public_user'),
}
# cf. Wizard hack in website_views.xml
def noop(self, *args, **kwargs):
pass
@ -186,11 +186,6 @@ class website(osv.osv):
except:
return False
def get_public_user(self, cr, uid, context=None):
uid = openerp.SUPERUSER_ID
res = self.pool['ir.model.data'].get_object_reference(cr, uid, 'base', 'public_user')
return res and res[1] or False
@openerp.tools.ormcache(skiparg=3)
def _get_languages(self, cr, uid, id, context=None):
website = self.browse(cr, uid, id)
@ -203,9 +198,6 @@ class website(osv.osv):
# TODO: Select website, currently hard coded
return self.pool['website'].browse(cr, uid, 1, context=context)
def preprocess_request(self, cr, uid, ids, request, context=None):
pass
def is_publisher(self, cr, uid, ids, context=None):
Access = self.pool['ir.model.access']
is_website_publisher = Access.check(cr, uid, 'ir.ui.view', 'write', False, context)
@ -342,7 +334,7 @@ class website(osv.osv):
"""
router = request.httprequest.app.get_db_router(request.db)
# Force enumeration to be performed as public user
uid = self.get_public_user(cr, uid, context=context)
uid = request.website.user_id.id
url_list = []
for rule in router.iter_rules():
if not self.rule_is_enumerable(rule):

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,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_designer,Web Menu Manager,model_website_menu,base.group_website_designer,1,1,1,1
access_website,web menu manager,website.model_website,base.group_website_designer,1,1,1,1
access_website_converter_test,access_website_converter_test,model_website_converter_test,,1,1,1,1
access_website_converter_test_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");
},
cancel: function () {
this.trigger("cancel");
},
close: function () {
this.$el.modal('hide');

View File

@ -879,20 +879,29 @@
this._super(np);
if (np.$next) {
if (np.$next.hasClass("oe_custom_bg")) {
var editor = new website.editor.ImageDialog();
editor.on('start', self, function (o) {o.url = np.$prev && np.$prev.data("src") || np.$next && np.$next.data("src") || "";});
editor.on('save', self, function (o) {
self._set_bg(o.url);
np.$next.data("src", o.url);
var $image = $('<img class="hidden"/>');
$image.attr("src", np.$prev ? np.$prev.data("src") : '');
$image.appendTo(self.$target);
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]);
$image.remove();
});
editor.on('cancel', self, function () {
if (!np.$prev || np.$prev.data("src") === "") {
self.$target.removeClass(np.$next.data("value"));
self.$target.trigger("snippet-style-change", [self, np]);
}
$image.remove();
});
editor.appendTo($('body'));
} else {
this._set_bg(np.$next.data("src"));
}

View File

@ -104,11 +104,11 @@ var T = website.Tour = {
if (tour.path && !window.location.href.match(new RegExp("("+T.getLang()+")?"+tour.path+"#?$", "i"))) {
var href = "/"+T.getLang()+tour.path;
console.log("Tour Begin from run method (redirection to "+href+")");
T.saveState(tour.id, mode || tour.mode, -1);
T.saveState(tour.id, mode || tour.mode, -1, 0);
window.location.href = href;
} else {
console.log("Tour Begin from run method");
T.saveState(tour.id, mode || tour.mode, 0);
T.saveState(tour.id, mode || tour.mode, 0, 0);
T.running();
}
},
@ -311,7 +311,7 @@ var T = website.Tour = {
};
window.location.hash = "";
console.log("Tour Begin from url hash");
T.saveState(state.id, state.mode, state.step_id);
T.saveState(state.id, state.mode, state.step_id, 0);
}
if (!state.id) {
return;
@ -341,8 +341,8 @@ var T = website.Tour = {
}
return tour_ids;
},
saveState: function (tour_id, mode, step_id) {
localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id || 0, "time": this.time}));
saveState: function (tour_id, mode, step_id, number) {
localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id || 0, "time": this.time, "number": number+1}));
},
reset: function () {
var state = T.getState();
@ -402,6 +402,7 @@ var T = website.Tour = {
if (T.check(next)) {
clearTimeout(T.currentTimer);
// use an other timeout for cke dom loading
T.saveState(state.id, state.mode, state.step.id, 0);
setTimeout(function () {
T.nextStep(next);
}, T.defaultDelay);
@ -421,7 +422,13 @@ var T = website.Tour = {
}
step = step || state.step;
T.saveState(state.id, state.mode, step.id);
var next = state.tour.steps[step.id+1];
if (state.number > 3) {
T.error(next, "Cycling. Can't reach the next step");
}
T.saveState(state.id, state.mode, step.id, state.number);
if (step.id !== state.step_id) {
console.log("Tour Step: '" + (step._title || step.title) + "' (" + (new Date().getTime() - this.time) + "ms)");
@ -433,7 +440,6 @@ var T = website.Tour = {
step.onload();
}
var next = state.tour.steps[step.id+1];
if (next) {
setTimeout(function () {
T.waitNextStep();

View File

@ -34,6 +34,7 @@ import time
from dateutil.relativedelta import relativedelta
from openerp import tools
import werkzeug.urls
from openerp.addons.website.models.website import slug
try:
import GeoIP
@ -211,7 +212,8 @@ class website_event(http.Controller):
'date_end': (date_begin + timedelta(days=(1))).strftime('%Y-%m-%d'),
}
event_id = Event.create(request.cr, request.uid, vals, context=context)
return request.redirect("/event/%s?enable_editor=1" % event_id)
event = Event.browse(request.cr, request.uid, event_id, context=context)
return request.redirect("/event/%s/register?enable_editor=1" % slug(event))
def get_visitors_country(self):
GI = GeoIP.open('/usr/share/GeoIP/GeoIP.dat', 0)

View File

@ -1,3 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_event_public,event.event.public,event.model_event_event,base.group_public,1,0,0,0
access_event_event_portal,event.event.portal,event.model_event_event,base.group_portal,1,0,0,0
access_event_type_public,event.type.public,event.model_event_type,base.group_public,1,0,0,0
access_event_type_portal,event.type.portal,event.model_event_type,base.group_portal,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_event_event_public event.event.public event.model_event_event base.group_public 1 0 0 0
3 access_event_event_portal event.event.portal event.model_event_event base.group_portal 1 0 0 0
4 access_event_type_public event.type.public event.model_event_type base.group_public 1 0 0 0
5 access_event_type_portal event.type.portal event.model_event_type base.group_portal 1 0 0 0

View File

@ -27,57 +27,24 @@ from openerp.tools.translate import _
class website_event(website_event):
@http.route(['/event/add_cart'], type='http', auth="public", website=True, multilang=True)
def add_cart(self, event_id, **post):
user_obj = request.registry['res.users']
order_line_obj = request.registry.get('sale.order.line')
@http.route(['/event/cart/update'], type='http', auth="public", methods=['POST'], website=True, multilang=True)
def cart_update(self, event_id, **post):
cr, uid, context = request.cr, request.uid, request.context
ticket_obj = request.registry.get('event.event.ticket')
order_obj = request.registry.get('sale.order')
website = request.registry['website']
order = website.ecommerce_get_current_order(request.cr, request.uid, context=request.context)
if not order:
order = website.ecommerce_get_new_order(request.cr, request.uid, context=request.context)
partner_id = user_obj.browse(request.cr, SUPERUSER_ID, request.uid,
context=request.context).partner_id.id
fields = [k for k, v in order_line_obj._columns.items()]
values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields,
context=request.context)
_values = None
sale = False
for key, value in post.items():
try:
quantity = int(value)
assert quantity > 0
except:
quantity = None
ticket_id = key.split("-")[0] == 'ticket' and int(key.split("-")[1]) or None
if not ticket_id or not quantity:
quantity = int(value or "0")
if not quantity:
continue
ticket = ticket_obj.browse(request.cr, request.uid, ticket_id,
context=request.context)
sale = True
ticket_id = key.split("-")[0] == 'ticket' and int(key.split("-")[1]) or None
ticket = ticket_obj.browse(cr, SUPERUSER_ID, ticket_id, context=context)
request.website.sale_get_order(force_create=1)._cart_update(
product_id=ticket.product_id.id, add_qty=quantity, context=dict(context, event_ticket_id=ticket.id))
values['product_id'] = ticket.product_id.id
values['event_id'] = ticket.event_id.id
values['event_ticket_id'] = ticket.id
values['product_uom_qty'] = quantity
values['price_unit'] = ticket.price
values['order_id'] = order.id
values['name'] = "%s: %s" % (ticket.event_id.name, ticket.name)
# change and record value
pricelist_id = order.pricelist_id and order.pricelist_id.id or False
_values = order_line_obj.product_id_change(
request.cr, SUPERUSER_ID, [], pricelist_id, ticket.product_id.id,
partner_id=partner_id, context=request.context)['value']
_values.update(values)
order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, _values, context=request.context)
order_obj.write(request.cr, SUPERUSER_ID, [order.id], {'order_line': [(4, order_line_id)]}, context=request.context)
if not _values:
if not sale:
return request.redirect("/event/%s" % event_id)
return request.redirect("/shop/checkout")

View File

@ -1,3 +1,3 @@
import product
import sale_order
import website
import sale_order

View File

@ -1,22 +1,49 @@
# -*- coding: utf-8 -*-
from openerp.osv import osv
from openerp import SUPERUSER_ID
from openerp.addons.web.http import request
from openerp.osv import osv, fields
from openerp.tools.translate import _
# defined for access rules
class sale_order(osv.Model):
_inherit = "sale.order"
class sale_order_line(osv.osv):
_inherit = "sale.order.line"
def _cart_find_product_line(self, cr, uid, ids, product_id=None, line_id=None, context=None):
for so in self.browse(cr, uid, ids, context=context):
order_line_id = None
domain = [('order_id', '=', so.id), ('product_id', '=', product_id)]
if line_id:
domain += [('id', '=', line_id)]
elif context.get("event_ticket_id"):
domain += [('event_ticket_id', '=', context.get("event_ticket_id"))]
order_line_ids = self.pool.get('sale.order.line').search(cr, SUPERUSER_ID, domain, context=context)
if order_line_ids:
order_line_id = order_line_ids[0]
return order_line_id
def _recalculate_product_values(self, cr, uid, ids, product_id=0, fiscal_position=False, context=None):
if not ids:
return super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product_id, fiscal_position=fiscal_position, context=context)
def _website_product_id_change(self, cr, uid, ids, order_id, product_id, line_id=None, context=None):
values = super(sale_order,self)._website_product_id_change(cr, uid, ids, order_id, product_id, line_id=None, context=None)
order_line = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
assert order_line.order_id.website_session_id == request.session['website_session_id']
event_ticket_id = None
if context.get("event_ticket_id"):
event_ticket_id = context.get("event_ticket_id")
elif line_id:
line = self.pool.get('sale.order.line').browse(cr, SUPERUSER_ID, line_id, context=context)
if line.event_ticket_id:
event_ticket_id = line.event_ticket_id.id
else:
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
if product.event_ticket_ids:
event_ticket_id = product.event_ticket_ids[0]
product = product_id and self.pool.get('product.product').browse(cr, uid, product_id, context=context) or order_line.product_id
res = super(sale_order_line, self)._recalculate_product_values(cr, uid, ids, product.id, fiscal_position=fiscal_position, context=context)
if product.event_type_id and order_line.event_ticket_id and order_line.event_ticket_id.price != product.lst_price:
res.update({'price_unit': order_line.event_ticket_id.price})
if event_ticket_id:
ticket = self.pool.get('event.event.ticket').browse(cr, uid, event_ticket_id, context=context)
if product_id != ticket.product_id.id:
raise osv.except_osv(_('Error!'),_("The ticket doesn't match with this product."))
return res
values['product_id'] = ticket.product_id.id
values['event_id'] = ticket.event_id.id
values['event_ticket_id'] = ticket.id
values['price_unit'] = ticket.price
values['name'] = "%s: %s" % (ticket.event_id.name, ticket.name)
return values

View File

@ -5,6 +5,6 @@ from openerp.osv import orm
class Website(orm.Model):
_inherit = 'website'
def ecommerce_get_product_domain(self):
def sale_product_domain(self, cr, uid, ids, context=None):
# remove product event from the website content grid and list view (not removed in detail view)
return ['&'] + super(Website, self).ecommerce_get_product_domain() + [('event_ok', '=', False)]
return ['&'] + super(Website, self).sale_product_domain(cr, uid, ids, context=context) + [('event_ok', '=', False)]

View File

@ -20,7 +20,7 @@
</xpath>
</template>
<template id="mycart" inherit_id="website_sale.mycart" name="My Cart Event's Price">
<template id="cart" inherit_id="website_sale.cart" name="My Cart Event's Price">
<xpath expr="//td[@name='price']/t" position="attributes">
<attribute name="t-if">abs(line.product_id.lst_price - line.price_unit) &gt; 0.2 and not line.product_id.event_ok</attribute>
</xpath>
@ -28,7 +28,7 @@
<template id="event_description_full" inherit_id="website_event.event_description_full" inherit_option_id="website_event.event_description_full" name="Event's Ticket form">
<xpath expr="//div[@t-field='event.description']" position="before">
<form t-attf-action="/event/add_cart?event_id=#{ event.id }" method="post" t-if="event.event_ticket_ids">
<form t-attf-action="/event/cart/update?event_id=#{ event.id }" method="post" t-if="event.event_ticket_ids">
<table itemprop="offers" class="table table-striped">
<thead>
<tr>

View File

@ -124,6 +124,7 @@ class WebsiteForum(http.Controller):
values.update({
'main_object': tag or forum,
'question_ids': question_ids,
'question_count': question_count,
'pager': pager,
'tag': tag,
'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)
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)
@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):
cr, uid, context = request.cr, request.uid, request.context
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)
values = self._prepare_forum_values(forum=forum, searches={'tags': True}, **post)
values.update({
@ -427,7 +428,7 @@ class WebsiteForum(http.Controller):
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)
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)
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)
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
values = {
'content': comment.body,
}
body = comment.body
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
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)
def convert_answer_to_comment(self, forum, post, **kwarg):

View File

@ -13,10 +13,7 @@
<field name="sequence" type="int">35</field>
</record>
<record id="default_allow_auth_signup" model="ir.config_parameter">
<field name="key">auth_signup.allow_uninvited</field>
<field name="value" eval="True"/>
</record>
<function model="ir.config_parameter" name="set_param" eval="('auth_signup.allow_uninvited', True)" />
<!-- JUMP TO FORUM AT INSTALL -->
<record id="action_open_forum" model="ir.actions.act_url">

View File

@ -70,6 +70,7 @@ class Post(osv.Model):
_name = 'forum.post'
_description = 'Forum Post'
_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):
res = dict.fromkeys(ids, 0)

View File

@ -21,6 +21,9 @@
background-color: #cccccc;
margin-left: 4px;
}
.question .badge-active {
background-color: #428bca;
}
.oe_grey {
background-color: #eeeeee;

View File

@ -17,6 +17,8 @@
.badge
background-color: #ccc
margin-left: 4px
.badge-active
background-color: #428bca
.oe_grey
background-color: #eeeeee

View File

@ -94,7 +94,8 @@
</div>
<div class="panel-body">
<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 t-if="header.get('question_data')">
@ -146,8 +147,11 @@
<span t-if="not question.active"><b> [Deleted]</b></span>
<span t-if="question.state == 'close'"><b> [Closed]</b></span>
</div>
<t t-foreach="question.tag_ids" t-as="tag">
<a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="badge pull-right" t-field="tag.name"/>
<t t-foreach="question.tag_ids" t-as="question_tag">
<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>
<div class="text-muted">
by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
@ -210,14 +214,14 @@
<template id="forum_index" name="Forum">
<t t-call="website_forum.header">
<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"/>
<small class="dropdown" t-if="filters in ('all', 'unanswered','followed', 'tag')">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<t t-if="filters == 'all'">All</t>
<t t-if="filters == 'unanswered'">Unanswered</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 == 'answered'"> by most answered</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
them.
</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"/>
<div class="form-group">
<label class="col-md-3 control-label" for="reason">Question:</label>
<div class="col-md-8 mt8">
<span t-field="post.name"/>
<span t-field="question.name"/>
</div>
</div>
<div class="form-group">
@ -356,7 +360,7 @@
<div class="col-md-offset-3 col-md-8">
<button class="btn btn-primary">Close question</button>
<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>
</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>
</li>
<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 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>
@ -469,7 +473,7 @@
<div>
<span t-field="question.create_uid.image" t-field-options='{"widget": "image", "class":"pull-left img img-circle img-avatar"}'/>
<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-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
style="display: inline-block;"/>

View File

@ -26,10 +26,10 @@
}
</style>
<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" 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>
</head>
<body>

View File

@ -32,14 +32,13 @@ class WebsiteMail(http.Controller):
partner_obj = request.registry['res.partner']
user_obj = request.registry['res.users']
website = request.registry['website']
_id = int(id)
_message_is_follower = message_is_follower == 'on'
_object = request.registry[object]
# search partner_id
public_id = website.get_public_user(cr, uid, context)
public_id = request.website.user_id.id
if uid != public_id:
partner_ids = [user_obj.browse(cr, uid, uid, context).partner_id.id]
else:
@ -68,10 +67,9 @@ class WebsiteMail(http.Controller):
partner_obj = request.registry.get('res.partner')
users_obj = request.registry.get('res.users')
obj = request.registry.get(model)
website = request.registry['website']
partner_id = None
public_id = website.get_public_user(cr, uid, context)
public_id = request.website.user_id.id
if uid != public_id:
partner_id = users_obj.browse(cr, SUPERUSER_ID, uid, context).partner_id
elif request.session.get('partner_id'):

View File

@ -1,9 +0,0 @@
.. _changelog:
Changelog
=========
`trunk (saas-3)`
----------------
- created ``website_mail`` menu, holding website-related stuff about mail module

View File

@ -1,10 +0,0 @@
Website Mail Module documentation topics
''''''''''''''''''''''''''''''''''''''''
Changelog
'''''''''
.. toctree::
:maxdepth: 1
changelog.rst

View File

@ -32,7 +32,7 @@
'views/website_partner_view.xml',
'data/website_data.xml',
],
'demo': ['website_partner_demo.xml'],
'demo': ['data/demo.xml'],
'qweb': [
],
'installable': True,

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